簡體   English   中英

承諾和Q-使用forEach完成一系列功能

[英]Promises and Q - Completing a long series of functions with a forEach

對於如何最好地編寫此內容有些困惑-希望此說明清楚。

我有一個forEach函數,我在其中瀏覽了一些JS對象數據,並對每一項執行一個函數:

found.forEach(function(item) {
      processData(item['userID']);
});

在這個processData函數中,我正在使用MongoDB find()調用。

var processData = function(userIDSelected) {

    User.find( {_id: userIDSelected},
           {gender: 1, country:1}, function(req, foundUser) {
            processUserInfo(foundUser[0]['gender']);
    });
}

考慮到每個調用將依次運行processUserInfo ,因此我遇到的問題是如何等待forEach中的所有操作完成。

我已經看過使用Q庫和Q.all,但是那是行不通的。

是否有一個Q函數等待長鏈中的所有事情完成?

謝謝

Q.all

返回由包含每個承諾的實現值的數組實現的承諾,或者以與第一個被拒絕的承諾相同的拒絕原因被拒絕的承諾。

Q.allSettled

返回一個由承諾狀態快照數組實現的承諾,但僅在所有原始承諾都已解決(即變為已實現或被拒絕)之后才能實現。

因此,您需要做三件事:

  1. 修改processData以及可能的對MongoDB的調用,以便最終得到processData返回異步操作的承諾。 (抱歉,我不熟悉MongoDB。Alnitak說 ,對於現代版本,如果您不提供回調,則MongoDB會返回一個promise(很好!)。否則, 此問題及其答案可能有助於返回一個promise。基於回調的API。)

  2. 使用map而不是forEach來獲取結果承諾的數組。

  3. 在承諾數組上使用Q.allQ.allSettled

如果User.find沒有指定的回調時,會返回一個承諾,#1看起來這樣

var processData = function(userIDSelected) {

    return User.find(
           {_id: userIDSelected},
           {gender: 1, country:1}
    ).then(function(req, foundUser) { // <== Check these args with the MongoDB docs!
        return processUserInfo(foundUser[0]['gender']);
    });
};

如果沒有,您可以使用Q.defer自己Q.defer

var processData = function(userIDSelected) {
    var d = Q.defer();
    User.find(
           {_id: userIDSelected},
           {gender: 1, country:1},
           function(req, foundUser) {
        processUserInfo(foundUser[0]['gender']);
        d.resolve(/*...data could go here...*/); // You'd use d.reject() if there were an error
    });
    return d.promise;
};

然后是2和3的樣子:

Q.all(found.map(function(item) { // Or Q.allSettled
    return processData(item);
}))
.then(...)
.catch(...);

如果processData僅使用其第一個參數(忽略任何其他參數),則可以放棄中介函數:

Q.all(found.map(processData)) { // Or Q.allSettled
.then(...)
.catch(...);

...但processData忽略多余的args時,因為map會將其傳遞給三個(值,其索引和數組)。

您的編碼方式可以假定userID是MongoDB中的ObjectId

如果真是這樣,只要found的不為空,這將起作用,否則您的用戶將永遠等待服務器響應。

processData(
  // Retrieve an object 
  // {
  //   $in: [ObjectId, ObjectId, ...]
  // }
  // 
  found.reduce(
    function(query, user) {
      return query.$in.push(user.userID), query;
    },
    {$in: []}
  )
);

您可以$in 此處獲得有關$in運算符的更多信息。

暫無
暫無

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

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