React 服务器渲染原理解析与实践(已完结)2018(最全)

之前我的认知是,这是一个generator的语法糖,是用来解决异步问题的,看起来写起来是同步代码,但实际运行还是异步的,感觉和他说的有点偏差,有偏差就说明至少有个人错了;于是我打算重新认识一遍这个东西,说不定会有新收获。

TALK IS CHEAP, SHOW YOU THE CODE.

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');
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
按照我之前的理解,我会把答案写成:

script start
async1 start
async2
async1 end
promise1
script end
promise2
setTimeout
因为我想await async2这里就是会等待他返回然后再往下执行

然而其实答案是:

script start
async1 start
async2
promise1
script end
promise2
async1 end
setTimeout
这里就涉及到await的特点了:

await 表达式会暂停当前 async function 的执行,等待 Promise 处理完成。若 Promise 正常处理(fulfilled),其回调的resolve函数参数作为 await 表达式的值,继续执行 async function。
若 Promise 处理异常(rejected),await 表达式会把 Promise 的异常原因抛出。
另外,如果 await 操作符后的表达式的值不是一个 Promise,则返回该值本身。

这里的暂停执行,我们应该理解为交出线程控制权,去执行后面的函数。我们反向来看,假如async函数里面一直等待await后面的表达式返回,那整个线程就等于卡在这个async函数里了,那不就变成同步阻塞的了。

所以我们回到上面的那段代码,开始分析
首先代码同步执行输出 script start ,接着 setTimeout 中的回调属于 MacroTask 队列,会被推入该队列等待执行。
接着代码执行到 async1 函数里面,输出 async1 start,接着遇到了await关键字,这一行语句会从右到左执行,先执行 async2 函数,输出async2,因为这个函数没有返回值,所以返回了一个 Promise.resolve(undefined).然后这个 Promise 会被推入 MicroTask 队列,同时 await 让出线程,跳出 async1 函数,继续执行下面的同步代码。
Promise构造器中的函数参数会被立即执行,所以输出 promise1 ,然后执行了resolve(),这个 Promise 也被推入 MicroTask 队列等待执行,接着输出script end,好了,同步代码执行完了,调用栈现在空了。
然后开始处理异步的任务队列。第一个是 async2 中返回的Promise.resolve(undefined)被resolve之后再次加入队列,所以回调没被执行,第二个是 new Promise里resolve的 Promise ,其回调被执行,输出 promise2 。好的现在调用栈又空了,然后开始再一次处理异步队列,这次取到的是之前被第二次放进来的Promise的回调,执行之后, 表达式await async2()的求值就完成了,值是undefined。接着可以认为async2返回的Promise已经处理完了,接着执行下面的代码,输出async1 end。
最后就是MacroTask队列中的回调被执行,输出setTimeout

这里需要解释一下一个地方,async2 返回的Promise状态是Resolved,为什么会被放到任务队列里面两次。首先async2函数是一个async function,他的返回值是一个resolved状态的Promise,await async2()类似于await Promise.resolve(something),Chrome的V8引擎对这个过程进行了优化,把Promise.resolve()的返回值优化成了返回一个新的Promise,这样他的回调就不会被立即执行,而是需要再等一个循环才执行。而在Node里面,Promise.resolve返回的就是当前的Promise,回调会被立即执行,所以如果你在node里面执行的话,顺序会是这样的:

script start
async1 start
async2
promise1
script end
async1 end
promise2
setTimeout
是因为Node环境下,async2返回的Promise在第一次被推入队列时就是resolved的,跟new Promise那个是一样的,所以按照入队列的顺序,先输出async1 end。这一点差异,应该以最新V8引擎为准。
--------------------- 
作者:divasatanica 
来源:CSDN 
原文:https://blog.csdn.net/divasatanica/article/details/85109924 
版权声明:本文为博主原创文章,转载请附上博文链接!

猜你喜欢

转载自blog.csdn.net/weixin_44225130/article/details/85534961