这里每次的 next 执行实际上执行的都是 Generator 的 _invoke 方法, _invoke(method, arg)_invoke('next', arg)
1 2 3 4 5 6 7 8 9 10 11 12 13
functionwrap(innerFn, outerFn, self, tryLocsList) { // If outerFn provided and outerFn.prototype is a Generator, then outerFn.prototype instanceof Generator. var protoGenerator = outerFn && outerFn.prototypeinstanceofGenerator ? outerFn : Generator; var generator = Object.create(protoGenerator.prototype); var context = newContext(tryLocsList || []);
// The ._invoke method unifies the implementations of the .next, // .throw, and .return methods. generator._invoke = makeInvokeMethod(innerFn, self, context);
/** * 这是定义的一些状态 * var GenStateSuspendedStart = "suspendedStart"; * var GenStateSuspendedYield = "suspendedYield"; * var GenStateExecuting = "executing"; * var GenStateCompleted = "completed"; */ // 这里定义自身状态 var state = GenStateSuspendedStart; // 闭包, 返回 invoke 函数 returnfunctioninvoke(method, arg) { if (state === GenStateExecuting) { thrownewError("Generator is already running"); }
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 returndoneResult(); }
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;
} elseif (context.method === "throw") { if (state === GenStateSuspendedStart) { state = GenStateCompleted; throw context.arg; }
state = GenStateExecuting; // 尝试捕捉错误 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 };
} elseif (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; } } }; }
可以看到, next 调用之后每次都会调用 babel 写的 switch , 拿到返回值, 返回. 通过维护一个 state 和一个 context, 形成一个状态机.