• JS中的同步和异步


    javascript语言是一门“单线程”的语言,不像java语言,类继承Thread再来个thread.start就可以开辟一个线程,所以,javascript就像一条流水线,仅仅是一条流水线而已,要么加工,要么包装,不能同时进行多个任务和流程。

    所以同步和异步,无论如何,做事情的时候都是只有一条流水线(单线程),同步和异步的差别就在于这条流水线上各个流程的执行顺序不同

      1、最基础的异步是setTimeout和setInterval函数,很常见,但是很少人有人知道其实这就是异步,因为它们可以控制js的执行顺序。我们也可以简单地理解为:可以改变程序正

         常执行顺序的操作就可以看成是异步操作

     1 <script type="text/javascript">
     2         console.log( "1" );
     3         setTimeout(function() {
     4             console.log( "2" )
     5         }, 0 );
     6         setTimeout(function() {
     7             console.log( "3" )
     8         }, 0 );
     9         setTimeout(function() {
    10             console.log( "4" )
    11         }, 0 );
    12         console.log( "5" );
    13 </script>

                  输出顺序:

                 

        在执行程序的时候,浏览器会默认setTimeout以及ajax请求这一类的方法都是耗时程序(尽管可能不耗时),将其加入一个队列中,该队列是一个存储耗时程序的队列,

        在所有不耗时程序执行过后,再来依次执行该队列中的程序。

      2、又回到了最初的起点——javascript是单线程。单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务。如果前一个任务耗时很长,后一个任务就不

         得不一直等着。于是就有一个概念——任务队列。如果排队是因为计算量大,CPU忙不过来,倒也算了,但是很多时候CPU是闲着的,因为IO设备(输入输出设备)很

         慢(比如Ajax操作从网络读取数据),不得不等着结果出来,再往下执行。于是JavaScript语言的设计者意识到,这时主线程完全可以不管IO设备,挂起处于等待中的任

         务,先运行排在后面的任务。等到IO设备返回了结果,再回过头,把挂起的任务继续执行下去。

         于是,所有任务可以分成两种,一种是同步任务(synchronous),另一种是异步任务(asynchronous)。同步任务指的是,在主线程上排队执行的任务,只有前一个任务

         执行完毕,才能执行后一个任务;异步任务指的是,不进入主线程、而进入"任务队列"(task queue)的任务,只有等主线程任务执行完毕,"任务队列"开始通知主线程,

         请求执行任务,该任务才会进入主线程执行。

         

         具体来说,异步运行机制如下:
        (1)所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)。
        (2)主线程之外,还存在一个"任务队列"(task queue)。只要异步任务有了运行结果,就在"任务队列"之中放置一个事件。
        (3)一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队列",看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。
        (4)主线程不断重复上面的第三步。
         只要主线程空了,就会去读取"任务队列",这就是JavaScript的运行机制。这个过程会不断重复。
         "任务队列"是一个事件的队列(也可以理解成消息的队列),IO设备完成一项任务,就在"任务队列"中添加一个事件,表示相关的异步任务可以进入"执行栈"了。主线程
         读取"任务队列",就是读取里面有哪些事件。
         "任务队列"中的事件,除了IO设备的事件以外,还包括一些用户产生的事件(比如鼠标点击、页面滚动等等),比如$(selectot).click(function),这些都是相对耗时的操作。
         只要指定过这些事件的回调函数,这些事件发生时就会进入"任务队列",等待主线程读取。
         所谓"回调函数"(callback),就是那些会被主线程挂起来的代码,前面说的点击事件$(selectot).click(function)中的function就是一个回调函数。异步任务必须指定回调函
         数,当主线程开始执行异步任务,就是执行对应的回调函数。例如ajax的success,complete,error也都指定了各自的回调函数,这些函数就会加入“任务队列”中,等待
         执行。
         3、Promise对象用于异步操作,它表示一个尚未完成且预计在未来完成的异步操作。
          Promise的真正强大之处在于它的多重链式调用,可以避免层层嵌套回调

          Promise对象代表一个未完成、但预计将来会完成的操作。
          它有以下三种状态:

        • pending:初始值,不是fulfilled,也不是rejected
        • fulfilled:代表操作成功
        • rejected:代表操作失败
    /* 例3.1 */
    //构建Promise
    var promise = new Promise(function (resolve, reject) {
        if (/* 异步操作成功 */) {
            resolve(data);
        } else {
            /* 异步操作失败 */
            reject(error);
        }
    });

    类似构建对象,我们使用new来构建一个PromisePromise接受一个「函数」作为参数,该函数的两个参数分别是resolvereject。这两个函数就是就是「回调函数」,由JavaScript引擎提供。

    resolve函数的作用:在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;
    reject函数的作用:在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。

    Promise实例生成以后,可以用then方法指定resolved状态和reject状态的回调函数。

    /* 接例3.1 */
    promise.then(onFulfilled, onRejected);
    
    promise.then(function(data) {
      // do something when success
    }, function(error) {
      // do something when failure
    });

    then方法会返回一个Promise。它有两个参数,分别为Promise从pending变为fulfilledrejected时的回调函数(第二个参数非必选)。这两个函数都接受Promise对象传出的值作为参数
    简单来说,then就是定义resolvereject函数的,其resolve参数相当于:

    function resolveFun(data) {
        //data为promise传出的值
    }

    而新建Promise中的'resolve(data)',则相当于执行resolveFun函数。
    Promise新建后就会立即执行。而then方法中指定的回调函数,将在当前脚本所有同步任务执行完才会执行


  • 相关阅读:
    (深入理解计算机系统)内存对齐
    (深入理解计算机系统)AT&T汇编指令
    (深入理解计算机系统)编译,链接和装载
    (C)struct结构体指针
    (linux)BSP板级支持包开发理解
    TortoiseSVN使用笔记
    (linux)idr(integer ID management)机制
    (linux)struct inode 和 struct file
    cygwin使用笔记
    Zookeeper学习总结
  • 原文地址:https://www.cnblogs.com/WebApp-DotNet/p/10537040.html
Copyright © 2020-2023  润新知