一道setTimeout async promise执行顺序的笔试题引发的思考

====据说这是今日头条去年的一道笔试题,主要考察的是setTimeout async promise执行顺序

~先双手奉上这道题目~

async function async1() {
            console.log("async1 start");
            await  async2();
            console.log("async1 end");
 
        }
        async  function async2() {
           console.log( 'async2');
        }
        console.log("script start");
        setTimeout(function () {
            console.log("settimeout");
        },0);
        async1();
        new Promise(function (resolve) {
            console.log("promise1");
            resolve();
        }).then(function () {
            console.log("promise2");
        });
        console.log('script end');
  • 首先,我们先来了解几个概念:

    JS众所周知是单线程语言,Javascript引擎同一时刻只能执行一个代码块,使用Event Loop作为它的异步执行机制

  • 那么Event Loop是如何实现异步呢,个人浅显的理解如下:

    1. 同步代码按照上下文的顺序放进主进程中去执行
    2. 异步函数放进异步队列中,等待执行,在异步队列执行的顺序按照先进先出的原则
    3. 等主进程中的同步函数执行完毕后,轮询去执行异步队列中的异步函数

      ⚠️注意: setTimeOut并不是直接的把你的回掉函数放进上述的异步队列中去,而是在定时器的时间到了之后,把回掉函数放到执行异步队列中去。如果此时这个队列已经有很多任务了,那就排在他们的后面。这也就解释了为什么setTimeOut为什么不能精准的执行的问题了。setTimeOut执行需要满足两个条件:

      1. 主进程必须是空闲的状态,如果到时间了,主进程不空闲也不会执行你的回掉函数 
      2. 这个回掉函数需要等到插入异步队列时前面的异步函数都执行完了,才会执行
  • 理解了Eventloop异步实现的方式,再来补充一下promise、async/await

    1. 首先,new Promise是同步的任务,会被放到主进程中去立即执行。而.then()函数是异步任务会放到异步队列中去,那什么时候放到异步队列中去呢?当你的promise状态结束的时候,就会立即放进异步队列中去了。如果你要问他和setTimeOut谁当进去的快,要从下面两个方面考虑:

      1. promise结束时。.then内函数插入异步队列的时间与setTimeOut的回掉函数插入队列的时间,谁的早,谁的就最快2. **如果promise是同步的而setTimeOut时间是0,那么是promise先执行**。至于什么,查了很多的资料,了解到:一个浏览器环境只能有一个事件循环,而一个事件循环可以有多个任务队列。settimeout所在的队列与promise.then()的队列不同,面对此种情况,v8实现的时候会先从promise.then()的队列取任务,但是并没有很理解,如果有大佬愿意指点迷津,请留言告知

相关推荐