In this lesson, you will learn how to create a "driver" function that allows you to pause and resume generator functions using Promise results, effectively creating your own custom async/await flow.
The Generator-Promise Bridge
A standard generator function pauses at yield statements. By itself, it doesn't know how to handle Promises. However, because a generator returns an iterator, we can manually call .next() to resume it. If we yield a Promise, we can wait for that Promise to resolve, then pass the result back into the generator using .next(value).
Think of it as a relay race: the generator passes a "baton" (the Promise) to a driver function, the driver waits for the Promise to finish, and then hands the result back to the generator.
Building a Custom Controller
Here is how you can write a simple spawn function to automate this process:
function spawn(generatorFunc) {
const iterator = generatorFunc();
function handle(result) {
if (result.done) return Promise.resolve(result.value);
// Ensure the yielded value is a promise, then resume
return Promise.resolve(result.value).then(
(res) => handle(iterator.next(res)),
(err) => handle(iterator.throw(err))
);
}
return handle(iterator.next());
}
// Usage:
spawn(function* () {
const user = yield Promise.resolve({ id: 1, name: 'Alice' });
const post = yield Promise.resolve(`Post for ${user.name}`);
return post;
}).then(console.log);
In this code, spawn acts as the engine. When the generator reaches a yield, it pauses and hands a Promise to handle. Once the Promise resolves, iterator.next(res) injects the resolved value back into the generator. If the Promise rejects, we use iterator.throw(err) to inject an error back into the generator, allowing the generator to use try/catch blocks just like you do with async/await.
By implementing this pattern, you gain complete control over how asynchronous operations are executed without relying on built-in syntax. This is the underlying mechanics of how modern asynchronous control flow is powered under the hood.
Key Takeaway: By creating a recursive driver function, you can manually orchestrate generator execution, using yield to wait for Promises and .next(value) to resume with the results.