简体   繁体   中英

Promise Chaining in Node.js

My promise-then chain does not appear to wait for each previous return statement.

new Promise(function (resolve, reject) {
    console.log("1");
    const http = require('http');
    http.get(url, (resp) => {
        let data = '';
        resp.on('data', (chunk) => {
            data += chunk;
        });
        resp.on('end', () => {
            var info;
            // process data
            resolve(info);
        });

    }).on("error", (err) => {
        console.log("Error: " + err.message);
    });

}).then(function (info) { 
    console.log("2");
    if (info.item) {
        console.log("item exists, don't retry");
        return (info);
    }
    const http = require('http');
    http.get(url, (resp) => {
        let data = '';
        resp.on('data', (chunk) => {
            data += chunk;
        });
        resp.on('end', () => {
            var info;
            // process data
            return(info);
        });

    }).on("error", (err) => {
        console.log("Error: " + err.message);
    });
}).then(function (info) { 
    console.log("3");
    const http = require('http');
    http.get('otherurl' + info.item, (resp) => {
        let data = '';
        resp.on('data', (chunk) => {
            data += chunk;
        });
        resp.on('end', () => {
            console.log("processed");
            return (info);
        });

    }).on("error", (err) => {
        console.log("Error: " + err.message);
    });

}).then(function (info) {
    console.log("4 " + info);
});

I want my output to be, eg.:

1
2
3
processed
4 [someinfo]

Here is what I get:

1
2
3
4 undefined
processed

It appears that only the first promise-then happen asynchronously. Why aren't the second and third then statements waiting for the prior return?

The code currently is:

new Promise(function (resolve, reject) {
    console.log("1");
    return(http.ClientRequest)

}).then(function (info) { 
    console.log("2");

    return(http.ClientRequest)

}).then(function (info) { 
    console.log("3");
    resolve(http.ClientRequest)

}).then(function (info) {
    console.log("4 " + info);
});

To work a Promise chain needs to return a promise from the then part. But anything you return from then is treated as promise. But in your case

  1. You are not returning anything.
  2. If you are returning, it is from the callback, so basically it doesn't go out of the function. if you do return http.get(...) you will get http.ClientRequest object in your next then chain. Not the actual data.

So in your case a crude way to do this will be: Promisifying each http call.

new Promise(function (resolve, reject) {
    console.log("1");
    const http = require('http');
    http.get(url, (resp) => {
        let data = '';
        resp.on('data', (chunk) => {
            data += chunk;
        });
        resp.on('end', () => {
            var info;
            // process data
            resolve(info);
        });

    }).on("error", (err) => {
        console.log("Error: " + err.message);
    });

}).then(function (info) {
    console.log("2");
    if (info.item) {
        console.log("item exists, don't retry");
        return (info);
    }
    return new Promise(function (resolve, reject) {
        const http = require('http');
        http.get(url, (resp) => {
            let data = '';
            resp.on('data', (chunk) => {
                data += chunk;
            });
            resp.on('end', () => {
                var info;
                // process data
                resolve(info);
            });

        }).on("error", (err) => {
            console.log("Error: " + err.message);
        });
    })

}).then(function (info) {
    console.log("3");
    return new Promise(function (resolve, reject) {
        const http = require('http');
        http.get('otherurl' + info.item, (resp) => {
            let data = '';
            resp.on('data', (chunk) => {
                data += chunk;
            });
            resp.on('end', () => {
                console.log("processed");
                resolve(info);
            });

        }).on("error", (err) => {
            console.log("Error: " + err.message);
        });
    })

}).then(function (info) {
    console.log("4 " + info);
});

Note: As I said it is a very non-elegant way of doing things, I would suggest using a promise based library like axios or maybe use async library instead of promises. Also you can use async-await . Each of them are better approach.

You are only resolving your first promise. When you return a value inside a callback you are not resolving the promise. You need to use the same strategy you use for the first one, wrapping the callback on a promise. So in your steps 2 and 3 you should return a new Promise and resolve it in the callback.

(...)
  .then(function(result){

    return new Promise(function(resolve, reject){

      someThingWithCallback(result, function(err, data){
        resolve(data)
      })
    })
  })
  .then(function(data){
    ...
  })

You should try to avoid using a module that uses callbacks if you want to work with promises. You can use something like request-promise or axios.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM