我有一个函数save
,可以多次调用并对我们的服务器进行AJAX调用。虽然该功能仍在保存,但我想在页面上显示一个指示符,该指示符将在所有保存请求完成后消失。我希望从save
返回的承诺在ALL请求完成后解析。我不能简单地使用Promise.all
,因为在所有保存请求完成之前可能会有更多请求进入。例如:
let pending_promises = [];
function addPromise(index, time = 5000) {
console.log('adding promise ' + index);
var promise = new Promise((resolve) => {
window.setTimeout(() => {
resolve();
}, time);
});
pending_promises.push(promise);
return promise
.then(() => {
console.log('done with promise ' + index);
return Promise.all(pending_promises);
})
.then(() => {
pending_promises = [];
});
}
addPromise(1, 5000).then(() => {
console.log('DONE WITH THEM ALL');
})
addPromise(2, 1000);
addPromise(3, 6000);
window.setTimeout(() => {
addPromise(4, 2000);
}, 5500);
这已经接近工作了,但是console.log说" DONE WITH THEM ALL"将在第4个承诺解决之前打印。任何人都可以提供一些帮助吗?
答案 0 :(得分:2)
你真的不需要保留一系列的承诺。相反,你可以跟踪尾巴的承诺。每当一个承诺结算,检查它是否仍然是尾巴。如果它仍然是尾巴,那么链条中没有更多的承诺,所以一切都完成了。这是编写代码的一种方法:
let promiseTail = Promise.resolve();
let opInFlight = false;
// simulated ajax call
function delay(t, v) {
return new Promise(function(resolve) {
setTimeout(resolve.bind(null, v), t);
});
}
function someAsyncCall(index, t) {
if (!opInFlight) {
console.log("----------------------------");
console.log("Starting chain of operations");
opInFlight = true;
// show spinner here
}
// insert your actual ajax call here
console.log('starting async operation ' + index);
let p = delay(t).then(function(result) {
console.log('done with async operation ' + index);
return result;
});
let thisPromise;
function complete() {
// if our promise was also the promiseTail,
// then everything that was in flight is now done
if (promiseTail === thisPromise) {
console.log("All done with chain of operations");
console.log("---------------------------------");
opInFlight = false;
// hide spinner here
}
return p;
}
// now hook this promise onto the chain
// and remember it's value locally so it can be compared later
thisPromise = promiseTail = promiseTail.then(complete, complete);
// return this specific promise so a caller can know when this specific
// async operation is done
return p;
}
// testing...
someAsyncCall(1, 5000);
someAsyncCall(2, 1000);
someAsyncCall(3, 6000);
someAsyncCall(4, 2000).then(function(result4) {
console.log("async operation 4 .then() handler called");
});
// now start one at little later to make sure it makes it into the chain too
setTimeout(function() {
someAsyncCall(5, 1000);
}, 2500);
// now start some after the above have all finished to see if another chain works
// and we can detect the second completion
setTimeout(function() {
someAsyncCall(10, 2000);
someAsyncCall(11, 1000);
}, 7000);
代码说明:
.then()
处理程序,每当我们看到.then()
火时,链的末端仍然是我们将我们添加到链中后的结果,然后链中一定没有其他东西,所以链现在是空的。我们通知链是空的,然后重置opInFlight
标志(这允许我们稍后检测我们何时开始新链)。注意:一个漂亮的干净设计会创建一个eventEmitter对象并发出几个事件:
然后,任何来电者都可以倾听他们最感兴趣的事件。
答案 1 :(得分:0)
如果之前通话的结果并不重要,那么您无需担心它们。
我对这种情况的伪代码(我经常遇到它)通常是这样的:
var myRequest;
function save() {
//it's important that you abort the previous ajax call
//before you show the spinner
if(myRequest) {
myRequest.abort();
}
showSpinner();
myRequest = //your ajax call
//hide the spinner regardless of the result of the request
myRequest.then(
function() { hideSpinner(); },
function() { hideSpinner(); }
);
//return the request
return myRequest;
};
save().then(function() { alert('done!'); })