面试官: 说说你对async的理解 (3)

上面的_asyncToGenerator执行后,会执行mark返回的函数:

function _callee() { return regeneratorRuntime.wrap(function _callee$( _context ) { // 这里就是动态得了,也就是根据用户写的async函数,转换的记过,由于我们是一个空函数,所以直接stop了 while (1) { switch ((_context.prev = _context.next)) { case 0: case 'end': return _context.stop(); } } }, _callee); }

_callee会返回wrap处理后的结果,我们继续看:

// innerFn是真正执行的函数,outerFn为被mark的函数 // self, tryLocsList未传递,为undefined function wrap(innerFn, outerFn, self, tryLocsList) { // If outerFn provided and outerFn.prototype is a Generator, then outerFn.prototype instanceof Generator. // outerFn 的原型已经被 mark重新设置,所以会包含generator相关原型 var protoGenerator = outerFn && outerFn.prototype instanceof Generator ? outerFn : Generator; // 创建自定义原型的对象 var generator = Object.create(protoGenerator.prototype); // context 实例是包含的 this.tryEntries 的 var context = new Context(tryLocsList || []); // The ._invoke method unifies the implementations of the .next, // .throw, and .return methods. generator._invoke = makeInvokeMethod(innerFn, self, context); return generator; }

其中有个new Context()的操作,用来重置并记录迭代器的状态,后面会用到。
之后给返回generator挂载一个_invoke方法,调用makeInvokeMethod,并传入self(未传递该参数,为undefined)和context。

function makeInvokeMethod(innerFn, self, context) { // state只有在该函数中备操作 var state = GenStateSuspendedStart; // GenStateSuspendedStart: 'suspendedStart' // 作为外面的返回值 return function invoke(method, arg) { // 这里就是generator相关的一些操作了,用到的时候再说 }; }

利用闭包初始化state,并返回一个invoke函数,接受两个参数,方法和值。先看到这,继续往后看。

回到之前的_asyncToGenerator:

// 返回带有_invoke属性的generator对象 var gen = fn.apply(self, args);

之后定义了一个next和throw方法,随后直接调用_next开始执行:

function _next(value) { asyncGeneratorStep( gen, // 迭代器函数 resolve, // promise的resolve reject, // promise的project _next, // 当前函数 _throw, // 下面的_throw函数 'next', // method名 value // arg 参数值 ); } function _throw(err) { asyncGeneratorStep( gen, resolve, reject, _next, _throw, 'throw', err ); } _next(undefined);

其中都是用的asyncGeneratorStep,并传递了一些参数。

那asyncGeneratorStep又是啥呢:

function asyncGeneratorStep( gen, resolve, reject, _next, _throw, key, arg ) { try { var info = gen[key](arg); var value = info.value; } catch (error) { // 出错 reject(error); return; } if (info.done) { // 如果完成,直接resolve resolve(value); } else { // 否则,继续下次next调用,形成递归 Promise.resolve(value).then(_next, _throw); } }

代码很少,获取即将要调用的方法名(key)并传入参数,所以当前info即是:

var info = gen['next'](arg);

那next是哪来的那?就是之前mark操作中定义的,如果原生支持,就是用原生的迭代器提供的next,否则使用polyfill中定义的next。

还记得之前的makeInvokeMethod吗?

它其实是用来定义标准化next、throw和return的:

function defineIteratorMethods(prototype) { ['next', 'throw', 'return'].forEach(function (method) { prototype[method] = function (arg) { return this._invoke(method, arg); }; }); } // Gp在之前的原型操作有用到 defineIteratorMethods(Gp);

然后当我们执行的时候,就会走到_invoke定义的invoke方法中:

function invoke(method, arg) { // 状态判断,抛错 if (state === GenStateExecuting) { throw new Error('Generator is already running'); } // 已完成,返回done状态 if (state === GenStateCompleted) { if (method === 'throw') { throw arg; } // Be forgiving, per 25.3.3.3.3 of the spec: // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-generatorresume return doneResult(); } // 这里就是之前定义的Context实例,下面代码没啥了,自己看吧 context.method = method; context.arg = arg; while (true) { var delegate = context.delegate; if (delegate) { var delegateResult = maybeInvokeDelegate(delegate, context); if (delegateResult) { if (delegateResult === ContinueSentinel) continue; return delegateResult; } } if (context.method === 'next') { // Setting context._sent for legacy support of Babel's // function.sent implementation. context.sent = context._sent = context.arg; } else if (context.method === 'throw') { if (state === GenStateSuspendedStart) { state = GenStateCompleted; throw context.arg; } context.dispatchException(context.arg); } else if (context.method === 'return') { context.abrupt('return', context.arg); } state = GenStateExecuting; // innerFn就是while个循环了,使我们的代码主体 var record = tryCatch(innerFn, self, context); if (record.type === 'normal') { // If an exception is thrown from innerFn, we leave state === // GenStateExecuting and loop back for another invocation. state = context.done ? GenStateCompleted : GenStateSuspendedYield; if (record.arg === ContinueSentinel) { continue; } return { value: record.arg, done: context.done }; } else if (record.type === 'throw') { state = GenStateCompleted; // Dispatch the exception by looping back around to the // context.dispatchException(context.arg) call above. context.method = 'throw'; context.arg = record.arg; } } };

在之后,就是我们熟悉的promise相关操作了,在判断done是否为true,否则继续执行,将_next和_throw作为resolve和reject传入即可。

小结

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpjjjw.html