簡體   English   中英

將嵌套的 Promise 重構為 Promise 鏈

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM