关于this jsFiddle,我试图动态添加在事件触发时创建的“延迟”,因此仅在解析所有延迟时调用完成的回调,包括稍后添加的那些:
相关代码:
var promises = [ deferred1, ... ];
var p = when.all(promises).then(function() {
console.log('All done!!');
//! trigger
});
promises.push( deferredFromEvent ); // << ignored
更新: 欢迎使用Q或jQuery的建议,我正在寻找一个有效的建议
答案 0 :(得分:1)
将固定的承诺视为一个单独的捆绑而不是动态承诺。
等待捆绑的promises,然后在最初为空的数组中通过$.when()
pipe结合它们的结果。您可以随时动态地将新的promises推送到此数组中。
http://jsfiddle.net/atesgoral/YVkVa/1/
HTML:
<p>You have 5 seconds to inject!</p>
<button id="inject">Inject Deferred 3</button>
<button id="resolve">Resolve Deferred 3</button>
<p>Deferred 1: <span id="dfd1">pending<span></p>
<p>Deferred 2: <span id="dfd2">pending<span></p>
<p>Deferred 3: <span id="dfd3">pending<span></p>
<h1 id="result"></h1>
JavaScript的:
var dfd1 = $.Deferred(),
dfd2 = $.Deferred(),
fixed = [ dfd1.promise(), dfd2.promise() ],
multiplexed = $.when.apply($, fixed), // Bundle the fixed ones
reservoir = []; // Reservoir for dynamic promises
// The solution to your problem lies here. The rest is scaffolding.
var ultimate = multiplexed.pipe(function () {
return $.when.apply($, reservoir);
});
ultimate.done(function() {
$("#result").text("Done!");
});
window.setTimeout(function () {
dfd1.resolve();
$("#dfd1").text("resolved");
}, 2500);
window.setTimeout(function () {
dfd2.resolve();
$("#dfd2").text("resolved");
}, 5000);
var dfd3 = $.Deferred();
$("#inject").click(function () {
reservoir.push(dfd3.promise());
});
$("#resolve").click(function () {
dfd3.resolve();
$("#dfd3").text("resolved");
});
答案 1 :(得分:0)
预先创建您知道自己需要的所有承诺。用它们构建.when
。保存从.when
返回的承诺。当您添加需要新承诺的新事件时,请使用之前.when
的承诺添加新的.when
,以及您已完成的任何新承诺。
如果您使用最终single points of failure
作为“继续使用该应用”,您的应用将有多个.when
。 IE:如果任何一个承诺在任何时候失败,那么之后创建的任何.when
也将失败。
...但是,如果这是你的意图,或者你有一些可靠的错误处理,那么你应该这样做。
我正在努力保持这个与库不相关的东西 - 通常,我使用自己的实现,这是jQuery所做的事情之间的中途,以及Crockford在最近的一次谈话中所做的事情,但是如果我们假设: / p>
函数返回promise-handlers
“when”返回一个promise-handler
promise-handlers至少有一个.done
和.fail
- 或者接受两个参数,或者其他什么
并且在函数内部发生的任何事情都将控制承诺是rejected/resolved
还是kept/broken
(或其他),然后你可能会得到一堆看起来像这样的功能:
var doing = doSomething(), // returns promise
making = makeSomething(), // returns promise
loading = loadSomething(), // returns promise
dependencies_lvl_1 = when(doing, making, loading);
稍后,您可能会添加一个新模块或小部件 - 可能会节省一些工作:
var saving = saveSomething(), //returns promise
dependencies_lvl_2 = when(dependencies_lvl_1, saving);
也许在那之后,你需要切换页面,但是你需要先将数据缓存
var caching = cacheData(), // returns promise
when(dependencies_lvl_2, caching)
.done(goToNextPage)
.fail(handleError);
如果你看一下,你知道一个事实,只要when
返回一个承诺,只有在保留所有承诺(并保留所有承诺)时才会成功,并且没有任何承诺破坏,那么dependencies_lvl_2
包括来自dependencies_lvl_1
的所有依赖项,以及其他承诺。
然后,等级3 .when
的分辨率取决于已添加到链中的每一件事物。
只要你将你的承诺缓存到变量(或某种未来访问)中,你就可以将它们连在一起,变成永恒。
答案 2 :(得分:0)
“......所以只有当所有延期解决时才会调用完成的回调,包括后来添加的那些”没有意义,但我想我知道你的意思。
如果我理解正确,那么你想要的是什么可能被称为“re-firable when()” - 类似这样的东西(基于jQuery):
function PromiseSet(memory, once) {//javascript Constructor
var flags = [];
if(memory) flags.push('memory');
if(once) flags.push('once');
var promises = [],
doneCallbacks = $.Callbacks(flags.join(' ')),
failCallbacks = $.Callbacks(flags.join(' '));
this.add = function(promise, val) {
promises.push(promise);
if(val) { this.fire(val); }
return this;
};
this.done = function(fn) {
doneCallbacks.add(fn);
return this;
};
this.fail = function(fn) {
failCallbacks.add(fn);
return this;
};
this.fire = function(val) {
val = val || null;
$.when.apply($, promises).then(
function() { doneCallbacks.fire(val); },
function() { failCallbacks.fire(val); }
);
return this;
};
return this;
}
未测试
所有方法都返回此选项以使其可链接。
如果我正确编写了构造函数,那么您可以通过将布尔值传递给new PromiseSet()
来控制其详细行为。对于您的建议用法,我认为您需要通过(true, false)
,但请尝试其他设置以查看会发生什么。
样本序列:
var myPromiseSet = new PromiseSet(true, false);
myPromiseSet.add(promise1);
myPromiseSet.add(promise2).add(promise3);
myPromiseSet.done(myDoneFunction).fail(myFailFunction);
myPromiseSet.fire("foo");
myPromiseSet.add(promise4).fire();
答案 3 :(得分:0)
看看这个解决方案。通过这种实现,您可以跟踪许多dinamic添加的承诺。如果您正在使用jQuery Deferred,您可以这样做。 jsFiddle
请注意,我已经使用了lodash库中的_.every方法,因此您还需要安装lodash
function doAlotOfAsyncThings(callback) {
var promises = [];
var def = $.Deferred();
console.log('Adding first promise');
promises.push(def.promise());
setTimeout(function() {
// Dinamically adding second promise. Important note: last added promise must be added to array BEFORE previous promise has been resolved
var def2 = $.Deferred();
var def3 = $.Deferred();
console.log('Dinamically adding second and third promises');
promises.push(def2.promise());
promises.push(def3.promise());
console.log('Resolving first promise');
def.resolve();
setTimeout(function() {
console.log('Resolving second and third promises');
def2.resolve();
def3.resolve();
}, 1500);
}, 1000);
function checkAllDone() {
console.log('Checking $.when');
$.when.apply(null, promises).then(function() {
// we have to check state of every promise in array
var all_resolved = _.every(promises, function(elem) { return elem.state() == 'resolved'; });
if(all_resolved) {
console.log('All promises are resolved! callback();')
callback();
} else {
console.log('Hm, seems that some promises were dinamically added, waiting for them..');
checkAllDone();
}
});
}
checkAllDone();
}
doAlotOfAsyncThings(function(){
console.log('Done');
});
Q.js甚至更短 在此解决方案中,我使用lodash库中的_.any方法
function doAlotOfAsyncThings(callback) {
var promises = [];
var def = Q.defer();
console.log('Adding first promise');
promises.push(def.promise);
setTimeout(function() {
// Dinamically adding second promise. Important note: last added promise must be added to array BEFORE previous promise has been resolved
var def2 = Q.defer();
var def3 = Q.defer();
console.log('Dinamically adding second and third promises');
promises.push(def2.promise);
promises.push(def3.promise);
console.log('Resolving first promise');
def.resolve();
setTimeout(function() {
console.log('Resolving second and third promises');
def2.resolve();
def3.resolve();
}, 1500);
}, 1000);
function checkAllDone() {
console.log('Checking $.when');
Q.all(promises).then(function() {
// Q remove resolved promises from array so we have to check if array contains some non-undefined elements (those elements would be non-resolved dinamically added promises)
if(_.any(promises)) {
console.log('Hm, seems that some promises were dinamically added, waiting for them..');
checkAllDone();
} else {
console.log('All promises are resolved! callback();')
callback();
}
});
}
checkAllDone();
}
doAlotOfAsyncThings(function(){
console.log('Done');
});