Socket
Socket
Sign inDemoInstall

deferred

Package Overview
Dependencies
1
Maintainers
1
Versions
44
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

deferred


Version published
Maintainers
1
Install size
220 kB
Created

Package description

What is deferred?

The 'deferred' npm package provides a way to handle asynchronous operations in JavaScript using promises. It allows you to create deferred objects that can be resolved or rejected at a later time, making it easier to manage complex asynchronous workflows.

What are deferred's main functionalities?

Creating a Deferred Object

This feature allows you to create a deferred object and resolve it at a later time. The deferred object has a promise property that can be used to handle the result of the asynchronous operation.

const deferred = require('deferred');
const d = deferred();

// Simulate an asynchronous operation
setTimeout(() => {
  d.resolve('Operation successful');
}, 1000);

// Using the promise
const promise = d.promise;
promise.then((result) => {
  console.log(result); // Output: Operation successful
});

Chaining Promises

This feature demonstrates how to chain multiple promises together. Each then() method returns a new promise, allowing you to handle the result of one asynchronous operation and pass it to the next.

const deferred = require('deferred');
const d = deferred();

// Simulate an asynchronous operation
setTimeout(() => {
  d.resolve('First operation successful');
}, 1000);

// Chaining promises
const promise = d.promise;
promise
  .then((result) => {
    console.log(result); // Output: First operation successful
    return 'Second operation successful';
  })
  .then((result) => {
    console.log(result); // Output: Second operation successful
  });

Handling Errors

This feature shows how to handle errors in asynchronous operations using the catch() method. If the deferred object is rejected, the catch() method will be called with the error.

const deferred = require('deferred');
const d = deferred();

// Simulate an asynchronous operation
setTimeout(() => {
  d.reject(new Error('Operation failed'));
}, 1000);

// Using the promise
const promise = d.promise;
promise
  .then((result) => {
    console.log(result);
  })
  .catch((error) => {
    console.error(error.message); // Output: Operation failed
  });

Other packages similar to deferred

Readme

Source

Asynchronous JavaScript with deferred and promises

Promises in a simple and powerful way. It was built with the less is more mantra in mind. It's just few functions that should give all you need to easily configure complicated asynchronous control flow.

This work is inspired by other deferred/promise implementations, in particular Q by Kris Kowal.

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

## Example

Concat all JavaScript files in a given directory and save it to lib.js.

Plain Node.js:

var fs = require('fs')

  , readdir = fs.readdir
  , readFile = fs.readFile
  , 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;
					}
				});
			}
		});
	});
});

Promises approach:

var promisify = require('deferred').promisify
  , fs = require('fs')

// We prepare promisified versions of each asynchronous function
  , readdir = promisify(fs.readdir)
  , readFile = promisify(fs.readFile)
  , 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')

).end(); // If there was eny error on the way throw it
## Installation ### Node.js

In your project path:

$ npm install deferred
### Browser

You can easily create browser bundle with help of modules-webmake. Mind that it relies on some EcmaScript5 features, so for older browsers you need 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. Decorates function so its execution is delayed in time:

var deferred = require('deferred');

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

		setTimeout(function () {
			d.resolve(fn.apply(self, args));
		}, timeout);

		return d.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);

However 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 function arguments that promise function can take, it can be other promises or any other JavaScript value (however null or undefined will be treated as no value). With such approach you may override result of a promise chain with specific value. It may seem awkward approach at first, but it can be handy when you work with sophisticated promises chains.

