求大佬解释下下面这段代码的执行顺序

新手上路,请多包涵

代码如下:

const p = Promise.resolve();
(() => {
    const implicit_promise = new Promise(resolve => {
        const promise = new Promise(res => res(p));
        promise.then(() => {
            console.log('after:await');
            resolve();
        });
    });
    return implicit_promise;

})();

p.then(() => {
    console.log('tick:a');
}).then(() => {
    console.log('tick:b');
}).then(() => {
    console.log('tick:c');
})

  这段代码在node 11和浏览器中的输出顺序为:

    tick:a
    tick:b
    after:await
    tick:c

不应该先输出after:await么?

阅读 2.6k
3 个回答
const p = Promise.resolve();
(() => {
    const implicit_promise = new Promise(resolve => {
        // SYNC1
        const sync1_promise = new Promise(res => res(p)/* ASYNC2 */);
        sync1_promise .then(() => {
            /* ASYNC3 */
            console.log('after:await');
            resolve();
        });
    });
    return implicit_promise;

})();

p.then(() => {
    // TICK A
    console.log('tick:a');
}).then(() => {
    // TICK B
    console.log('tick:b');
}).then(() => {
    // TICK C
    console.log('tick:c');
})

几点注意:

  1. Promise 的 then 函数回调不会同步执行,如果 Promise 已经被 resolve 或 reject ,那么其回调会被放进异步队列。当 Promise 并没有被 resolve 或 reject 的时候,then 的回调不会被放入任务队列,而是在 Promise 在被 resolve 或 reject 的时候才放入异步队列。
  2. Promise 的 then(onFullfilled, onReject) 会返回一个新的 Promise,这个新的 Promise 会在 onFullfilled 或 onReject 别执行之后,被 resolve 或 reject 。
  3. 当使用 Promise 来 rosolve 另一个 Promise 的时候 (res=>res(p)),会建立一个异步任务,并在异步任务里调用 p.then(res)

所以:
同步任务,p 是一个已经 resolve 的 Promise 。匿名函数直接调用,SYNC1 执行,ASYNC2 执行。ASYNC2 执行并没有 resolve sync1_promise (见以上第三点),而是增加了一个异步任务(异步1),在异步任务里将执行 p.then(res)。 于是,SYNC1 中的 sync1_promise 并没有被 resolve ,ASYNC3 也并不会被放入异步队列。
接下来,由于 p 已经 resolve,TICKA 被放入异步队列(异步2)。但是,其返回 Promise 由于 TICKA 并没有被调用(还在异步队列里),并没有被 resolve ,于是 TICKB 与 TICKC 均不会被放入异步队列。

异步1:执行 p.then(res),p 已经 resolve ,所以 res 被放入异步队列(异步3)
异步2:执行 TICKA,输出 "tick:a"。同时,rosolve p.then(TICKA) 返回的 Promise ,TICKB 被放入队列(异步4)
异步3:执行 res() ,resolve 掉 SYNC1 中的 sync1_promise ,于是在它的 then 里注册的 ASYNC3 被放入队列(异步5)
异步4:执行 TICKB,输出 "tick:b"。同时,rosolve p.then(TICKA).then(TICKB) 返回的 Promise ,TICKC 被放入队列(异步6)
异步5:执行 ASYNC3,输出 "after:await" 。resolve implicit_promise
异步6:执行 TICKC,输出 "tick:c"

js是单线程,而promise是异步的,总是后执行,异步里套异步,也是先把同层级的异步任务跑完再去跑下一层级异步任务。造成这个的原因可以看下eventLoop;

这是别人的例子,可以看看想想。

setTimeout(function(){
    console.log(1);
    setTimeout(function(){
        console.log(2);
    }, 0);
}, 0);

setTimeout(function(){
    console.log(3);
    setTimeout(function(){
        console.log(4);
    }, 0);
}, 0);
结果打印1 3 2 4,而不是1 2 3 4。

链接描述
JavaScript 运行机制详解:再谈Event Loop

微任务排队,一个then就重新排。两个promise链排队问题。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题