Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 662 lines (478 sloc) 22.215 kb
64053aa5 »
2012-09-21 Update documentation for v0.6
1 # Deferred – Asynchronous JavaScript with Promises
22f05204 »
2011-07-07 Documentation
2
64053aa5 »
2012-09-21 Update documentation for v0.6
3 _Promises in a simple and powerful way. Implementation originally inspired by Kris Kowal's [Q](https://github.com/kriskowal/q)_
22f05204 »
2011-07-07 Documentation
4
e38bda27 »
2012-09-22 Documentation improvements
5 Deferred is complete, __[fastest](#performance)__ and most natural promise implementation in JavaScript, with Deferred you can write __[clear maintainable code](#promises-approach)__ that takes maximum out of asynchronicity, in fact due to multi-dimensional nature of promises (__[chaining](#chaining)__ and __[nesting](#nesting)__) you're forced to program declaratively.
64053aa5 »
2012-09-21 Update documentation for v0.6
6
e38bda27 »
2012-09-22 Documentation improvements
7 With Deferred you also can: __[Process collections](#processing-collections)__ of deferred calls. __[Handle Node.js asynchronous functions](#promisify---working-with-asynchronous-functions-as-we-know-them-from-nodejs)__. __[Limit concurrency](#limiting-concurrency)__ of scheduled tasks. __[Emit progress events](#progress-and-other-events)__ or __[stream results partially](#streaming-data-partially)__ on the go.
d8eff9d8 »
2012-09-22 Documentation improvements
8
9 In the end you may debug your flow by __[tracking unresolved promises](#monitoring-unresolved-promises)__ or gathering __[usage statistics](#usage-statistics)__.
10
11 _For good insight into promise/deferred concept and in general asynchronous programming see also slides from meetjs summit presentation: [Asynchronous JavaScript](http://www.medikoo.com/asynchronous-javascript/)_
3109fb59 »
2012-03-22 Update README.md
12
e38bda27 »
2012-09-22 Documentation improvements
13 __If you need help with deferred, just ask on our open mailing list: [deferred-js@googlegroups.com](https://groups.google.com/forum/#!forum/deferred-js)__
14
d5c80396 »
2012-01-08 Documentation for v0.3
15 ## Example
22f05204 »
2011-07-07 Documentation
16
7f6550cc »
2012-01-08 Documentation improvements
17 Concat all JavaScript files in a given directory and save it to lib.js.
22f05204 »
2011-07-07 Documentation
18
d8eff9d8 »
2012-09-22 Documentation improvements
19 ### Plain Node.js:
22f05204 »
2011-07-07 Documentation
20
0bfd1b8d »
2012-01-20 JavaScript code displayed with proper highlighting
21 ```javascript
64053aa5 »
2012-09-21 Update documentation for v0.6
22 var fs = require('fs');
0bfd1b8d »
2012-01-20 JavaScript code displayed with proper highlighting
23
64053aa5 »
2012-09-21 Update documentation for v0.6
24 var readdir = fs.readdir;
25 var readFile = fs.readFile;
26 var writeFile = fs.writeFile;
0bfd1b8d »
2012-01-20 JavaScript code displayed with proper highlighting
27
28 // Read all filenames in given path
29 readdir(__dirname, function (err, files) {
30 var result, waiting;
31 if (err) {
32 // if we're unable to get file listing throw error
33 throw err;
34 }
35
f8aca4d7 »
2012-04-20 Update README.md
36 // Filter *.js files and generated lib.js
0bfd1b8d »
2012-01-20 JavaScript code displayed with proper highlighting
37 files = files.filter(function (file) {
38 return (file.slice(-3) === '.js') && (file !== 'lib.js');
39 });
d5c80396 »
2012-01-08 Documentation for v0.3
40
0bfd1b8d »
2012-01-20 JavaScript code displayed with proper highlighting
41 // Read content of each file
42 waiting = 0;
43 result = [];
44 files.forEach(function (file, index) {
45 ++waiting;
f8aca4d7 »
2012-04-20 Update README.md
46 readFile(file, function (err, content) {
0bfd1b8d »
2012-01-20 JavaScript code displayed with proper highlighting
47 if (err) {
48 // We were not able to read file content, throw error
49 throw err;
50 }
51 result[index] = content;
52
53 if (!--waiting) {
54 // Got content of all files
55 // Concatenate into one string and write into lib.js
56 writeFile(__dirname + '/lib.js', result.join("\n"), function (err) {
57 if (err) {
58 // We cannot write lib.js file, throw error
59 throw err;
60 }
61 });
62 }
d5c80396 »
2012-01-08 Documentation for v0.3
63 });
64 });
0bfd1b8d »
2012-01-20 JavaScript code displayed with proper highlighting
65 });
66 ```
22f05204 »
2011-07-07 Documentation
67
d8eff9d8 »
2012-09-22 Documentation improvements
68 ### Promises approach:
22f05204 »
2011-07-07 Documentation
69
0bfd1b8d »
2012-01-20 JavaScript code displayed with proper highlighting
70 ```javascript
64053aa5 »
2012-09-21 Update documentation for v0.6
71 var promisify = require('deferred').promisify;
72 var fs = require('fs');
22f05204 »
2011-07-07 Documentation
73
64053aa5 »
2012-09-21 Update documentation for v0.6
74 // We prepare promisified versions of each asynchronous function
75 var readdir = promisify(fs.readdir);
76 var readFile = promisify(fs.readFile, 1);
77 var writeFile = promisify(fs.writeFile);
22f05204 »
2011-07-07 Documentation
78
0bfd1b8d »
2012-01-20 JavaScript code displayed with proper highlighting
79 writeFile(__dirname + '/lib.js',
80 // Read all filenames in given path
81 readdir(__dirname)
22f05204 »
2011-07-07 Documentation
82
f8aca4d7 »
2012-04-20 Update README.md
83 // Filter *.js files and generated lib.js
0bfd1b8d »
2012-01-20 JavaScript code displayed with proper highlighting
84 .invoke('filter', function (file) {
85 return (file.slice(-3) === '.js') && (file !== 'lib.js');
86 })
75d8af7d »
2011-08-07 Renamed 'chain' dir to 'join', as it's about joining promises
87
0bfd1b8d »
2012-01-20 JavaScript code displayed with proper highlighting
88 // Read content of all files
f8aca4d7 »
2012-04-20 Update README.md
89 .map(readFile)
75d8af7d »
2011-08-07 Renamed 'chain' dir to 'join', as it's about joining promises
90
0bfd1b8d »
2012-01-20 JavaScript code displayed with proper highlighting
91 // Concatenate files content into one string
92 .invoke('join', '\n')
22f05204 »
2011-07-07 Documentation
93
64053aa5 »
2012-09-21 Update documentation for v0.6
94 ).end(); // If there was any error on the way throw it
0bfd1b8d »
2012-01-20 JavaScript code displayed with proper highlighting
95 ```
22f05204 »
2011-07-07 Documentation
96
d5c80396 »
2012-01-08 Documentation for v0.3
97 ## Installation
22f05204 »
2011-07-07 Documentation
98
64053aa5 »
2012-09-21 Update documentation for v0.6
99 ### NPM
22f05204 »
2011-07-07 Documentation
100
d5c80396 »
2012-01-08 Documentation for v0.3
101 In your project path:
22f05204 »
2011-07-07 Documentation
102
d5c80396 »
2012-01-08 Documentation for v0.3
103 $ npm install deferred
22f05204 »
2011-07-07 Documentation
104
d5c80396 »
2012-01-08 Documentation for v0.3
105 ### Browser
22f05204 »
2011-07-07 Documentation
106
f77d6ca5 »
2012-02-02 Documentation
107 You can easily create browser bundle with help of [modules-webmake](https://github.com/medikoo/modules-webmake). Mind that it relies on some EcmaScript5 features, so for older browsers you need as well [es5-shim](https://github.com/kriskowal/es5-shim)
22f05204 »
2011-07-07 Documentation
108
d5c80396 »
2012-01-08 Documentation for v0.3
109 ## Deferred/Promise concept
22f05204 »
2011-07-07 Documentation
110
d5c80396 »
2012-01-08 Documentation for v0.3
111 ### Deferred
22f05204 »
2011-07-07 Documentation
112
929a93ab »
2012-01-25 Better documentation
113 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
22f05204 »
2011-07-07 Documentation
114
64053aa5 »
2012-09-21 Update documentation for v0.6
115 Let's create `delay` function decorator:
22f05204 »
2011-07-07 Documentation
116
0bfd1b8d »
2012-01-20 JavaScript code displayed with proper highlighting
117 ```javascript
118 var deferred = require('deferred');
22f05204 »
2011-07-07 Documentation
119
0bfd1b8d »
2012-01-20 JavaScript code displayed with proper highlighting
120 var delay = function (fn, timeout) {
121 return function () {
2ce4df6c »
2012-07-12 Name deferred objects `def` instead of `d`
122 var def = deferred(), self = this, args = arguments;
22f05204 »
2011-07-07 Documentation
123
0bfd1b8d »
2012-01-20 JavaScript code displayed with proper highlighting
124 setTimeout(function () {
2ce4df6c »
2012-07-12 Name deferred objects `def` instead of `d`
125 def.resolve(fn.apply(self, args));
0bfd1b8d »
2012-01-20 JavaScript code displayed with proper highlighting
126 }, timeout);
d5c80396 »
2012-01-08 Documentation for v0.3
127
2ce4df6c »
2012-07-12 Name deferred objects `def` instead of `d`
128 return def.promise;
22f05204 »
2011-07-07 Documentation
129 };
0bfd1b8d »
2012-01-20 JavaScript code displayed with proper highlighting
130 };
22f05204 »
2011-07-07 Documentation
131
0bfd1b8d »
2012-01-20 JavaScript code displayed with proper highlighting
132 var delayedAdd = delay(function (a, b) {
133 return a + b;
134 }, 100);
22f05204 »
2011-07-07 Documentation
135
0bfd1b8d »
2012-01-20 JavaScript code displayed with proper highlighting
136 var resultPromise = delayedAdd(2, 3);
22f05204 »
2011-07-07 Documentation
137
0bfd1b8d »
2012-01-20 JavaScript code displayed with proper highlighting
138 console.log(deferred.isPromise(resultPromise)); // true
22f05204 »
2011-07-07 Documentation
139
0bfd1b8d »
2012-01-20 JavaScript code displayed with proper highlighting
140 resultPromise(function (value) {
141 // Invoked after 100 milliseconds
142 console.log(value); // 5
143 });
144 ```
22f05204 »
2011-07-07 Documentation
145
d5c80396 »
2012-01-08 Documentation for v0.3
146 ### Promise
22f05204 »
2011-07-07 Documentation
147
929a93ab »
2012-01-25 Better documentation
148 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.
d5c80396 »
2012-01-08 Documentation for v0.3
149 In `deferred` (and most of the other promise implementations) you may listen for the value by passing observers to `then` function:
22f05204 »
2011-07-07 Documentation
150
0bfd1b8d »
2012-01-20 JavaScript code displayed with proper highlighting
151 ```javascript
152 promise.then(onsuccess, onfail);
153 ```
22f05204 »
2011-07-07 Documentation
154
82c63102 »
2012-01-08 Documentation
155 In __deferred__ promise is really a `then` function, so you may use promise _function_ directly:
22f05204 »
2011-07-07 Documentation
156
0bfd1b8d »
2012-01-20 JavaScript code displayed with proper highlighting
157 ```javascript
158 promise === promise.then; // true
f9b961a5 »
2012-02-20 Documentation
159 promise(onsuccess, onfail);
0bfd1b8d »
2012-01-20 JavaScript code displayed with proper highlighting
160 ```
d5c80396 »
2012-01-08 Documentation for v0.3
161
64053aa5 »
2012-09-21 Update documentation for v0.6
162 __If you want to keep clear visible distinction between promises and other object I encourage you to always use `promise.then` notation.__
22f05204 »
2011-07-07 Documentation
163
2a888df6 »
2012-03-11 Update README.md
164 Both callbacks `onsuccess` and `onfail` are optional. They will be called only once and only either `onsuccess` or `onfail` will be called.
22f05204 »
2011-07-07 Documentation
165
d5c80396 »
2012-01-08 Documentation for v0.3
166 #### Chaining
22f05204 »
2011-07-07 Documentation
167
a51ee889 »
2012-01-25 Better documentation
168 Promises by nature can be chained. `promise` function returns another promise which is resolved with a value returned by a callback function:
22f05204 »
2011-07-07 Documentation
169
0bfd1b8d »
2012-01-20 JavaScript code displayed with proper highlighting
170 ```javascript
7b5c4bf0 »
2012-02-20 Documentation
171 delayedAdd(2, 3)(function (result) {
172 return result * result
173 })(function (result) {
0bfd1b8d »
2012-01-20 JavaScript code displayed with proper highlighting
174 console.log(result); // 25
175 });
176 ```
22f05204 »
2011-07-07 Documentation
177
64053aa5 »
2012-09-21 Update documentation for v0.6
178 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.
22f05204 »
2011-07-07 Documentation
179
d5c80396 »
2012-01-08 Documentation for v0.3
180 #### Nesting
22f05204 »
2011-07-07 Documentation
181
a51ee889 »
2012-01-25 Better documentation
182 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:
22f05204 »
2011-07-07 Documentation
183
0bfd1b8d »
2012-01-20 JavaScript code displayed with proper highlighting
184 ```javascript
2ce4df6c »
2012-07-12 Name deferred objects `def` instead of `d`
185 var def = deferred();
64053aa5 »
2012-09-21 Update documentation for v0.6
186 def.resolve(delayedAdd(2, 3)); // Resolve promise with another promise
2ce4df6c »
2012-07-12 Name deferred objects `def` instead of `d`
187 def.promise(function (result) {
0bfd1b8d »
2012-01-20 JavaScript code displayed with proper highlighting
188 console.log(5); // 5;
189 });
190 ```
22f05204 »
2011-07-07 Documentation
191
d5c80396 »
2012-01-08 Documentation for v0.3
192 #### Error handling
22f05204 »
2011-07-07 Documentation
193
64053aa5 »
2012-09-21 Update documentation for v0.6
194 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.
22f05204 »
2011-07-07 Documentation
195
a51ee889 »
2012-01-25 Better documentation
196 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).
197 If observer function crashes with error or returns error, its promise is rejected with the error.
22f05204 »
2011-07-07 Documentation
198
7f6550cc »
2012-01-08 Documentation improvements
199 To handle error, pass dedicated callback as second argument to promise function:
22f05204 »
2011-07-07 Documentation
200
0bfd1b8d »
2012-01-20 JavaScript code displayed with proper highlighting
201 ```javascript
7b5c4bf0 »
2012-02-20 Documentation
202 delayedAdd(2, 3)(function (result) {
0bfd1b8d »
2012-01-20 JavaScript code displayed with proper highlighting
203 throw new Error('Error!')
7b5c4bf0 »
2012-02-20 Documentation
204 })(function () {
0bfd1b8d »
2012-01-20 JavaScript code displayed with proper highlighting
205 // never called
206 }, function (e) {
207 // handle error;
208 });
209 ```
22f05204 »
2011-07-07 Documentation
210
1d9044aa »
2012-01-19 Update documentation
211 #### Ending chain
212
64053aa5 »
2012-09-21 Update documentation for v0.6
213 To expose the errors that are not handled, end promise chain with `.end()`, then error that broke the chain will be thrown:
22f05204 »
2011-07-07 Documentation
214
0bfd1b8d »
2012-01-20 JavaScript code displayed with proper highlighting
215 ```javascript
216 delayedAdd(2, 3)
217 (function (result) {
218 throw new Error('Error!')
7b5c4bf0 »
2012-02-20 Documentation
219 })(function (result) {
0bfd1b8d »
2012-01-20 JavaScript code displayed with proper highlighting
220 // never executed
221 })
222 .end(); // throws error!
223 ```
b4d41a00 »
2012-01-19 Documentation
224
64053aa5 »
2012-09-21 Update documentation for v0.6
225 __It's important to end your promise chains with `end` otherwise eventual ignored errors will not be exposed__.
22f05204 »
2011-07-07 Documentation
226
64053aa5 »
2012-09-21 Update documentation for v0.6
227 Signature of `end` function is same as for `then` (or promise itself)
1ed06846 »
2011-07-08 Documentation
228
0bfd1b8d »
2012-01-20 JavaScript code displayed with proper highlighting
229 ```javascript
230 promise(function (value) {
231 // process
232 }).end(function (result) {
233 // process result
234 }, function (err) {
235 // handle error
236 });
237 ```
1d9044aa »
2012-01-19 Update documentation
238
64053aa5 »
2012-09-21 Update documentation for v0.6
239 And as with `then` either callback can be provided. If callback for error was omitted, eventual error will be thrown.
1d9044aa »
2012-01-19 Update documentation
240
d5c80396 »
2012-01-08 Documentation for v0.3
241 #### Creating resolved promises
1ed06846 »
2011-07-08 Documentation
242
64053aa5 »
2012-09-21 Update documentation for v0.6
243 You may create initially resolved promises.
1ed06846 »
2011-07-08 Documentation
244
0bfd1b8d »
2012-01-20 JavaScript code displayed with proper highlighting
245 ```javascript
246 var promise = deferred(1);
22f05204 »
2011-07-07 Documentation
247
0bfd1b8d »
2012-01-20 JavaScript code displayed with proper highlighting
248 promise(function (result) {
249 console.log(result); // 1;
250 });
251 ```
22f05204 »
2011-07-07 Documentation
252
64053aa5 »
2012-09-21 Update documentation for v0.6
253 ## Promisify - working with asynchronous functions as we know them from Node.js
22f05204 »
2011-07-07 Documentation
254
64053aa5 »
2012-09-21 Update documentation for v0.6
255 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:
22f05204 »
2011-07-07 Documentation
256
0bfd1b8d »
2012-01-20 JavaScript code displayed with proper highlighting
257 ```javascript
258 var fs = require('fs');
22f05204 »
2011-07-07 Documentation
259
0bfd1b8d »
2012-01-20 JavaScript code displayed with proper highlighting
260 fs.readFile(__filename, 'utf-8', function (err, content) {
261 if (err) {
262 // handle error;
263 return;
264 }
265 // process content
266 });
267 ```
22f05204 »
2011-07-07 Documentation
268
64053aa5 »
2012-09-21 Update documentation for v0.6
269 It's not convenient 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__.
22f05204 »
2011-07-07 Documentation
270
0bfd1b8d »
2012-01-20 JavaScript code displayed with proper highlighting
271 ```javascript
272 var deferred = require('deferred')
273 , fs = require('fs')
22f05204 »
2011-07-07 Documentation
274
0bfd1b8d »
2012-01-20 JavaScript code displayed with proper highlighting
275 , readFile = deferred.promisify(fs.readFile);
22f05204 »
2011-07-07 Documentation
276
7b5c4bf0 »
2012-02-20 Documentation
277 readFile(__filename, 'utf-8')(function (content) {
278 // process content
279 }, function (err) {
280 // handle error
281 });
0bfd1b8d »
2012-01-20 JavaScript code displayed with proper highlighting
282 ```
22f05204 »
2011-07-07 Documentation
283
64053aa5 »
2012-09-21 Update documentation for v0.6
284 `promisify` accepts also second argument, through which we may specify length of arguments that function takes (not counting callback argument), it may be handy if there's a chance that unexpected arguments will be passed to function (e.g. Array's `forEach` or `map`)
a51ee889 »
2012-01-25 Better documentation
285
286 `promisify` also takes care of input arguments. __It makes sure that all arguments that are to be passed to asynchronous function are first resolved.__
22f05204 »
2011-07-07 Documentation
287
d5c80396 »
2012-01-08 Documentation for v0.3
288 ## Grouping promises
22f05204 »
2011-07-07 Documentation
289
64053aa5 »
2012-09-21 Update documentation for v0.6
290 When we're interested in results of more than one promise object we may group them into one promise with `deferred` function:
22f05204 »
2011-07-07 Documentation
291
0bfd1b8d »
2012-01-20 JavaScript code displayed with proper highlighting
292 ```javascript
7b5c4bf0 »
2012-02-20 Documentation
293 deferred(delayedAdd(2, 3), delayedAdd(3, 5), delayedAdd(1, 7))(function (result) {
0bfd1b8d »
2012-01-20 JavaScript code displayed with proper highlighting
294 console.log(result); // [5, 8, 8]
295 });
296 ```
22f05204 »
2011-07-07 Documentation
297
d5c80396 »
2012-01-08 Documentation for v0.3
298 ## Processing collections
22f05204 »
2011-07-07 Documentation
299
d5c80396 »
2012-01-08 Documentation for v0.3
300 ### Map
22f05204 »
2011-07-07 Documentation
301
a51ee889 »
2012-01-25 Better documentation
302 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.
22f05204 »
2011-07-07 Documentation
303
d8eff9d8 »
2012-09-22 Documentation improvements
304 In following example we take content of each file found in an array:
22f05204 »
2011-07-07 Documentation
305
0bfd1b8d »
2012-01-20 JavaScript code displayed with proper highlighting
306 ```javascript
307 var readFile = deferred.promisify(fs.readFile);
22f05204 »
2011-07-07 Documentation
308
0bfd1b8d »
2012-01-20 JavaScript code displayed with proper highlighting
309 deferred.map(filenames, function (filename) {
310 return readFile(filename, 'utf-8');
7b5c4bf0 »
2012-02-20 Documentation
311 })(function (result) {
0bfd1b8d »
2012-01-20 JavaScript code displayed with proper highlighting
312 // result is an array of file's contents
313 });
314 ```
22f05204 »
2011-07-07 Documentation
315
d5c80396 »
2012-01-08 Documentation for v0.3
316 `map` is also available directly on a promise object, so we may invoke it directly on promise of a collection.
22f05204 »
2011-07-07 Documentation
317
7f6550cc »
2012-01-08 Documentation improvements
318 Let's try again previous example but this time instead of relying on already existing filenames, we take list of files from current directory:
22f05204 »
2011-07-07 Documentation
319
0bfd1b8d »
2012-01-20 JavaScript code displayed with proper highlighting
320 ```javascript
64053aa5 »
2012-09-21 Update documentation for v0.6
321 var readdir = deferred.promisify(fs.readdir);
322 var readFile = deferred.promisify(fs.readFile);
22f05204 »
2011-07-07 Documentation
323
0bfd1b8d »
2012-01-20 JavaScript code displayed with proper highlighting
324 readdir(__dirname).map(function (filename) {
325 return readFile(filename, 'utf-8');
7b5c4bf0 »
2012-02-20 Documentation
326 })(function (result) {
327 // result is an array of file's contents
328 });
329 ```
330
64053aa5 »
2012-09-21 Update documentation for v0.6
331 This function is available also as an extension on promise object.
332
333 __See [limiting concurrency](#limiting-concurrency) section for info on how to limit maximum number of concurrent calls in `map`__
22f05204 »
2011-07-07 Documentation
334
d5c80396 »
2012-01-08 Documentation for v0.3
335 ### Reduce
22f05204 »
2011-07-07 Documentation
336
64053aa5 »
2012-09-21 Update documentation for v0.6
337 It's same as Array's reduce with that difference that it calls callback only after previous accumulated value is resolved, this way we may accumulate results of collection of promises or invoke some asynchronous tasks one after another.
22f05204 »
2011-07-07 Documentation
338
0bfd1b8d »
2012-01-20 JavaScript code displayed with proper highlighting
339 ```javascript
340 deferred.reduce([delayedAdd(2, 3), delayedAdd(3, 5), delayedAdd(1, 7)], function (a, b) {
341 return delayedAdd(a, b);
342 })
343 (function (result) {
344 console.log(result); // 21
345 });
346 ```
22f05204 »
2011-07-07 Documentation
347
64053aa5 »
2012-09-21 Update documentation for v0.6
348 This function is available also as an extension on promise object.
22f05204 »
2011-07-07 Documentation
349
64053aa5 »
2012-09-21 Update documentation for v0.6
350 ### Some
70a87eb4 »
2012-05-28 Add Limitting concurrency section.
351
64053aa5 »
2012-09-21 Update documentation for v0.6
352 Promise aware Array's some. Process collection one after another and stop when first item matches your criteria
70a87eb4 »
2012-05-28 Add Limitting concurrency section.
353
354 ```javascript
64053aa5 »
2012-09-21 Update documentation for v0.6
355 deferred.some([filename1, filename2, filename3], function (a) {
356 return readFile(filename, 'utf8', function (data) {
357 if (data.indexOf('needle')) {
358 // Got it! Stop further processing
359 return true;
360 }
361 });
70a87eb4 »
2012-05-28 Add Limitting concurrency section.
362 });
363 ```
364
64053aa5 »
2012-09-21 Update documentation for v0.6
365 This function is available also as an extension on promise object.
366
367 ## Limiting concurrency
368
369 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.
370
77b887c8 »
2012-09-22 Documentation
371 Handle that with `deferred.gate`:
70a87eb4 »
2012-05-28 Add Limitting concurrency section.
372
373 ```javascript
374 var fn = deferred.gate(function async() {
64053aa5 »
2012-09-21 Update documentation for v0.6
375 var def = deferred();
70a87eb4 »
2012-05-28 Add Limitting concurrency section.
376 // ..
64053aa5 »
2012-09-21 Update documentation for v0.6
377 return def.promise;
70a87eb4 »
2012-05-28 Add Limitting concurrency section.
378 }, 10);
379 ```
380
64053aa5 »
2012-09-21 Update documentation for v0.6
381 If there are already 10 concurrent tasks running `async` function invocation will be postponed into the queue and released when first of the running tasks will finish its job.
70a87eb4 »
2012-05-28 Add Limitting concurrency section.
382
64053aa5 »
2012-09-21 Update documentation for v0.6
383 Additionally with third argument, we may limit number of postponed calls, so if there's more than _n_ of them rest is discarded. In below example, queue holds maximum 3 postponed calls, rest will be discarded.
70a87eb4 »
2012-05-28 Add Limitting concurrency section.
384
385 ```javascript
386 var fn = deferred.gate(function async() { .. }, 10, 3);
387 ```
388
64053aa5 »
2012-09-21 Update documentation for v0.6
389 In following example we'll limit concurrent readFile calls when using deferred.map:
390
391 ```javascript
392 // Open maximum 100 file descriptors at once
393 deferred.map(filenames, deferred.gate(function (filename) {
394 return readFile(filename, 'utf-8');
395 }, 100))(function (result) {
396 // result is an array of file's contents
397 });
398 ```
399
d8eff9d8 »
2012-09-22 Documentation improvements
400 ## Progress and other events
401
402 __Promise objects are also an event emitters__. Deferred implementation is backed by cross-environment [event-emitter solution](https://github.com/medikoo/event-emitter)
403
404 Simple Ajax file uploader example:
405
406 ```javascript
407 var ajaxFileUploader = function (url, data) {
408 var def = deferred();
409 var xhr = new XMLHttpRequest();
410
411 xhr.open('POST', url, true);
412 xhr.onload = def.resolve;
413 xhr.onerror = function () {
414 def.resolve(new Error("Could not upload files"));
415 };
416 xhr.upload.onprogress = function (e) {
417 def.promise.emit('progress', e);
418 };
419 xhr.send(data);
420 return def.promise;
421 };
422
423 var upload = ajaxFileUploader(formData);
424 upload.on('progress', function () {
425 // process progress events
426 });
427 upload.end(function (e) {
428 // All files uploaded!
429 });
430 ```
431 ### Streaming data partially
432
433 Another use case would be to provide obtained data partially on the go (stream like).
434 Imagine recursive directory reader that scans whole file system and provides filenames as it approaches them:
435
436 ```javascript
437 var reader = readdirDeep(rootPath); // reader promise is returned
438 reader.on('data', function (someFilenames) {
439 // Called many times during scan with obtained names
440 });
441 reader.end(function (allFilenames) {
442 // File-system scan finished!
443 });
444 ```
445
d5c80396 »
2012-01-08 Documentation for v0.3
446 ## Promise extensions
22f05204 »
2011-07-07 Documentation
447
64053aa5 »
2012-09-21 Update documentation for v0.6
448 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.
449 When preparing client-side file (with help of e.g. [modules-webmake](https://github.com/medikoo/modules-webmake)) you are free to decide, which extensions you want to take (see source of `lib/index.js` on how to do that)
450
451 ### aside
452
8837d0d5 »
2012-09-22 Documentation
453 Third brother of `then` and `end`. Has same signature but neither extends chain nor ends it, instead splits it by returning promise on which it was invoked. Useful when we want to return promise, but on a side (in parallel) do something else with obtained value:
64053aa5 »
2012-09-21 Update documentation for v0.6
454
455 ```javascript
456 var x = deferred({ foo: 'bar' });
457 var promise = deferred({ foo: 'bar' });
458
459 var y = promise.aside(function (value) {
460 console.log(value === x); // true
461 });
462 console.log(y === promise); // true
463 ```
464
465 ### cb
466
467 Convert back to callback style. Useful if you want to process regular callback at the end of promise chain. Simple use case would be regular asynchronous function built internally with promises. `cb` also makes sure that your callback is not called immediately but in next tick earliest.
468
469 With cb we may build hybrid functions that do both, handle asynchronous callback and return promise:
470
471 ```javascript
472 var asyncFunction = function (x, y, callback) {
473 deferred({ foo: x, bar: y }).cb(callback);
474 });
475 ```
22f05204 »
2011-07-07 Documentation
476
d5c80396 »
2012-01-08 Documentation for v0.3
477 ### get
22f05204 »
2011-07-07 Documentation
478
64053aa5 »
2012-09-21 Update documentation for v0.6
479 To directly get to object property use `get`
22f05204 »
2011-07-07 Documentation
480
0bfd1b8d »
2012-01-20 JavaScript code displayed with proper highlighting
481 ```javascript
482 var promise = deferred({ foo: 'bar' });
22f05204 »
2011-07-07 Documentation
483
0bfd1b8d »
2012-01-20 JavaScript code displayed with proper highlighting
484 promise(function (obj) {
485 console.log(obj.foo); // 'bar';
486 })
22f05204 »
2011-07-07 Documentation
487
0bfd1b8d »
2012-01-20 JavaScript code displayed with proper highlighting
488 promise.get('foo')(function (value) {
489 console.log(value); // 'bar'
490 });
491 ```
22f05204 »
2011-07-07 Documentation
492
64053aa5 »
2012-09-21 Update documentation for v0.6
493 You can get to nested properties as well:
a1a1853c »
2012-04-18 Updated README up to latest changes
494
495 ```javascript
496 var promise = deferred({ foo: { bar: 317 });
497
498 promise(function (obj) {
499 console.log(obj.foo.bar); // 317;
500 })
501
502 promise.get('foo', 'bar')(function (value) {
503 console.log(value); // 317
504 });
505 ```
506
507 ### invoke & invokeAsync
22f05204 »
2011-07-07 Documentation
508
64053aa5 »
2012-09-21 Update documentation for v0.6
509 Schedule function call on returned object
22f05204 »
2011-07-07 Documentation
510
0bfd1b8d »
2012-01-20 JavaScript code displayed with proper highlighting
511 ```javascript
512 var promise = deferred({ foo: function (arg) { return arg*arg; } });
22f05204 »
2011-07-07 Documentation
513
a1a1853c »
2012-04-18 Updated README up to latest changes
514 promise.invoke('foo', 3)(function (result) {
0bfd1b8d »
2012-01-20 JavaScript code displayed with proper highlighting
515 console.log(result); // 9
516 });
22f05204 »
2011-07-07 Documentation
517
a1a1853c »
2012-04-18 Updated README up to latest changes
518 // For asynchronous functions use invokeAsync
0bfd1b8d »
2012-01-20 JavaScript code displayed with proper highlighting
519 var promise = deferred({ foo: function (arg, callback) {
520 setTimeout(function () {
521 callback(null, arg*arg);
522 }, 100);
523 } });
22f05204 »
2011-07-07 Documentation
524
a1a1853c »
2012-04-18 Updated README up to latest changes
525 promise.invokeAsync('foo', 3)(function (result) {
0bfd1b8d »
2012-01-20 JavaScript code displayed with proper highlighting
526 console.log(result); // 9
527 });
528 ```
22f05204 »
2011-07-07 Documentation
529
d5c80396 »
2012-01-08 Documentation for v0.3
530 ### map
22f05204 »
2011-07-07 Documentation
531
64053aa5 »
2012-09-21 Update documentation for v0.6
532 See [promise aware version of Array's map](#map).
22f05204 »
2011-07-07 Documentation
533
d5c80396 »
2012-01-08 Documentation for v0.3
534 ### match
22f05204 »
2011-07-07 Documentation
535
d5c80396 »
2012-01-08 Documentation for v0.3
536 If promise expected value is a list that you want to match into function arguments then use `match`
22f05204 »
2011-07-07 Documentation
537
0bfd1b8d »
2012-01-20 JavaScript code displayed with proper highlighting
538 ```javascript
539 var promise = deferred([2, 3]);
22f05204 »
2011-07-07 Documentation
540
0bfd1b8d »
2012-01-20 JavaScript code displayed with proper highlighting
541 promise.match(function (a, b) {
542 console.log(a + b); // 5
543 });
544 ```
22f05204 »
2011-07-07 Documentation
545
d5c80396 »
2012-01-08 Documentation for v0.3
546 ### reduce
22f05204 »
2011-07-07 Documentation
547
64053aa5 »
2012-09-21 Update documentation for v0.6
548 See [promise aware version of Array's reduce](#reduce)
549
550 ### some
551
552 See [promise aware version of Array's some](#some)
553
8837d0d5 »
2012-09-22 Documentation
554 ## Debugging
555
556 ### Monitoring unresolved promises
557
558 In properly constructed flow, there should be no promises that are never resolved.
559 If you want to be sure that it's not the case, or you suspect there are such issues, check whether deferred's monitor has something to say
560
561 ```javascript
562 deferred.monitor();
563 ```
564
565 By default monitor will log error for every promise that was not resolved in 5 seconds.
d8eff9d8 »
2012-09-22 Documentation improvements
566 You can customize that timeout, and handle errors with your own listener:
8837d0d5 »
2012-09-22 Documentation
567
568 ```javascript
569 deferred.monitor(10000, function (err) {
570 // Called for each promise not resolved in 10 seconds time
571 });
572 ```
573
574 This extension affects performance and it's best not to use it in production environment
575
576 ### Usage statistics
577
578 Being able to see how many promises were initialized (and where) in our flow can be helpful to track application issues, it's also good way to confirm that constructed flow works as intended.
579
580 ```javascript
581 var profiler = deferred.profiler();
582 profiler.profile(); // Start collecting statistics
583
584 //...
585
586 var stats = profiler.profileEnd(); // End profiling
587 console.log(stats.log); // See readable output
588 ```
589
590 Example log output:
591
592 ```
593 ------------------------------------------------------------
594 Deferred/Promise usage statistics:
595
596 104540 Total promises initialized
597 104540 Initialized as Unresolved
598 0 Initialized as Resolved
599
600 Unresolved promises were initialized at:
601 22590 at Object.module.exports.factory (/Users/medikoo/Projects/_packages/next/lib/fs/_memoize-watcher.js:21:10)
602 11553 at Object.IsIgnored.init (/Users/medikoo/Projects/_packages/next/lib/fs/is-ignored.js:140:18)
603 11553 at module.exports.factory (/Users/medikoo/Projects/_packages/next/lib/fs/_memoize-watcher.js:21:10)
604 7854 at Object.Readdir.filterIgnored (/Users/medikoo/Projects/_packages/next/lib/fs/readdir.js:434:23)
605 4619 at Object.module.exports.factory (/Users/medikoo/Projects/_packages/next/lib/fs/_memoize-watcher.js:21:10)
606 3927 at Object.Readdir.filterByType (/Users/medikoo/Projects/_packages/next/lib/fs/readdir.js:222:15)
607 3927 at Object.Readdir.filterByType (/Users/medikoo/Projects/_packages/next/lib/fs/readdir.js:236:15)
608 3927 at Object.self (/Users/medikoo/Projects/_packages/next/lib/fs/readdir.js:164:12)
609 3927 at Object.Readdir.readdir (/Users/medikoo/Projects/_packages/next/lib/fs/readdir.js:540:9)
610 3927 at Object.self (/Users/medikoo/Projects/_packages/next/lib/fs/readdir.js:164:21)
611 3729 at directory (/Users/medikoo/Projects/_packages/next/lib/fs/_watch-alt.js:95:2)
612 2820 at Readdir.filterIgnored.promise.root (/Users/medikoo/Projects/_packages/next/lib/fs/readdir.js:517:9)
613 2163 at basic (/Users/medikoo/Projects/_packages/next/lib/fs/is-gitrepo-root.js:14:8)
614 2159 at buildMap (/Users/medikoo/Projects/_packages/next/lib/fs/is-ignored.js:117:22)
615 2159 at Object.FindRoot (/Users/medikoo/Projects/_packages/next/lib/fs/find-root.js:18:15)
616 1107 at Readdir.filterIgnored.promise.root (/Users/medikoo/Projects/_packages/next/lib/fs/readdir.js:527:11)
617 697 at Object.Map.addPaths (/Users/medikoo/Projects/_packages/next/lib/fs/_get-conf-file-map.js:107:19)
618 697 at readFile (/Users/medikoo/Projects/_packages/next/lib/fs/read-file.js:18:8)
619 697 at Object.readRulesWatch (/Users/medikoo/Projects/_packages/next/lib/fs/_get-conf-file-map.js:45:12)
620 247 at module.exports (/Users/medikoo/Projects/_packages/next/lib/fs/_watch.js:90:2)
621 247 at module.exports (/Users/medikoo/Projects/_packages/next/lib/fs/_watch.js:90:13)
622 1 at Object.Readdir.init (/Users/medikoo/Projects/_packa
623 ```
624
625 __Using profiler significantly affects performance don't use it in production environment.__
626
64053aa5 »
2012-09-21 Update documentation for v0.6
627 ## Performance
628
d8eff9d8 »
2012-09-22 Documentation improvements
629 Promises just by being rich objects introduce overhead over regular callbacks. If we do a lot asynchronous operations that are fast, performance of promise implementation that we rely on becomes a significant factor.
64053aa5 »
2012-09-21 Update documentation for v0.6
630
631 _benchmark_ folder contains few plain test cases that compares Deferred to other popular promise implementations. Base of test is plain [lstat](http://nodejs.org/api/all.html#all_fs_lstat_path_callback) call to self file.
632
faf8bea2 »
2012-09-22 Fix benchmarks.
633 _Example output taken under Node v0.8.9 on 2008 MBP._
64053aa5 »
2012-09-21 Update documentation for v0.6
634
635 ```
636 Promise overhead (calling one after another) x10000:
637
c969c294 »
2012-10-01 Added "when" implementation to benchmarks
638 1: 460ms Base (plain Node.js lstat call)
639 2: 644ms Deferred: Dedicated wrapper
640 3: 719ms Deferred: Promisify (generic wrapper)
641 4: 991ms jQuery.Deferred: Dedicated wrapper
642 5: 1171ms When: Dedicated wrapper
643 6: 3344ms Q: Dedicated wrapper
644 7: 7027ms Q: nbind (generic wrapper)
64053aa5 »
2012-09-21 Update documentation for v0.6
645
646 Promise overhead (concurrent calls) x10000:
647
c969c294 »
2012-10-01 Added "when" implementation to benchmarks
648 1: 303ms Base (plain Node.js lstat call)
649 2: 533ms Deferred: Dedicated wrapper
650 3: 607ms Deferred: Promisify (generic wrapper)
651 4: 712ms Deferred: Map + Promisify
652 5: 1074ms jQuery.Deferred: Dedicated wrapper
20fe2934 »
2012-10-01 -- uppercase
653 6: 1616ms When: Dedicated wrapper
c969c294 »
2012-10-01 Added "when" implementation to benchmarks
654 7: 2994ms Q: Dedicated wrapper
655 8: 5214ms Q: nbind (generic wrapper)
64053aa5 »
2012-09-21 Update documentation for v0.6
656 ```
22f05204 »
2011-07-07 Documentation
657
6ba4cb94 »
2012-05-28 Bring back Travis badge
658 ## Tests [![Build Status](https://secure.travis-ci.org/medikoo/deferred.png?branch=master)](https://secure.travis-ci.org/medikoo/deferred)
22f05204 »
2011-07-07 Documentation
659
64053aa5 »
2012-09-21 Update documentation for v0.6
660 __Covered by over 300 hundred unit tests__
22f05204 »
2011-07-07 Documentation
661
d5c80396 »
2012-01-08 Documentation for v0.3
662 $ npm test
Something went wrong with that request. Please try again.