Skip to content

Instantly share code, notes, and snippets.

@jaawerth
Last active February 15, 2023 05:45
Show Gist options
  • Save jaawerth/91ec6f6e65583a1ddacf to your computer and use it in GitHub Desktop.
Save jaawerth/91ec6f6e65583a1ddacf to your computer and use it in GitHub Desktop.
Example implementation of using generators the "spawn" function for JavaScript coroutines in ES6, for async/await functionality

JavaScript coroutines and "spawn"

In ES2017, we have async/await for unwrapping promises. However, this is just syntastic sugar for the use of coroutines, which are already available in ES6 (see the recommended modules tj/co and Bluebird's Promise.coroutine()).

Below is a sample implementation of spawn showing how it works. It takes a generator function, inside of which yield can be used to unwrap promises for synchronous-style code. spawn always returns a promise.

Try it yourself!

You can install this gist via npm to tinker with it yourself, or copy/paste the function into any environment that supports generators.

IMPORTANT: Use this code only for tinkering and education purposes, not for use in a real project. While you're free to do so, it's a MUCH beter practice to use an existing, published module for such functionality, such as the two linked above, or better yet use async/await via babel.

To install:

  • npm install gist:91ec6f6e65583a1ddacf

Sample usage (also using let, const, and for..of):

const spawn = require('./spawn');
const result = spawn(function*() {
  let actions = [Promise.resolve('one'), Promise.resolve('two'), Promise.reject(new Error('denied!'))];
  let values = [];
  for (let promise of actions) {
    try {
      let result = yield promise;
      console.log("Got: ", result);
      values.push(result);
    } catch(e) {
      console.error("Caught rejection:", e);
    }
  }
  return values;
 
});
 result.then(res => console.log("Final result: ", res)
    .catch(err => console.error("Rejected: ", err);
// "Got: one"
// "Got: two"
// "Caught rejection: Denied!"
// "Final result: [one, two]"
{
"name": "spawn-example",
"main": "./spawn.js",
"version": "0.1.0"
}
'use strict';
function spawn(genFn, args = []) {
return new Promise(resolve => {
const gen = Reflect.apply(genFn, this, args);
resolve(tick());
function tick(step) {
if (step && step.done) return step.value;
let stepResult = step ? Promise.resolve(step.value) : Promise.resolve(undefined);
return stepResult.then(pass).catch(fail);
}
function pass(res) {
try {
res = gen.next(res);
} catch(e) {
return Promise.reject(e);
}
return tick(res);
}
function fail(err) {
try {
err = gen.throw(err);
} catch(e) {
return Promise.reject(e);
}
return tick(err);
}
});
}
module.exports = spawn;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment