我有以下jQuery代码:
myFunc: function(cmd, obj){
var idToExtMap = this. map;
var requireRes = this.reqInst;
var deferreds = [];
var ret = true;
$.each(idToExtMap[cmd], function(key, ext){
if(ext.$classIns && ext.$classIns.prepare) {
var returnedValue = ext.$classIns.prepare(obj);
deferreds.push(returnedValue);
$.when(returnedValue).done(function(satisfied){
if(ret!==false){
ret = satisfied;
}
});
} else {
requireRes(ext).done(function(){
var cls = $.toFunction(ext.$jscls);
if(cls) {
ext.$classIns = new cls();
if(ext.$classIns.prepare){
var returnedValue = ext.$classIns.prepare(obj);
deferreds.push(returnedValue);
$.when(returnedValue).done(function(satisfied){
if(ret!==false){
ret = satisfied;
}
});
}
}
});
}
});
$.when.apply(null, deferreds).done(function(){
return ret;
});
}
我遇到的问题是在将所有延迟推送到deferreds数组之前执行$ .when.apply。如何确保$ .when.apply仅在所有延迟被推入deferreds数组后执行?
答案 0 :(得分:1)
您要做的主要是确保将promises同步推送到数组。如果deferreds.push(...)
埋没在完成的回调中,则push()
是异步的,并且在执行$.when.apply(...)
时保证数组仍为空。
其他一些问题也可以解决:
ext.$classIns.prepare(obj)
周围的代码重复。ret
。通过其他一些小的整理,我最终得到了这个(未经测试):
myFunc: function(cmd, obj) {
var requireRes = this.reqInst;
var promises = $.map(this.map[cmd], function(key, ext) {
var p; // p for promise
if(ext.$classIns) {
p = $.when(ext.$classIns);
} else {
p = requireRes(ext).then(function() {
var cls = $.toFunction(ext.$jscls);
if(cls) {
ext.$classIns = new cls();
}
return ext.$classIns || null;
});
}
/* At this point, `p` is a promise resolved with either a previously created `cls()` object or a freshly created one */
// As we are inside `$.map(...)`, `return p.then(...)` causes the promise delivered by `p.then(...)` to be pushed onto the `promises` array.
return p.then(function($classIns) {
if($classIns && $classIns.prepare) {
return $classIns.prepare(obj).then(function(satisfied) {
if(!satisfied) {
// Here, returning a rejected promise is equivalent to setting the original `ret` irrevocably to `false`.
return $.Deferred().reject(new Error(".prepare() not satisfied"));
}
});
} else {
// You may want also to reject if `$classIns` or `$classIns.prepare` doesn't exist.
// If not, then delete this else{} clause.
return $.Deferred().reject(new Error(".prepare() could not be called"));
}
});
});
/* At this point, `promises` is an array of promises - some or all resolved, some or all pending */
// Here, instead of the boolean `ret`, you can exploit the joined promise's success/error paths :
// * success path is equivalent to ret == true.
// * error path is equivalent to ret == false, or any unpredicted error.
return $.when.apply(null, promises).then(function() {
// Success.
// Do whatever is necessary here or in `myFunc().then(function() {...})`.
}, function(e) {
// An error occurred.
// Do whatever is necessary here or in `myFunc().then(null, function() {...})`.
console.error(e); //for example
});
}
评论应该解释发生了什么。
答案 1 :(得分:0)
在$.when.apply()
循环之后移动.each()
,以便在您构建deferreds
数组之后不要调用它。
但你还有其他问题。我看起来像是在尝试从$.when().done()
返回一个值。由于您的代码结构合理,因此无法执行任何操作。您需要从函数返回一个promise或者为函数添加一个回调函数,然后在得到最终结果时调用它。这是因为您的操作是异步的,并且在主函数返回后很长时间才会完成。