#### 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 d = deferred();
d.resolve(delayedAdd(2, 3));
d.promise(function (result) {
	console.log(5); // 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 maintanable 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

When there is no error callback passed, eventual error is silent. To expose the error, end promise chain with .end(), then error that broke the chain will be thrown:

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

It's very important to end your promise chains with end otherwise eventual errors that were not handled will not be exposed.
end is an exit from promises flow. You can call it with one callback argument and it will be called same way as callback passed to Node.js style asynchronous function:

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

Altenatively you can pass two callbacks onsuccess and onerror and that will resemble way .then works, with difference that it won't extend chain with another promise:

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

Just onerror may be provided:

promise(function (value) {
	// process
}).end(null, function (err) {
	// handle error
});

and just onsuccess either (we need to pass null as second argument)

promise(function (value) {
	// process
}).end(function (res) {
	// handle result
}, null); // throw on error
#### Creating resolved promises

With deferred function you may create initially resolved promises.

var promise = deferred(1);

promise(function (result) {
	console.log(result); // 1;
});
## Promisify - working with asynchronous functions as we know it from Node.js

There is a known convention (coined by Node.js) for working with asynchronous calls. The following approach is widely used:

var fs = require('fs');

fs.readFile(__filename, 'utf-8', function (err, content) {
	if (err) {
		// handle error;
		return;
	}
	// process content
});

An asynchronous function receives a callback argument which handles both error and expected value.
It's not convienient to work with both promises and callback style functions. When you decide to build your flow with promises don't mix both concepts, just promisify asynchronous functions so they return promises instead.

var deferred = require('deferred')
	, fs = require('fs')

	, readFile = deferred.promisify(fs.readFile);

readFile(__filename, 'utf-8')(function (content) {
	// process content
}, function (err) {
	// handle error
});

With second argument passed to promisify we may specify length of arguments that function takes before callback argument. It's very handy if we want to work with functions that may call our function with unexpected arguments (e.g. Array's forEach or map)

promisify also takes care of input arguments. It makes sure that all arguments that are to be passed to asynchronous function are first resolved.

## Grouping promises

Sometimes we're interested in results of more than one promise object. We may do it again with help deferred function:

deferred(delayedAdd(2, 3), delayedAdd(3, 5), delayedAdd(1, 7))(function (result) {
	console.log(result); // [5, 8, 8]
});
## Processing collections ### Map

It's analogous to Array's map, with that difference that it returns promise (of an array) that would be resolved when promises for all items are resolved. Any error that would occur will reject the promise and resolve it with same error.

Let's say we have list of filenames and we want to get each file's content:

var readFile = deferred.promisify(fs.readFile);

deferred.map(filenames, function (filename) {
	return readFile(filename, 'utf-8');
})(function (result) {
	// result is an array of file's contents
});

map is also available directly on a promise object, so we may invoke it directly on promise of a collection.

Let's try again previous example but this time instead of relying on already existing filenames, we take list of files from current directory:

var readdir = deferred.promisify(fs.readdir)
	, readFile = deferred.promisify(fs.readFile);

readdir(__dirname).map(function (filename) {
	return readFile(filename, 'utf-8');
})(function (result) {
	// result is an array of file's contents
});

See limitting concurrency section for info on how to limit maximum number of concurrent calls in map

### Reduce

It's same as Array's reduce with that difference that it calls callback only after previous accummulated value is resolved, this way we may accumulate results of collection of promises or invoke some asynchronous tasks one after another.

deferred.reduce([delayedAdd(2, 3), delayedAdd(3, 5), delayedAdd(1, 7)], function (a, b) {
	return delayedAdd(a, b);
})
(function (result) {
	console.log(result); // 21
});

As with map, reduce is also available directly as an extension on promise object.

## Limitting concurrency

There are cases when we don't want to run too many tasks simultaneously. Like common case in Node.js when we don't want to open too many file descriptors. deferred.map accepts fourth argument which is maximum number of tasks that should be run at once:

// Open maximum 100 file descriptors at once
deferred.map(filenames, function (filename) {
	return readFile(filename, 'utf-8');
}, null, 100)(function (result) {
	// result is an array of file's contents
});

Aside of deferred.map there's more generic deferred.gate for limitting concurrent calls of same asynchronouns task:

var fn = deferred.gate(function async() {
	var defer = defered();
	// ..
	return defer.promise;
}, 10);

If there's already 10 concurrent task running async function invocation will be postponed into the queue and released when some of the running tasks will finish its job.

Additionally we may limit number of postponed calls, so if there's more than n of them rest is discarred, it can be done with third argument. In below example, queue holds maximum 3 postponed calls, rest will be discarded.

var fn = deferred.gate(function async() { .. }, 10, 3);
## Promise extensions

Promise objects are equipped with some useful extensions. All extension are optional but are loaded by default when deferred is loaded via require('deferred') import, and that's the recommended way when you work with Node.js. When preparing client-side file (with help of e.g. modules-webmake) you are free to decide, which extensions you want to take (see source of lib/index.js on how to do it)

### get

If you're interested not in promised object, but rather in one of it's properties then use get

var promise = deferred({ foo: 'bar' });

promise(function (obj) {
	console.log(obj.foo); // 'bar';
})

promise.get('foo')(function (value) {
	console.log(value); // 'bar'
});

With single call you can get nested properties as well:

var promise = deferred({ foo: { bar: 317 });

promise(function (obj) {
	console.log(obj.foo.bar); // 317;
})

promise.get('foo', 'bar')(function (value) {
	console.log(value); // 317
});
### invoke & invokeAsync

Schedule function call on promised object

var promise = deferred({ foo: function (arg) { return arg*arg; } });

promise.invoke('foo', 3)(function (result) {
	console.log(result); // 9
});

// For asynchronous functions use invokeAsync
var promise = deferred({ foo: function (arg, callback) {
	setTimeout(function () {
		callback(null, arg*arg);
	}, 100);
} });

promise.invokeAsync('foo', 3)(function (result) {
	console.log(result); // 9
});
### map

As described in Processing collections section it's promise aware version of Array's map

### match

If promise expected value is a list that you want to match into function arguments then use match

var promise = deferred([2, 3]);

promise.match(function (a, b) {
	console.log(a + b); // 5
});
### reduce

Described under Processing collections section. Promise aware version of Array's reduce

## Tests [![Build Status](https://secure.travis-ci.org/medikoo/deferred.png?branch=master)](https://secure.travis-ci.org/medikoo/deferred)

Before running tests make sure you've installed project with dev dependencies npm install --dev

$ npm test

Keywords

FAQs

Last updated on 17 Jul 2012

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Packages

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc