SkillAgentSearch skills...

Deferred

Modular and fast Promises implementation for JavaScript

Install / Use

/learn @medikoo/Deferred
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

[![Build status][semaphore-image]][semaphore-url] [![Windows status][appveyor-image]][appveyor-url] [![Transpilation status][transpilation-image] [![npm version][npm-image]][npm-url]

Deferred

Modular and fast Promises implementation for JavaScript

Implementation originally inspired by Kris Kowal's Q

Deferred is complete, one of the fastest and natural promise implementation in JavaScript, with Deferred you can write clear maintainable code that takes maximum out of asynchronicity, in fact due to multi-dimensional nature of promises (chaining and nesting) you're forced to program declaratively.

With Deferred you also can: Process collections of deferred calls. Handle Node.js asynchronous functions. Limit concurrency of scheduled tasks. Emit progress events or stream results partially on the go.

In the end you may debug your flow by tracking unresolved promises or gathering usage statistics.

For good insight into promise/deferred concept and in general asynchronous programming see also slides from meetjs summit presentation: Asynchronous JavaScript

If you need help with deferred, please ask on dedicated mailing list: deferred-js@googlegroups.com

Comparision with callback style

Example of JavaScript files concatenation:

Plain Node.js, callbacks approach

var fs = require("fs");

var readdir = fs.readdir;
var readFile = fs.readFile;
var writeFile = fs.writeFile;

// Read all filenames in given path
readdir(__dirname, function (err, files) {
  var result, waiting;
  if (err) {
    // if we're unable to get file listing throw error
    throw err;
  }

  // Filter *.js files and generated lib.js
  files = files.filter(function (file) { return file.slice(-3) === ".js" && file !== "lib.js"; });

  // Read content of each file
  waiting = 0;
  result = [];
  files.forEach(function (file, index) {
    ++waiting;
    readFile(file, function (err, content) {
      if (err) {
        // We were not able to read file content, throw error
        throw err;
      }
      result[index] = content;

      if (!--waiting) {
        // Got content of all files
        // Concatenate into one string and write into lib.js
        writeFile(__dirname + "/lib.js", result.join("\n"), function (err) {
          if (err) {
            // We cannot write lib.js file, throw error
            throw err;
          }
        });
      }
    });
  });
});

Implementation with promises:

var promisify = require("deferred").promisify;
var fs = require("fs");

// Convert node.js async functions, into ones that return a promise
var readdir = promisify(fs.readdir);
var readFile = promisify(fs.readFile, 1); // Restrict arity to 1 + callback
var writeFile = promisify(fs.writeFile);

writeFile(
  __dirname + "/lib.js",
  // Read all filenames in given path
  readdir(__dirname)
    // Filter *.js files and generated lib.js
    .invoke("filter", function (file) { return file.slice(-3) === ".js" && file !== "lib.js"; })

    // Read content of all files
    .map(readFile)

    // Concatenate files content into one string
    .invoke("join", "\n")
).done(); // If there was any error on the way throw it

Examples

See examples folder for a demonstration of promises usage in some other real world cases.

Installation

NPM

In your project path:

$ npm install deferred

Browser

Browser bundle can be easily created with help of modules-webmake. Assuming that you have latest Node.js and Git installed, following will work in command shell of any system (Linux/MacOS/Windows):

$ npm install -g webmake
$ git clone git://github.com/medikoo/deferred.git
$ cd deferred
$ npm install
$ cd ..
$ webmake --name=deferred deferred/index.js deferred.js

Last command bundles deferred with all it's functionalities, but you may need just a subset, you can have that by addressing specific modules directly, e.g. with following you will build just core functionality with map extension:

$ webmake --name=deferred --include=deferred/ext/promise/map.js deferred/deferred.js deferred.js

If you work with AMD modules, use amd option, so generated bundle is one:

$ webmake --amd deferred/index.js deferred.js

Mind that deferred relies on some ECMAScript5 features, so for older browsers you need to load as well es5-shim

Deferred/Promise concept

Deferred

For work that doesn't return immediately (asynchronous) you may create deferred object. Deferred holds both resolve and promise objects. Observers interested in value are attached to promise object, with resolve we resolve promise with an actual value. In common usage promise is returned to the world and resolve is kept internally

Let's create delay function decorator:

var deferred = require('deferred');

var delay = function (fn, timeout) {
  return function () {
    var def = deferred(), self = this, args = arguments;

    setTimeout(function () {
      var value;
      try {
        value = fn.apply(self, args));
      } catch (e) {
        def.reject(e);
        return;
      }
      def.resolve(value);
    }, timeout);

    return def.promise;
  };
};

