簡體   English   中英

我如何將許諾組合在一起?

[英]How can I chain together groups of promises?

我正在使用Q javascript Promise庫,並且正在瀏覽器中運行,並且我想弄清楚如何將Promise組鏈接在一起,以便每個組依次執行。 例如,如果我有項目A,B,C和D,我想將A和B分組在一起,然后將C和D分組在一起,以便A和B在執行C和D之前都必須滿足。 我創建了這個簡單的jsfiddle以顯示我當前的嘗試。

var work_items = [ 'A','B','C','D','E','F','G','H','I' ];
var n = 2;    // group size
var wait = 1000;

var getWorkPromiseFn = function (item) {
    log("Getting promise function for " + item);
    return function () {
        log("Starting " + item);
        var deferred = Q.defer();
        setTimeout(function () {
            var status = "Finished " + item;
            log(status);
            deferred.resolve(status);             
        }, wait);
        return deferred.promise;
    };
};

var queue = Q();

//log('Getting sequentially');    // One-by-one in sequence works fine
//work_items.forEach(function (item) {
//    queue = queue.then(getWorkPromiseFn(item));
//});

log('Getting ' + n + ' at a time'); // This section does not        
while (work_items.length > 0) {
    var unit = [];
    for (var i=0; i<n; i++) {
        var item = work_items.shift();
        if (item) {
            unit.push(getWorkPromiseFn(item));               
        }
    }
    queue.then(Q.all(unit));
}
var inspect = queue.inspect(); // already fulfilled, though no work is done

看來我可能在這里將錯誤的數組傳遞給Q.all ,因為我傳遞的是一個數組,這些函數返回的是promise,而不是promise的數組。 當我嘗試直接在其中使用promise(例如,使用unit.push(Q().then(getWorkPromiseFn(item)); ))時,每個承諾的工作都立即開始,並且沒有順序處理。我想我基本上是不清楚以一種適當的方式來延遲組的執行來代表組。

那么,我該如何推遲執行這樣的一組諾言呢?

這可以通過以下方式完成:首先將項目數組進行預處理,然后應用標題為“ The Collection Kerfuffle”下此處提供的兩種模式(非反模式)。

主例程可以編碼為數組方法的單鏈。

var work_items = [ 'A','B','C','D','E','F','G','H','I' ];
var wait = 3000;

//Async worker function
function getWorkPromise(item) {
    console.log("Starting " + item);
    var deferred = Q.defer();
    setTimeout(function () {
        var status = "Finished " + item;
        console.log(status);
        deferred.resolve(status);             
    }, wait);
    return deferred.promise;
};

function doAsyncStuffInGroups(arr, n) {
    /* 
     * Process original array into groups, then 
     * process the groups in series, 
     * progressing to the next group 
     * only after performing something asynchronous 
     * on all group members in parallel.
     */
    return arr.map(function(currentValue, i) {
        return (i % n === 0) ? arr.slice(i, i+n) : null;
    }).filter(function(item) {
        return item;
    }).reduce(function(promise, group) {
        return promise.then(function() {
            return Q.all(group.map(function(item) {
                return getWorkPromise(item);
            }));
        });
    }, Q());
}

doAsyncStuffInGroups(work_items, 2).then(function() {
    console.log("All done");
});

小提琴 延遲3秒讓您有時間去了解發生了什么。 我發現1太快了。

像這樣的解決方案優雅簡潔,但是非常難以理解。 在生產代碼中,我將提供更多注釋,以幫助任何關注我的人。

作為記錄:

  • 開頭的arr.map(...).filter(...)arr (非破壞性地)處理為一個數組數組,每個內部數組代表一組長度為n的組(加上終端余數)。
  • 鏈接的.reduce(...)是異步的“序列化器”模式。
  • 嵌套的Q.all(group.map(...))是異步的“並行器”模式。

promise的.then函數不會使promise發生變化,所以當您這樣做時:

 p.then(function(){
         // stuff
 });

您根本不需要更改承諾p ,而是需要將其分配給某些東西:

p = p.then(....)

這就是為什么您的queue承諾始終得到解決的原因,它從未改變過Q()

就您而言,類似更改:

queue.then(Q.all(unit));

進入:

queue = queue.then(function(){ return Q.all(unit); });

或者在ES6的Promise和使用Bluebird之類語法的庫中,提到了另一個答案:

queue = queue.then(function(){ return Promise.all(unit); });

最讓我困惑的是,被鏈接的異步函數需要返回一個返回承諾的函數。 這是一個例子:

function setTimeoutPromise(ms) {
  return new Promise(function (resolve) {
    setTimeout(resolve, ms);
  });
}

function foo(item, ms) {
  return function() {
    return setTimeoutPromise(ms).then(function () {
      console.log(item);
    });
  };
}

var items = ['one', 'two', 'three'];

function bar() {
  var chain = Promise.resolve();
  for (var i in items) {
    chain = chain.then(foo(items[i], (items.length - i)*1000));
  }
  return chain.then();
}

bar().then(function () {
  console.log('done');
});

注意,foo返回一個返回promise的函數 FOO() 直接返回一個承諾。

觀看此現場演示

我建議您使用bluebird,它是目前性能最好的承諾, https://github.com/petkaantonov/bluebird

鏈接示例也應該在這里https://github.com/petkaantonov/bluebird#how-do-long-stack-traces-differ-from-eg-q

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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