问题
I've completed this exercise from learnyounode and I'm trying to refactor it using ES2015's promises (or with other libraries if it's easier). I've read about promises and I think I understand how they work, but I'd like to know if it's possible to use them in the following code and how to do it.
My goal is to make the code easier to read and understand, and also better understand promises in the process.
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:
You could try something like this:
'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);
});
回答2:
While it may be useful to implement all of the promise logic yourself for educational purposes, it should be noted that there are good modules for HTTP requests with promise supports, like request-promise
:
- https://www.npmjs.com/package/request-promise
With over 1 million monthly downloads it is widely used and is a tested solution for this sort of tasks. And I always recommend using a good tested solution for any real work instead of reinventing the wheel.
Now, for educational purposes on the other hand I always recommend to reinvent as many wheels as you possibly can. For example see this answer for some examples of converting callback-based code to promises:
- Understanding when to use Events and when to use Callback
See also all links from this answer:
- using promises in node.js to create and compare two arrays
You will find a lot of examples of the same code using both callbacks and promises, so that you can examine the differences.
回答3:
You could do something like this, but you should be aware that the results might not be returned, in the order of the given inputs.
Edit: It will now output data in the order given.
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));
}
回答4:
The interfaces of Node's core libraries aren't promise-based. However, you can use a simple function to convert a function accepting a Node-style callback to a function returning a promise. Writing it yourself may be a good exercise. Or find it on npm. This converting function is usually named promisify
. A more advanced version of it takes an object and converts all its methods.
来源:https://stackoverflow.com/questions/42295368/use-promises-instead-of-callbacks