Nodejs中更快的async(2)

2019年11月16日 352点热度 0人点赞 0条评论

在上一篇文章中,有说过v8的async优化节约了一个额外的Promise和两个Microtask,那么本篇文章来更详细的讲述一下优化了哪两个Microtask。

还是这个例子:

async function foo() {  const w = await v;  return w;}

图片

在上篇文章中有上面这样的一个图,讲述了V8是如何处理这个await的,那么转换为js代码是怎样的呢?

function foo(v) {  const implicit_promise = new Promise((resolve, reject) =>{    const promise = Promise.resolve().then(return v);    const throwaway = new Promise((resolve, reject) => {      promise.then(resolve, reject);    }).then(result => {      resumeFoo(result);    }).catch(err => {      throwFoo(err);    });
const resumeFoo = function (result) { const returnValue = (v => { // 原来的foo执行逻辑 const w = v; return w;
})(result); resolve(returnValue); };
const throwFoo = err => { reject(err); } }); return implicit_promise;}

在js执行时,会把每个promise的then塞入Microtasks,而Microtasks会在每次事件循环后进行处理,于是参照上面的js代码可以看到:

第一个Microtask:

const promise = Promise.resolve().then(return v);

这个Microtask中无论v是不是一个Promise,通过Promise.resolve().then这样的处理之后都会变为一个Promise,但是这对于v本来就是一个Promise的话显得很多余,于是在v8中判断了下如果是Promise就不再包裹,减少了一次Microtasks。

第二个Microtask:

promise.then(resolve, reject);

第三个Microtask:

const throwaway = new Promise((resolve, reject) => {  promise.then(resolve, reject);}).then(result => {   resumeFoo(result); }).catch(err => {   throwFoo(err);});

能够看到throwaway这部分代码完全是可以优化成下面这样的:

promise.then(resumeFoo, throwFoo);

又减少了一个Microtasks,于是最终的代码变成了这样:

function foo() {  const implicit_promise = new Promise((resolve, reject) =>{    v.then(resumeFoo, throwFoo);    const resumeFoo = function (result{      const returnValue = (v => {        // 原来的foo执行逻辑        const w = v;        return w;
      })(result); resolve(returnValue); };
    const throwFoo = err => {      reject(err); } });  return implicit_promise;}

那么再来看之前的这段代码的输出:

const p = Promise.resolve();(async () => {  await p; console.log('after:await');})();p.then(() => console.log('tick:a')) .then(() => console.log('tick:b'));

变换成node12的执行逻辑:

const p = Promise.resolve();(async () => {   const implicit_promise = new Promise((resolve, reject) =>{     v.then(resumeFoo, throwFoo);    const resumeFoo = function (result) {       const returnValue = (v => {
console.log('after:await');
})(result); resolve(returnValue); };
const throwFoo = err => { reject(err); } }); return implicit_promise; })();p.then(() => console.log('tick:a')) .then(() => console.log('tick:b'));

所以按照从上到下执行的逻辑就是:

1.先触发第一个then,把 resumeFoo 塞入microtask2.触发第二个then,把 console.log('tick:a') 塞入microtask

开始执行Microtasks,输出 after:await,再输出 tick:a
然后再触发第三个then将 console.log('tick:b') 塞入Microtasks,再去清理Microtasks,执行输出 tick:b

29830Nodejs中更快的async(2)

这个人很懒,什么都没留下

文章评论