async/await polyfill 变化

1,416 阅读3分钟

ES8 的async/await语法

async function fn() {
  return await new Promise(res => void setTimeout(res, 1000, true))
}

fn().then(console.log)

用 tsc 转化为 ES6 代码变成了:

var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
function fn() {
    return __awaiter(thisvoid 0void 0function* () {
        return yield new Promise(res => void setTimeout(res, 1000true));
    });
}
fn().then(console.log);

翻译成可阅读的版本:

function __awaiter(thisArg, _arguments, generator) {
  function adopt(value) {
    return value instanceof Promise
      ? value
      : new Promise(function (resolve) {
          resolve(value);
        });
  }
  return new Promise(function (resolve, reject) {
    function fulfilled(value) {
      try {
        step(generator.next(value));
      } catch (e) {
        reject(e);
      }
    }
    function rejected(value) {
      try {
        step(generator["throw"](value));
      } catch (e) {
        reject(e);
      }
    }
    function step(result) {
      result.done
        ? resolve(result.value)
        : adopt(result.value).then(fulfilled, rejected);
    }
    step((generator = generator.apply(thisArg, _arguments || [])).next());
  });
}

function fn() {
  return __awaiter(this, void 0, function* () {
    return yield new Promise((res) => void setTimeout(res, 1000, true));
  });
}
fn().then(console.log);

也就是把async函数变成了生成器函数,await变成了yield


Faster async functions and promises 讲了 V8 中实现更快的异步函数的方法,其区别:

原:await后的表达式被一律包裹为Promise实例对象,即使已经是Promise

现:若await后的表达式不是Promise才会被包裹为Promise实例对象。


尝试一下古早的 tsc,上述代码编译后变成了:

var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
function fn() {
    return __awaiter(thisvoid 0void 0function* () {
        return yield new Promise(res => void setTimeout(res, 1000true));
    });
}
fn().then(console.log);

翻译成可阅读的版本:

function __awaiter(thisArg, _arguments, generator) {
    return new Promise(function (resolve, reject) {
      function fulfilled(value) {
        try {
          step(generator.next(value));
        } catch (e) {
          reject(e);
        }
      }
      function rejected(value) {
        try {
          step(generator["throw"](value));
        } catch (e) {
          reject(e);
        }
      }
      function step(result) {
        result.done
          ? resolve(result.value)
          : new Promise(function (resolve) {
              resolve(result.value);
            }).then(fulfilled, rejected);
      }
      step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
  };

function fn() {
  return __awaiter(this, void 0,  function* () {
    return yield new Promise((res) => void setTimeout(res, 1000, true));
  });
}
fn().then(console.log);

这也就导致了

const p = Promise.resolve();

(async () => {
  await p;
  console.log('after:await');
})();

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

上述代码的输出:

原:"tick:a", "tick:b", "after:await", "tick:c"

现:"after:await", "tick:a", "tick:b", "tick:c"


每次当一个任务退出且执行上下文为空的时候,微任务队列中的每一个微任务会依次被执行。不同的是它会等到微任务队列为空才会停止执行——即使中途有微任务加入。换句话说,微任务可以添加新的微任务到队列中,并在下一个任务开始执行之前且当前事件循环结束之前执行完所有的微任务。

原来的微任务队列

  1. [promiseResolveThenableJob, () => console.log('tick:a')]
  2. [() => console.log('tick:b'), resolvePromiseA]
  3. [() => { console.log('after:await'); }, () => console.log('tick:c')

其实,新的 Polyfill 中,adopt函数就是Promise对象的静态方法resolve,他是个幂等函数,也就是无论套多少层都一样。不妨把新版__awaiter改成:

function __awaiter(thisArg, _arguments, generator) {
  return new Promise(function (resolve, reject) {
    function fulfilled(value) {
      try {
        step(generator.next(value));
      } catch (e) {
        reject(e);
      }
    }
    function rejected(value) {
      try {
        step(generator["throw"](value));
      } catch (e) {
        reject(e);
      }
    }
    function step(result) {
      result.done
        ? resolve(result.value)
        : Promise.resolve(result.value).then(fulfilled, rejected);
    }
    step((generator = generator.apply(thisArg, _arguments || [])).next());
  });
}