var delayedAdd = delay(function (a, b) {
  return a + b;
}, 100);

var resultPromise = delayedAdd(2, 3);

console.log(deferred.isPromise(resultPromise)); // true

resultPromise(function (value) {
  // Invoked after 100 milliseconds
  console.log(value); // 5
});

Promise

Promise is an object that represents eventual value which may already be available or is expected to be available in a future. Promise may succeed (fulfillment) or fail (rejection). Promise can be resolved only once. In deferred (and most of the other promise implementations) you may listen for the value by passing observers to then function:

promise.then(onsuccess, onfail);

In deferred promise is really a then function, so you may use promise function directly:

promise === promise.then; // true
promise(onsuccess, onfail);

If you want to keep clear visible distinction between promises and other object I encourage you to always use promise.then notation.

Both callbacks onsuccess and onfail are optional. They will be called only once and only either onsuccess or onfail will be called.

Chaining

Promises by nature can be chained. promise function returns another promise which is resolved with a value returned by a callback function:

delayedAdd(2, 3)(function (result) { return result * result; })(function (result) {
  console.log(result); // 25
});

It's not just functions that promise function can take, it can be other promises or any other JavaScript value (with exception of null or undefined which will be treated as no value). Going that way you may override result of a promise chain with specific value.

Nesting

Promises can be nested. If a promise resolves with another promise, it's not really resolved. It's resolved only when final promise is resolved with a real value:

var def = deferred();
def.resolve(delayedAdd(2, 3)); // Resolve promise with another promise
def.promise(function (result) {
  console.log(result); // 5;
});
Error handling

Errors in promises are handled with separate control flow, that's one of the reasons why code written with promises is more readable and maintainable than when using callbacks approach.

A promise resolved with an error (rejected), propagates its error to all promises that depend on this promise (e.g. promises initiated by adding observers). If observer function crashes with error or returns error, its promise is rejected with the error.

To handle error, pass dedicated callback as second argument to promise function:

delayedAdd(2, 3)(function (result) { throw new Error("Error!"); })(
  function () {
    // never called
  },
  function (e) {
    // handle error;
  }
);
Ending chain

To expose the errors that are not handled, end promise chain with .done(), then error that broke the chain will be thrown:

delayedAdd(2, 3)(function (result) { throw new Error("Error!"); })(function (result) {
  // never executed
}).done(); // throws error!

It's important to end your promise chains with done otherwise eventual ignored errors will not be exposed.

Signature of done function is same as for then (or promise itself)

done is aliased with end function, however end will be removed with introduction of v0.7 release.

promise(function (value) {
  // process
}).done(
  function (result) {
    // process result
  },
  function (err) {
    // handle error
  }
);

And as with then either callback can be provided. If callback for error was omitted, eventual error will be thrown.

Creating resolved promises

You may create initially resolved promises.

var promise = deferred(1);

promise(function (result) {
  console.log(result); // 1;
});

Working with asynchronous functions

promisify(fn[, length])

There is a known convention (coined by Node.js) for working with asynchronous calls. An asynchronous function receives a callback argument which handles both eventual error and expected value:

var fs = require("fs");

fs.readFile(__filename, "utf-8", function (err, content) {
  if (err) {
    // handle error;
    return;
  }
  /
View on GitHub
GitHub Stars363
CategoryDevelopment
Updated1mo ago
Forks18

Languages

JavaScript

Security Score

95/100

Audited on Feb 13, 2026

No findings