如何确保 $.each 推送 jQuery 中的所有延迟?
How to make sure $.each pushes all deferreds in jQuery?
我有以下 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;
});
}
我遇到的问题是 $.when.apply 在所有 deferreds 被推入 deferreds 数组之前执行。我怎样才能确保 $.when.apply 只有在所有 deferreds 被推入 deferreds 数组后才执行?
将 $.when.apply()
outside/after 移动到 .each()
循环中,这样您就可以在完成构建 deferreds
数组之前调用它。
不过你还有其他问题。我看起来你正试图 return 来自 $.when().done()
的值。当你的代码结构化时,那不会做任何事情。您将需要 return 来自您的函数的承诺,或者向您的函数添加一个回调,然后您可以在获得最终结果时调用该回调。这是因为您的操作是异步的,并且将在您的主要功能 returns.
之后很长时间内完成
您要做的主要事情是确保将承诺同步推送到数组中。 deferreds.push(...)
埋在 done 回调中,push()
是异步的,当执行 $.when.apply(...)
时数组保证仍然是空的。
其他一些问题也可以解决:
- 通过重新排列可以避免
ext.$classIns.prepare(obj)
周围的代码重复。
- 繁琐的外部 var
ret
可以通过利用 promise rejection 来避免。
通过其他一些小的整理,我得到了这个(未经测试):
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
});
}
评论应该解释发生了什么。
我有以下 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;
});
}
我遇到的问题是 $.when.apply 在所有 deferreds 被推入 deferreds 数组之前执行。我怎样才能确保 $.when.apply 只有在所有 deferreds 被推入 deferreds 数组后才执行?
将 $.when.apply()
outside/after 移动到 .each()
循环中,这样您就可以在完成构建 deferreds
数组之前调用它。
不过你还有其他问题。我看起来你正试图 return 来自 $.when().done()
的值。当你的代码结构化时,那不会做任何事情。您将需要 return 来自您的函数的承诺,或者向您的函数添加一个回调,然后您可以在获得最终结果时调用该回调。这是因为您的操作是异步的,并且将在您的主要功能 returns.
您要做的主要事情是确保将承诺同步推送到数组中。 deferreds.push(...)
埋在 done 回调中,push()
是异步的,当执行 $.when.apply(...)
时数组保证仍然是空的。
其他一些问题也可以解决:
- 通过重新排列可以避免
ext.$classIns.prepare(obj)
周围的代码重复。 - 繁琐的外部 var
ret
可以通过利用 promise rejection 来避免。
通过其他一些小的整理,我得到了这个(未经测试):
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
});
}
评论应该解释发生了什么。