今天从GIT源码库中下载了promise.js,发现该源码是基于Web前端JavaScript写的,并不能直接用于nodejs。还好代码不是很多,也不是很复杂。经过分析整合,将其实现为nodejs的一个框架,代码如下:
(function(){/*** Copyright 2012-2013 (c) Pierre Duquesne <stackp@online.fr>* script: promise.js* description: promises的nodejs模块* modified: https://github.com/stackp/promisejs* authors: alwu007@sina.cn* */var Promise = exports.Promise = function(){this._callbacks = [];};Promise.prototype.then = function(func, context){//处理回调结果的方法function doCallbackResults(r) {if (r instanceof Promise) {r.then(function(err, values){p.done(err, values);});} else {p.done(null, r);}}var p = new Promise();if (this._isdone) {var results = func.apply(context, this.results);doCallbackResults(results);} else {this._callbacks.push(function(){var results = func.apply(context, arguments);doCallbackResults(results);});}return p;};Promise.prototype.done = function(){this.results = arguments;this._isdone = true;for (var i=0; i<this._callbacks.length; i++) {this._callbacks[i].apply(null, arguments);}this._callbacks = [];};Promise.join = function(promises){var p = new Promise();var results = [];if (!promises || !promises.length) {p.done(results);return p;}var numdone = 0;var total = promises.length;function notifier(i) {return function() {numdone += 1;results[i] = Array.prototype.slice.call(arguments);if (numdone === total) {p.done(results);}};}for (var i = 0; i < total; i++) {promises[i].then(notifier(i));}return p;};Promise.chain = function(funcs, args) {var p = new Promise();if (!funcs || !funcs.length) {p.done.apply(p, args);} else {funcs[0].apply(null, args).then(function(){funcs.splice(0, 1);Promise.chain(funcs, arguments).then(function(){p.done.apply(p, arguments);});});}return p;};})();另附测试代码如下:
/*** script: test.js* description: promise.js测试代码* */var promise = require("./mypromise");function asyncfoo() {var p = new promise.Promise();setTimeout(function(){p.done();}, 1000);return p;}function syncfoo() {var p = new promise.Promise();p.done();return p;}var o = {};/*asyncfoo().then(function(){return "Raymond";}, o).then(function(err, name){o.name = name;return asyncfoo().then(asyncfoo).then(function(){return asyncfoo().then(asyncfoo).then(function(){return 18;});});}, o).then(function(err, age){o.age = age;return asyncfoo().then(asyncfoo).then(function(){return asyncfoo().then(asyncfoo).then(function(){return "boy";});}).then(function(err, sex){return sex;});}).then(function(err, sex){o.sex = sex;return "Hello, world!";}).then(function(err, say){o.say = say;console.dir(o);});syncfoo().then(function(){return "Raymond";}, o).then(function(err, name){o.name = name;return syncfoo().then(syncfoo).then(function(){return syncfoo().then(syncfoo).then(function(){return 18;});});}, o).then(function(err, age){o.age = age;return asyncfoo().then(asyncfoo).then(function(){return asyncfoo().then(asyncfoo).then(function(){return "boy";});}).then(function(err, sex){return sex;});}).then(function(err, sex){o.sex = sex;return "Hello, world!";}).then(function(err, say){o.say = say;console.dir(o);});*/function asyncfoo1(){var p = new promise.Promise();setTimeout(function(){p.done(null, "Raymond");}, 1000);return p;}function asyncfoo2(err, name){o.name = name;var p = new promise.Promise();setTimeout(function(){p.done(null, 18);}, 1000);return p;}function asyncfoo3(err, age){o.age = age;var p = new promise.Promise();setTimeout(function(){p.done(null, "boy");}, 1000);return p;}function asyncfoo4(){var p = new promise.Promise();setTimeout(function(){p.done(null, "Hello, world!");}, 1000);return p;}promise.Promise.chain([asyncfoo1, asyncfoo2, asyncfoo3]).then(function(err, sex){o.sex = sex;return asyncfoo4();}).then(function(err, say){o.say = say;}).then(function(){console.dir(o);});