You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

咨询JavaScript中与yield配套的spawn函数工作原理

Hey there! Let's break down that spawn function step by step—since it's a core utility for running generator functions with promises, it makes sense to unpack each piece clearly. First, let's fill in the missing part of your code (it cuts off mid-line, but this is the standard implementation):

Understanding the spawn Generator Runner Function

Here's the complete, typical version of the function you're looking at:

function spawn(generatorFunc) {
  function continuer(verb, arg) {
    var result;
    try {
      result = generator[verb](arg);
    } catch (err) {
      return Promise.reject(err);
    }
    if (result.done) {
      return result.value;
    } else {
      return Promise.resolve(result.value).then(onFulfilled, onRejected);
    }
  }
  var generator = generatorFunc();
  var onFulfilled = continuer.bind(continuer, "next");
  var onRejected = continuer.bind(continuer, "throw");
  return onFulfilled();
}

Now let's break this down piece by piece:

What's this function actually doing?

This is a generator runner—it lets you write asynchronous code in a synchronous-looking style using ES6 generators, by automatically handling the promise flow every time the generator yields a value. Think of it as a manual implementation of what async/await does under the hood!

Core Components Explained

1. Creating the generator instance

var generator = generatorFunc();

First, we call the passed generator function to get a generator object. This object has two critical methods: next() (resumes execution) and throw() (injects an error into the generator).

2. The continuer helper (the real workhorse)

This function handles repeating the cycle of running the generator, resolving its yielded promises, and resuming execution. Let's walk through its logic:

  • It takes verb (which generator method to call: "next" or "throw") and arg (the value to pass to that method)
  • Try executing the generator: It runs generator[verb](arg)—either resuming the generator with a resolved promise value, or injecting an error from a rejected promise.
  • Catch generator errors: If the generator itself throws an uncaught error, we return a rejected promise to propagate that error outward.
  • Check if execution is done: If result.done is true, the generator has finished running—we return its final value (which gets wrapped into a promise automatically if it isn't one).
  • Continue the promise chain: If the generator isn't done, we resolve the yielded value (expected to be a promise), then hook up the handlers to keep the generator running.

3. Pre-bound handlers for promise resolution/rejection

var onFulfilled = continuer.bind(continuer, "next");
var onRejected = continuer.bind(continuer, "throw");

These are shortcut versions of continuer that lock in the first argument:

  • onFulfilled: When a yielded promise resolves, this calls continuer("next", resolvedValue)—resuming the generator with the resolved data.
  • onRejected: When a yielded promise rejects, this calls continuer("throw", rejectedError)—throwing the error into the generator, which you can catch with a try/catch block inside the generator itself.

4. Kick off the runner

return onFulfilled();

We start the whole process by calling onFulfilled() with no arguments—this runs generator.next() for the first time, launching the generator's execution.

Example Usage to Make It Real

Suppose you have a generator function like this:

function* myAsyncWorkflow() {
  try {
    const user = yield fetchUser(); // fetchUser returns a promise
    const posts = yield fetchPosts(user.id); // another promise
    return `Fetched ${posts.length} posts for user ${user.name}`;
  } catch (err) {
    console.error("Workflow failed:", err);
    throw err;
  }
}

Calling spawn(myAsyncWorkflow) will:

  1. Start the generator, run until it hits yield fetchUser()
  2. Wait for the fetchUser() promise to resolve, then pass the user data to generator.next(user)
  3. Run until it hits yield fetchPosts(user.id)
  4. Wait for that promise to resolve, pass the posts to generator.next(posts)
  5. The generator returns its final string, so spawn returns a promise that resolves to that string
  6. If any promise rejects, onRejected triggers generator.throw(err), which lands in the catch block inside the generator.

Key Takeaways

  • This function bridges generators and promises, enabling "synchronous" async code before async/await existed (async/await is just syntactic sugar over this pattern!)
  • The continuer function creates a loop of yielding promises, resolving them, and resuming the generator
  • Errors are propagated either by rejecting the final promise or by throwing into the generator for internal handling

内容的提问来源于stack exchange,提问作者Ouroboros

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 03:48:38