2017-02-17 121 views
0

我已經完成了learnyounode這個練習,我試圖用ES2015的promise(或者如果更簡單的話與其他庫)重構它。我已閱讀了許諾,並且我想我理解他們的工作方式,但是我想知道是否可以在以下代碼中使用它們以及如何執行它。使用Promises而不是回調

我的目標是讓代碼更易於閱讀和理解,並更好地理解過程中的承諾。

let http = require("http"); 

if (process.argv.length != 5) { 
    throw new Error("Please provide the 3 URLs as a command line arguments"); 
} 

let urls = []; 
let results = []; 
let count = 0; 

for (let i = 2; i < process.argv.length; i++) { 
    urls.push(process.argv[i]); 
} 

function httpGet(index) { 
    let url = urls[index]; 
    let result = ""; 

    http.get(url, res => { 
     res.on("data", data => { 
      result += data; 
     }); 

     res.on('end',() => { 
      count += 1; 
      results[index] = result; 

      if (count === 3) { 
       results.forEach(function(result) { 
        console.log(result); 
       }); 
      } 
     }); 
    }); 

} 

for (let i = 0; i < urls.length; i++) { 
    httpGet(i); 
} 
+1

根據[文檔](https://nodejs.org/api/http.html#http_http_get_options_callback)'http.get'不返回承諾並僅支持回調方法。你將不得不自己創造和解決承諾。 – Cristy

+0

bluebirds如何對上面的代碼提供幫助?*答案:根本沒有* –

回答

2

你可以嘗試這樣的事:

'use strict'; 
 

 
const http = require('http'); 
 
if (process.argv.length != 5) { 
 
    throw new Error('Please provide the 3 URLs as a command line arguments'); 
 
} 
 

 
let urls = []; 
 
for (let i = 2; i < process.argv.length; i++) { 
 
    urls.push(process.argv[i]); 
 
} 
 

 
function httpGet(url) { 
 
    let result = ''; 
 
    return new Promise((resolve, reject) => { 
 
     http.get(url, function (res) { 
 
      res.on('error', err => { 
 
       reject(err); 
 
      }); 
 
      res.on('data', data => { 
 
       result += data; 
 
      }); 
 
      res.on('end',() => { 
 
       //You can do resolve(result) if you don't need the url. 
 
       resolve({url, result}); 
 
      }); 
 
     }) 
 
    }); 
 
} 
 

 
let promises = urls.map(url => httpGet(url)); 
 

 
Promise.all(promises) 
 
    .then(results => { 
 
     console.log(`All done. Results: ${results}`); 
 
    }) 
 
    .catch(err => { 
 
     console.error(err); 
 
    });

+0

謝謝,它完美的作品 – Noxxys

1

你可以做這樣的事情,但你應該知道,結果可能不會返回,在給定輸入的順序。

編輯:它現在將按給定的順序輸出數據。

const http = require('http'); 

if (process.argv.length != 5) 
    throw new Error("Please provide the 3 URLs as a command line arguments"); 

let urls = []; 
let results = []; 
let count = 0; 

for (let i = 2; i < process.argv.length; i++) 
    urls.push(process.argv[i]); 

function httpGet (url) 
{ 
    return new Promise((resolve, reject) => { 
     let result = ''; 
     http.get(url, res => { 
      res.on('data', data => result += data); 
      res.on('end',() => resolve(result)) 
     }).on('err', reject); 

    }); 
} 

function printResults() { 
    for (let result of results) { 
     console.log(result); 
    } 
} 

for (let i = 0; i < urls.length; i++) { 
    httpGet(urls[i]) 
     .then(result => { 
      results[i] = result; 
      if (++count === 3) 
       printResults(); 
     }) 
     .catch(err => console.log(err)); 
} 
+0

謝謝。它有效,但確實不會保留網址的順序。我可以通過將索引傳遞給'httpGet(index)'並將結果保存到'results [index]'中來保存順序,就像我以前一樣。 – Noxxys

+0

@Noxxys我想我忽略了將索引傳遞給函數的原因,我可能會更新答案以適應它。 –

+0

感謝您的編輯 – Noxxys

0

Node的核心庫接口不是基於promise的。但是,您可以使用一個簡單的函數將接受Node風格回調的函數轉換爲返回promise的函數。自己寫作可能是一個很好的練習。或者在npm上找到它。這種轉換功能通常被命名爲promisify。它的更高級版本需要一個對象並轉換其所有方法。

+3

有一刻需要考慮。 http.get不遵循錯誤優先約定。 'res'是第一個參數。因此,例如bluebird.promisify將無法正常工作。 –

1

雖然可以實現所有承諾邏輯自己的教育目的是有用的,但應注意的是,有與許HTTP請求良好的模塊支持,像request-promise

每月下載超過100萬次,它被廣泛使用,並且是針對此類任務的經過測試的解決方案。我總是建議使用經過測試的解決方案來完成任何真正的工作,而不是重新發明輪子。

現在,爲了教育目的另一方面,我總是建議儘可能多地重新發明儘可能多的輪子。例如看到這個答案基於回調的代碼轉換爲承諾的一些例子:

參見從這個回答所有鏈接:

你會發現許多使用回調和promise的相同代碼的例子,所以t您可以檢查差異。

+0

謝謝,我會閱讀這些鏈接並嘗試使用request-promise – Noxxys

相關問題