咨询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):
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") andarg(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.doneistrue, 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 callscontinuer("next", resolvedValue)—resuming the generator with the resolved data.onRejected: When a yielded promise rejects, this callscontinuer("throw", rejectedError)—throwing the error into the generator, which you can catch with atry/catchblock 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:
- Start the generator, run until it hits
yield fetchUser() - Wait for the
fetchUser()promise to resolve, then pass the user data togenerator.next(user) - Run until it hits
yield fetchPosts(user.id) - Wait for that promise to resolve, pass the posts to
generator.next(posts) - The generator returns its final string, so
spawnreturns a promise that resolves to that string - If any promise rejects,
onRejectedtriggersgenerator.throw(err), which lands in thecatchblock inside the generator.
Key Takeaways
- This function bridges generators and promises, enabling "synchronous" async code before
async/awaitexisted (async/await is just syntactic sugar over this pattern!) - The
continuerfunction 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

