async以下是群友回答。问题是 async 函数的实现原理,在单论 async 时,我觉得与 generator 并没有关系。
我们来看一下 MDN 上的描述:
async function 用来定义一个返回 AsyncFunction 对象的异步函数。异步函数是指通过事件循环异步执行的函数,它会通过一个隐式的 Promise 返回其结果。
在看一下 MDN 上的转换结果:
For example, the following:
async function foo() { return 1}复制代码is equivalent to:
function foo() { return Promise.resolve(1)}复制代码 所以单论 async 的实现,它更应该类似于下面的代码:
function _async(fn) { return (...args) => Promise.resolve(fn(...args));}复制代码generator再来看看 generator 是什么。先实现 generator 是为了在接下来的 await 中使用。以下是廖雪峰教程中的示例代码:
function* fib(max) { var t, a = 0, b = 1, n = 0; while (n < max) { yield a; [a, b] = [b, a + b]; n ++; } return;}var f = fib(5);f.next(); // {value: 0, done: false}f.next(); // {value: 1, done: false}f.next(); // {value: 1, done: false}f.next(); // {value: 2, done: false}f.next(); // {value: 3, done: false}f.next(); // {value: undefined, done: true}复制代码可以理解为调用 generator 返回的“对象”上的 next 方法,可以产生类似于 { value, done } 形式的结果。
再来看一下掘友写代码像蔡徐抻的9k字 | Promise/async/Generator实现原理解析这篇文章里写的 generator 转换结果:
// 代码function* foo() { yield 'result1' yield 'result2' yield 'result3'} const gen = foo()console.log(gen.next().value)console.log(gen.next().value)console.log(gen.next().value)// babel官网转换结果"use strict";var _marked =/*#__PURE__*/regeneratorRuntime.mark(foo);function foo() { return regeneratorRuntime.wrap(function foo$(_context) { while (1) { switch (_context.prev = _context.next) { case 0: _context.next = 2; return 'result1'; case 2: _context.next = 4; return 'result2'; case 4: _context.next = 6; return 'result3'; case 6: case "end": return _context.stop(); } } }, _marked);}var gen = foo();console.log(gen.next().value);console.log(gen.next().value);console.log(gen.next().value);复制代码在群里探讨的过程中,为了区别 async 和 await,写了如下的一段“generator”:
function get() { let g = { done: false, count: 0, next() { if (this.count === 3) this.done = true; if (this.done) return { value: this.count, done: this.done }; this.count++; return { value: this.count, done: this.done }; } } return g;}let obj = get();console.log(obj.next())console.log(obj.next())console.log(obj.next())console.log(obj.next())console.log(obj.next())// 输出结果// { value: 1, done: false }// { value: 2, done: false }// { value: 3, done: false }// { value: 3, done: true }// { value: 3, done: true }复制代码以上代码与 babel 以及 ES 中的实现肯定差别很大,但是基本上就是一个 generator 的执行逻辑。具体可以参考 babel 转码后的结果中的 switch (_context.prev = _context.next) 以及几行 _context.next = 2; 代码。
await先回顾一下 await的作用,它能够将异步代码转变成同步代码的逻辑,在异步代码返回值到达前,程序将会被挂起。所以我们要挑一个能让程序挂起的代码,也就是 while(true)。实现如下:
function _await() { let result = data.next(); while (true) { console.log('waiting...', result); if (result.done) return result.value; result = data.next(); }}let g = get();console.log('before');let a = _await(g);console.log(a);console.log('after');// 输出// before// awaiting... { value: 1, done: false }// awaiting... { value: 2, done: false }// awaiting... { value: 3, done: false }// awaiting... { value: 3, done: true }// 3// after复制代码更进一步在实际使用过程中,await 只能在 async 中使用,群友问这个要怎么实现,于是折腾出下面这一版。
function myAwait() { this.c = function(data) { if (!this.isCalledByAsync) throw new Error('Should be called by async'); let result = data.next(); while (true) { console.log('awaiting...', result); if (result.done) return result.value; result = data.next(); } }}function myAsync(fn) { myAwait.prototype.isCalledByAsync = true; let m = get(); console.log('async before'); let d = new myAwait().c(m); console.log(d); console.log('async after'); myAwait.prototype.isCalledByAsync = false;}myAsync();let g = get();console.log('no async before');let a = new myAwait().c(g);console.log(a);console.log('no async after');// 输出// async before// awaiting... { value: 1, done: false }// awaiting... { value: 2, done: false }// awaiting... { value: 3, done: false }// awaiting... { value: 3, done: true }// 3// async after// no async before// Error: Should be called by async复制代码没想到其他什么办法来做这个标记,只能使用控制原型的方式来控制是否能够执行,但也算只能在 async 内部才能使用了。
作者:Wetoria
链接:https://juejin.im/post/5ec4f16bf265da76b74072e4
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
|
|