Use promises instead of callbacks

空扰寡人 提交于 2019-12-13 06:49:40

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!