以下是promise的简单实现
var Deferred = function () {
this.promise = new Promise();
};
var Promise = function () {
this.queue = [];
this.isPromise = true; //判断是否返回了一个promise对象
}
Promise.prototype.then = function (fulfilledHandler,errorHandler,progressHandler) {
var handler = {};
if(typeof fulfilledHandler === 'function'){
handler.fulfilled = fulfilledHandler;
}
if(typeof errorHandler === 'function'){
handler.error = errorHandler;
}
this.queue.push(handler);
return this;
}
//生成回调函数
Deferred.prototype.callback = function () {
var that = this;
return function (err,file) {
if(err){
return that.reject(err);
}
that.resolve(file);
}
}
Deferred.prototype.resolve = function (obj) {
var promise = this.promise;
var handler;
while(handler = promise.queue.shift()){
if(handler && handler.fulfilled){
var ret = handler.fulfilled(obj);
if(ret &&ret.isPromise){
ret.queue = promise.queue;
this.promise = ret;
return ret;
}
}
}
}
Deferred.prototype.reject = function (err) {
var promise = this.promise,handler;
while(handler = promise.queue.shift()){
if(handler && handler.error){
var ret = handler.error(err);
if(ret && ret.isPromise){
ret.queue = promise.queue;
this.promise = ret;
return ;
}
}
}
}
这里我们以两次文件读取为例子,以验证该设计的可行性。这里假设读取第二个文件是依赖于第一个文件中的内容的,相关代码如下:
var readFile1 = function (file,encoding) {
var deferred = new Deferred();
fs.readFile(file,encoding,deferred.callback());
return deferred.promise;
}
var readFile2 = function (file,encoding) {
var deferred = new Deferred();
fs.readFile(file,encoding,deferred.callback());
return deferred.promise;
}
readFile1('file1.txt','utf8').then(function (file1) {
return readFile2(file1.trim(),'utf8');
}).then(function (file2) {
console.log(file2);
});
要让Promise支持链式执行,主要通过以下两个步骤
(1)将所有的回调都存放在队列中
(2)Promise完成时,逐个执行回调,一旦检测到返回了新的Promise对象,停止执行,然后将当前
deferred对象的Promise引用改变为新的Promise对象,并将队列中余下的回调转交给它。
这里的代码主要用于研究Promise的执行原理,在更多细节的优化方面,Q或者when等Promise库做得更好,实际应用时请采用这些成熟库。
注意:Promise.prototype.then
的函数实现中return this;
才实现了链式调用,this指代的是当前promise实例。