CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-co

Generator-based async control flow library for Node.js and browsers using promises

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

co

co is a generator-based control flow library for Node.js and browsers that allows writing asynchronous code in a synchronous-looking style using JavaScript generators and promises. It serves as a stepping stone toward ES7 async/await syntax, providing a clean abstraction for complex asynchronous operations while maintaining backward compatibility.

Package Information

  • Package Name: co
  • Package Type: npm
  • Language: JavaScript
  • Installation: npm install co

Core Imports

const co = require('co');

ES6 modules:

import co from 'co';

Alternative access patterns:

const co = require('co');
// co is also available as:
co.default(); // Same as co()
co.co();      // Same as co()

Basic Usage

const co = require('co');

// Execute a generator function that yields promises
co(function* () {
  // Yield promises for async operations
  const result1 = yield Promise.resolve('Hello');
  const result2 = yield Promise.resolve('World');
  
  return `${result1} ${result2}`;
}).then(function(value) {
  console.log(value); // "Hello World"
}).catch(function(err) {
  console.error(err.stack);
});

// Wrap a generator function to return a promise-returning function
const asyncFunction = co.wrap(function* (name) {
  const greeting = yield Promise.resolve('Hello');
  return `${greeting}, ${name}!`;
});

asyncFunction('Alice').then(console.log); // "Hello, Alice!"

Capabilities

Generator Execution

Execute generator functions or generator instances and return promises.

/**
 * Execute the generator function or a generator and return a promise
 * @param {GeneratorFunction|Generator} gen - Generator function or generator instance
 * @param {...any} args - Additional arguments passed to generator function
 * @returns {Promise} Promise that resolves with the generator's return value
 */
function co(gen, ...args);

Usage Examples:

// Execute generator function
co(function* () {
  const data = yield fetch('/api/data').then(res => res.json());
  return data;
}).then(result => console.log(result));

// Execute with context and arguments
const result = co.call(context, function* (param1, param2) {
  return yield someAsyncOperation(param1, param2);
}, 'arg1', 'arg2');

// Execute generator instance
function* myGenerator() {
  return yield Promise.resolve('done');
}
co(myGenerator()).then(console.log);

Function Wrapping

Wrap generator functions to return promise-returning functions.

/**
 * Wrap the given generator function into a function that returns a promise
 * @param {GeneratorFunction} fn - Generator function to wrap
 * @returns {Function} Function that returns a promise when called
 */
co.wrap(fn);

Usage Examples:

// Create reusable async function
const fetchUser = co.wrap(function* (userId) {
  const user = yield fetch(`/api/users/${userId}`).then(res => res.json());
  const profile = yield fetch(`/api/profiles/${user.profileId}`).then(res => res.json());
  return { ...user, profile };
});

// Use the wrapped function
fetchUser(123).then(user => console.log(user));

// Access original generator function
console.log(fetchUser.__generatorFunction__); // Original generator function

Yieldable Types

co supports yielding various types of values that represent asynchronous operations:

Promises

Yield promise objects directly for async operations.

co(function* () {
  const result = yield Promise.resolve('value');
  const data = yield fetch('/api').then(res => res.json());
  return { result, data };
});

Thunks

Yield functions that accept a single callback parameter (legacy support).

co(function* () {
  // Thunk function
  const result = yield function(callback) {
    setTimeout(() => callback(null, 'delayed value'), 100);
  };
  return result;
});

Arrays (Parallel Execution)

Yield arrays of yieldable values for parallel execution using Promise.all().

co(function* () {
  // Execute promises in parallel
  const [user, posts, comments] = yield [
    fetch('/api/user').then(res => res.json()),
    fetch('/api/posts').then(res => res.json()),
    fetch('/api/comments').then(res => res.json())
  ];
  
  return { user, posts, comments };
});

Objects (Parallel Execution)

Yield objects with yieldable properties for parallel execution with labeled results.

co(function* () {
  // Execute promises in parallel with named results
  const results = yield {
    userData: fetch('/api/user').then(res => res.json()),
    settings: fetch('/api/settings').then(res => res.json()),
    notifications: fetch('/api/notifications').then(res => res.json())
  };
  
  // results = { userData: {...}, settings: {...}, notifications: [...] }
  return results;
});

Generators and Generator Functions

Yield other generators or generator functions for delegation.

function* fetchUserData(userId) {
  const user = yield fetch(`/api/users/${userId}`).then(res => res.json());
  return user;
}

co(function* () {
  // Yield generator function (executed with co)
  const user1 = yield fetchUserData(1);
  
  // Yield generator instance
  const user2 = yield fetchUserData(2);
  
  return [user1, user2];
});

Error Handling

co provides comprehensive error handling through promises and try/catch blocks:

// Promise-based error handling
co(function* () {
  return yield Promise.reject(new Error('Something went wrong'));
}).catch(err => {
  console.error('Caught error:', err.message);
});

// Generator try/catch error handling
co(function* () {
  try {
    const result = yield Promise.reject(new Error('API Error'));
  } catch (err) {
    console.error('Handled in generator:', err.message);
    return 'fallback value';
  }
});

// Invalid yieldable type error
co(function* () {
  try {
    // This will throw a TypeError
    const result = yield "invalid yieldable";
  } catch (err) {
    console.error(err.message);
    // "You may only yield a function, promise, generator, array, or object, but the following object was passed: "invalid yieldable""
  }
});

Platform Compatibility

  • Node.js: Requires Node.js 0.12.0+ or io.js 1.0.0+
  • Generators: Requires --harmony flag for Node.js versions < 4.0
  • Promises: Requires native Promise support or polyfill
  • Browser: Supported via browserify build

Advanced Patterns

Nested Yieldables

co supports deeply nested structures of yieldable objects:

co(function* () {
  const result = yield {
    users: [
      fetch('/api/users/1').then(res => res.json()),
      fetch('/api/users/2').then(res => res.json())
    ],
    metadata: {
      count: fetch('/api/users/count').then(res => res.json()),
      lastUpdated: Promise.resolve(new Date())
    }
  };
  
  return result;
});

Context Preservation

co preserves the this context throughout generator execution:

const api = {
  baseUrl: 'https://api.example.com',
  
  fetchData: co.wrap(function* (endpoint) {
    const url = `${this.baseUrl}${endpoint}`; // 'this' is preserved
    return yield fetch(url).then(res => res.json());
  })
};

api.fetchData('/users').then(console.log);

Install with Tessl CLI

npx tessl i tessl/npm-co
Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/co@4.6.x
Publish Source
CLI
Badge
tessl/npm-co badge