2016-07-09 74 views
0

因此,我正在圍繞API構建一個簡單的包裝來獲取特定實體的所有結果。 API方法一次最多隻能返回500個結果,但可以使用skip參數檢索所有結果,該參數可用於指定開始從哪個索引開始檢索結果。該API還有一個方法,可返回總共存在的結果數量。以正確的順序異步連接API響應

我花了一些時間在使用request軟件包進行對抗,試圖想出一種方法來按順序連接所有結果,然後執行一個回調函數,通過所有結果。

這是目前我的代碼:

Donedone.prototype.getAllActiveIssues = function(callback){ 
    var url = this.url; 
    request(url + `/issues/all_active.json?take=500`, function (error, response, body) { 
     if (!error && response.statusCode == 200) { 
      var data = JSON.parse(body); 
      var totalIssues = data.total_issues; 
      var issues = []; 
      for (let i=0; i < totalIssues; i+=500){ 
       request(url + `/issues/all_active.json?skip=${i}&take=500`, function (error, response, body){ 
        if (!error && response.statusCode == 200) { 
         console.log(JSON.parse(body).issues.length); 
         issues.concat(JSON.parse(body).issues); 
         console.log(issues); // returns [] on all occasions 
         //callback(issues); 
        } else{ 
         console.log("AGHR"); 
        } 
       }); 
      } 
     } else { 
      console.log("ERROR IN GET ALL ACTIVE ISSUES"); 
     } 
    }); 
}; 

所以我開始了與空數組,issues。我遍歷一個for循環,每次將i增加500,並將其作爲skip參數傳遞。正如你所看到的,我將記錄每個響應包含的主題issues變量之前包含多少個問題的長度。

的輸出,從總共869個結果是這樣的:

369 
[] 
500 
[] 

爲什麼我的問題變量空當我登錄它呢?顯然有結果與它連接。

更常見的問題:這種方法是我想要實現的最好方法嗎?我想,即使我的代碼確實起作用,異步性的本質意味着完全有可能將結果以錯誤的順序連接起來。

我應該只使用同步請求庫嗎?

回答

1

爲什麼當我註銷時我的問題變空了?顯然有 結果與它連接。

這裏的一個主要問題是.concat()返回一個新的數組。它不會將項目添加到現有陣列上。

你可以改變這一點:

issues.concat(JSON.parse(body).issues); 

這樣:

issues = issues.concat(JSON.parse(body).issues); 

,以確保您保留新的級聯陣列。這是一個非常常見的錯誤。


您還可能有順序問題數組中,因爲你正在運行一個for環路開始一大堆在同一時間和結果可能會或可能不會回到正確的順序到達的請求。您仍然會得到適當的問題總數,但它們可能沒有按要求的順序排列。我不知道這對你是否有問題。如果這是一個問題,我們也可以爲此提出解決方案。

一個更普遍的問題:這種方法是最好的方式去 我想實現什麼?我想,即使我的代碼確實有效,異步性的本質意味着完全有可能將 結果以錯誤的順序連接起來。

除了排序問題,也可以修復,這是一個合理的做事方式。我們必須知道更多關於您的API的知識,以瞭解這是否是使用API​​獲取結果的最有效方式。通常,您希望避免將N次重複的API調用發送到同一臺服務器,並且您希望進行一次API調用以獲取所有結果。

我應該只使用一個同步請求庫嗎?

絕對不是。 node.js需要學習如何進行異步編程。這對於大多數人來說是一個學習的步驟,但是如何從node.js獲得最佳性能並應該學習和使用。


下面就來收集用於同步和誤差傳播(這是在node.js的異步處理巨大的有用的)承諾,可靠的訂單全部結果的方式:關於

// promisify the request() function so it returns a promise 
// whose fulfilled value is the request result 
function requestP(url) { 
    return new Promise(function(resolve, reject) { 
     request(url, function(err, response, body) { 
      if (err || response.statusCode !== 200) { 
       reject({err: err, response: response}); 
      } else { 
       resolve({response: response, body: body}); 
      } 
     }); 
    }); 
} 

Donedone.prototype.getAllActiveIssues = function() { 
    var url = this.url; 
    return requestP(url + `/issues/all_active.json?take=500`).then(function(results) { 
     var data = JSON.parse(results.body); 
     var totalIssues = data.total_issues; 
     var promises = []; 
     for (let i = 0; i < totalIssues; i+= 500) { 
      promises.push(requestP(url + `/issues/all_active.json?skip=${i}&take=500`).then(function(results) { 
       return JSON.parse(results.body).issues;     
      })); 
     } 
     return Promise.all(promises).then(function(results) { 
      // results is an array of each chunk (which is itself an array) so we have an array of arrays 
      // now concat all results in order 
      return Array.prototype.concat.apply([], results); 
     }) 
    }); 
} 

xxx.getAllActiveIssues().then(function(issues) { 
    // process issues here 
}, function(err) { 
    // process error here 
}) 
+0

啊,我傻CONCAT。真正有趣的解決方案使用承諾!以前沒有用過它,會給它一個旋轉,謝謝。 – Jazcash

+1

@Jazcash - 是的,對於這個特定情況的承諾,一個非常好的事情是'Promise.all()'爲您收集結果,即使您並行運行請求也是如此。它還提供更好的錯誤處理。這將返回給調用者(通過返回的承諾),這是發生在請求循環中任何地方的錯誤。你的代碼沒有返回錯誤。 – jfriend00

相關問題