Browse files

Merge pull request #7 from thesmart/master

adding standard node callback support
  • Loading branch information...
2 parents c0eb7bc + 275381a commit 170bcfbc10b3a38dd849a1dae4a5040a182137be @kriszyp committed Dec 12, 2012
Showing with 102 additions and 33 deletions.
  1. +9 −9 README.md
  2. +13 −0 package.json
  3. +60 −22 promise.js
  4. +20 −2 test-promise.js
View
18 README.md
@@ -1,4 +1,3 @@
-
MIT License.
The node-promise project provides a complete promise implementation. Promises provide a clean separation
@@ -20,7 +19,8 @@ emitSuccess, and emitError should still behave as expected)
Utility functions, including:
* when() - Normalization of sync (normal values) and async (promises)
-* all() - Create a promise that accumulate multiple concurrent promises
+* all() - Create a promise that accumulate multiple concurrent promises (failed promises resolve to Error objects)
+* allOrNone() - Ditto, but the first promise to fail causes the composition to fail as well
* first() - Find the first promise to be fulfilled in a group of promises
* seq() - Sequentially execute a set of promise returning functions
* delay() - Returns a promise that is fulfilled after a given amount of time
@@ -30,18 +30,18 @@ promise (thank you Benjamin Thomas for providing this)
Much of this is adapted from Tyler Close's ref_send and Kris Kowal's work on promises.
Some quick examples from test-promise.js (again, it is recommended that you use http://github.com/kriszyp/promised-io for file and other I/O interaction):
- sys = require("sys");
+ util = require('util');
var fs = require('./fs-promise');
// open a file and read it
fs.open("fs-promise.js", process.O_RDONLY).then(function(fd){
return fs.read(fd, 4096);
}).then(function(args){
- sys.puts(args[0]); // print the contents of the file
+ util.puts(args[0]); // print the contents of the file
});
// does the same thing
- fs.readFile("fs-promise.js").addCallback(sys.puts);
+ fs.readFile("fs-promise.js").addCallback(util.puts);
A default Promise constructor can be used to create a self-resolving deferred/promise:
@@ -85,8 +85,8 @@ Another way that a consumer can use promises:
More examples:
function printFirstAndList(itemsDeferred){
- findFirst(itemsDeferred).then(sys.puts);
- findLast(itemsDeferred).then(sys.puts);
+ findFirst(itemsDeferred).then(util.puts);
+ findLast(itemsDeferred).then(util.puts);
}
function findFirst(itemsDeferred){
return itemsDeferred.then(function(items){
@@ -109,8 +109,8 @@ The workhorse function of this library is the "when" function, which provides a
var when = require("promise").when;
function printFirstAndLast(items){
// print the first and last item
- when(findFirst(items), sys.puts);
- when(findLast(items), sys.puts);
+ when(findFirst(items), util.puts);
+ when(findLast(items), util.puts);
}
function findFirst(items){
// return the first item
View
13 package.json
@@ -0,0 +1,13 @@
+{
+ "name": "node-promise",
+ "description": "Kris Zyp's implementation of promises with added features, maintained as an npm package.",
+ "version": "0.5.4",
+ "homepage": "https://github.com/MaxMotovilov/node-promise",
+ "files": [ "package.json", "promise.js", "fs-promise.js" ],
+ "main": "promise.js",
+ "repository": {
+ "type": "git",
+ "url": "https://MaxMotovilov@github.com/MaxMotovilov/node-promise.git"
+ }
+}
+
View
82 promise.js
@@ -1,5 +1,6 @@
// Kris Zyp
+// Updates/added features by ...Max... (Max Motovilov)
// this is based on the CommonJS spec for promises:
// http://wiki.commonjs.org/wiki/Promises
@@ -122,6 +123,20 @@ Promise.prototype.wait = function(){
return exports.wait(this);
};
+/**
+ * When promise is resolved or rejected, call a single callback in the style of Node callbacks
+ *
+ * @param {Function} nodeCallback The callback function (e.g. function(err, result))
+ * @param {*=} opt_scope Optional scope to set in the callback (default: null)
+ * @return {*}
+ */
+Promise.prototype.thenNode = function(nodeCallback, opt_scope) {
+ return this.then(
+ nodeCallback.bind(opt_scope ? opt_scope : null, null), // no err
+ nodeCallback.bind(opt_scope ? opt_scope : null) // err is first param
+ );
+};
+
Deferred.prototype = Promise.prototype;
// A deferred provides an API for creating and resolving a promise.
exports.Promise = exports.Deferred = exports.defer = defer;
@@ -403,28 +418,51 @@ exports.wait = function(target){
* @param array The array of promises
* @return the promise that is fulfilled when all the array is fulfilled, resolved to the array of results
*/
-exports.all = function(array){
- var deferred = new Deferred();
- if(!(array instanceof Array)){
- array = Array.prototype.slice.call(arguments);
- }
- var fulfilled = 0, length = array.length;
- var results = [];
- if (length === 0) deferred.resolve(results);
- else {
- array.forEach(function(promise, index){
- exports.when(promise, each, each);
- function each(value){
- results[index] = value;
- fulfilled++;
- if(fulfilled === length){
- deferred.resolve(results);
- }
- }
- });
- }
- return deferred.promise;
-};
+
+function composeAll(fail_on_error) {
+ return function(array) {
+ var deferred = new Deferred(),
+ once = true;
+
+ if( !(array instanceof Array) )
+ array = Array.prototype.slice.call(arguments);
+ else
+ array = array.slice();
+ var todo = array.reduce( function(count,p){ return count+(p&&p.then?1:0); }, 0 );
+ if( todo === 0 )
+ deferred.resolve(array);
+ else
+ array.forEach( function( p, i ) {
+ if( p && p.then )
+ exports.when( p, succeed, fail_on_error ? failOnce : succeed );
+
+ function succeed( v ) {
+ array[i] = v;
+ if( --todo === 0 )
+ deferred.resolve(array);
+ }
+ } );
+
+ function failOnce( err ) {
+ if( once ) {
+ array.forEach( function(p) {
+ if( p.then && p.cancel ) p.cancel();
+ } );
+ deferred.reject( err );
+ once = false;
+ }
+ }
+
+ return deferred.promise;
+ }
+}
+
+exports.all = composeAll(false);
+
+/**
+ * Variation of all() -- fails if any of the promises fail
+ */
+exports.allOrNone = composeAll(true);
/**
* Takes an array of promises and returns a promise that is fulfilled when the first
View
22 test-promise.js
@@ -2,11 +2,29 @@ sys = require("sys");
var fs = require('./fs-promise');
// open a file and read it
-fs.open("fs-promise.js", process.O_RDONLY).then(function(fd){
+fs.open("fs-promise.js", 'r').then(function(fd){
return fs.read(fd, 4096);
}).then(function(args){
sys.puts(args[0]);
});
// does the same thing
-fs.readFile("fs-promise.js").addCallback(sys.puts);
+fs.readFile("fs-promise.js").addCallback(sys.puts);
+
+// does the same thing
+fs.readFile("fs-promise.js").thenNode(function(err, result) {
+ if (err) {
+ console.error(err);
+ } else {
+ console.info('thenNode result success');
+ }
+});
+
+// forced error
+fs.readFile("foobar.js").thenNode(function(err, result) {
+ if (err) {
+ console.info('thenNode err success');
+ } else {
+ console.error('err should be passed');
+ }
+});

0 comments on commit 170bcfb

Please sign in to comment.