[英]Refactor nested promises to a chain of promises
我已經簡化了這個問題。 我有 3 個函數,我想在每個函數之間運行 2 秒延遲。 以下代碼正在工作:
$.when(one()).done(function () {
$.when(delay(2000)).done(function () {
$.when(two()).done(function () {
$.when(delay(2000)).done(function () {
$.when(three()).done(function () {
console.log('finished');
});
});
});
});
});
function delay(ms) {
var waitForDelay = new $.Deferred();
setTimeout(function () {
waitForDelay.resolve().promise();
}, ms);
return waitForDelay.promise();
}
function one() {
console.log('one');
return new $.Deferred().resolve().promise();
}
function two() {
console.log('two');
return new $.Deferred().resolve().promise();
}
function three() {
console.log('three');
return new $.Deferred().resolve().promise();
}
但是,當我嘗試重構它時,它不再等待延遲的時間:
one().done(delay(2000)).done(two).done(delay(2000)).done(three).done(function () {
console.log('finished');
});
我如何重構以鏈接這些承諾而不是嵌套它們? 我想使用 jQuery 來實現舊版瀏覽器的兼容性。
我的建議是根本不要使用 jQuery 奇怪的類似Promise 的數據結構。
讓您的函數返回一個實際的Promise (顯式地或通過使它們成為異步函數)並await
鏈中的每個步驟。
const delay = (ms) => new Promise((res) => setTimeout(res, ms)); // an async function implicitly returns a promise const one = async () => { console.log("one"); } // or you can return one manually const two = () => { console.log("two"); return Promise.resolve(); } const three = async () => { console.log("three"); } // await each step in an async function (an async IIFE in this case) (async () => { await one(); await delay(2000); await two(); await delay(2000); await three(); console.log("finished"); })();
如果您喜歡這種風格,也可以使用.then()
// Convenience function so you don't repeat yourself
const waitTwoSeconds = () => delay(2000);
one()
.then(waitTwoSeconds)
.then(two)
.then(waitTwoSeconds)
.then(three)
.then(() => {
console.log("finished");
});
如果你必須使用 jQuery,它看起來並沒有太大的不同
function delay(ms) { var d = $.Deferred(); setTimeout(d.resolve, ms); return d.promise(); } function one() { console.log("one"); return $.Deferred().resolve().promise(); } function two() { console.log("two"); return $.Deferred().resolve().promise(); } function three() { console.log("three"); return $.Deferred().resolve().promise(); } function waitTwoSeconds() { return delay(2000); } one() .then(waitTwoSeconds) .then(two) .then(waitTwoSeconds) .then(three) .then(function() { console.log("finished"); });
<!-- Note jQuery 1.8 was the first to have chainable deferreds --> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
我使用了.then()
而不是.done()
,因為后者沒有鏈接並且在.then()
可用時使用$.when()
是不必要的。
從 Phil 的回答中汲取靈感,這里有一個與舊瀏覽器兼容的解決方案。
首先,將delay()
函數更改為返回一個函數:
function delay(ms) {
return function() {
var waitForDelay = new $.Deferred();
setTimeout(function () {
waitForDelay.resolve().promise();
}, ms);
return waitForDelay.promise();
}
}
所有其他功能與問題中的相同。
最后將.done()
替換為 .then( .then()
以使它們鏈接:
one().then(delay(2000)).then(two).then(delay(2000)).then(three).then(function () {
console.log('finished');
});
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.