我想在不使用jQuery的情况下实现基本的Deferred对象。在这里,我将仅实现已完成和失败的回调,具有解析和拒绝功能。和将promise
方法与此功能相关联的课程。
我在纯js(编辑)中执行以下实现:
function Deferred() {
var d = {};
d.resolve = function() {
d.done(arguments);
}
d.reject = function() {
d.fail(arguments);
}
d.promise = function() {
var x = {};
x.done = function(args) {
return args;
}
x.fail = function(args) {
return args;
}
return x;
}
return d;
}
var v;
var setVal = function() {
var d = new Deferred();
setTimeout(function() {
v = 'a value';
d.resolve(this);
}, 5000);
return d.promise();
};
setVal().done(function() {
console.log('all done :' + v);
});
但上面给出了错误:Object #<Object> has no method 'fail'
我知道Deferred()
函数的返回对象'd'没有方法done()。如果我从Deferred()
返回d.promise,则无法解析并拒绝函数。
请指出我为实现Deferred对象的简单目标所犯的错误。
这是我正在做的小提琴:http://jsfiddle.net/SyEmK/14/
答案 0 :(得分:19)
function Deferred(){
this._done = [];
this._fail = [];
}
Deferred.prototype = {
execute: function(list, args){
var i = list.length;
// convert arguments to an array
// so they can be sent to the
// callbacks via the apply method
args = Array.prototype.slice.call(args);
while(i--) list[i].apply(null, args);
},
resolve: function(){
this.execute(this._done, arguments);
},
reject: function(){
this.execute(this._fail, arguments);
},
done: function(callback){
this._done.push(callback);
},
fail: function(callback){
this._fail.push(callback);
}
}
var v;
var setVal = function() {
var d = new Deferred();
setTimeout(function() {
v = 'a value';
d.resolve(this);
}, 5000);
return d;
};
setVal().done(function() {
console.log('all done :' + v);
});
答案 1 :(得分:1)
我认为在调用回调之后取消分配回调是很好的,以避免内存泄漏,并立即执行以后添加的回调。
function deferred() {
let thens = []
let catches = []
let status
let resolvedValue
let rejectedError
return {
resolve: value => {
status = 'resolved'
resolvedValue = value
thens.forEach(t => t(value))
thens = [] // Avoid memleaks.
},
reject: error => {
status = 'rejected'
rejectedError = error
catches.forEach(c => c(error))
catches = [] // Avoid memleaks.
},
then: cb => {
if (status === 'resolved') {
cb(resolvedValue)
} else {
thens.unshift(cb)
}
},
catch: cb => {
if (status === 'rejected') {
cb(rejectedError)
} else {
catches.unshift(cb)
}
},
}
}
const d = deferred()
setTimeout(() => {
d.resolve('good')
}, 1000)
// Will be called after 1s
d.then(value => console.log('#1 resolved!', value))
setTimeout(() => {
// Will be called after 3s and executed right away as it's already resolved
d.then(value => console.log('#2 resolved!', value))
}, 3000)