2017-02-17 132 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

相关问题