How to convert Waterfall method to promise

2019-06-14 20:12发布

问题:

Below is a code snippet using async-waterfall method. How can i convert this using promise.

async.waterfall([
    function(callback){
     User.update({username: user.username}, {$set: update_list}, function(err, a_user) {
      if (err) {
        err = new Error();
        err.code = 400;
        err.message = "Unexpected error occurred."
        callback(err)
      }
      if (!a_user) {
        err = new Error();
        err.code = 400;
        err.message = "User not found."
        callback(err)
      }else{
        callback(null, "updated", user_image);
      }
    })
   }, function(message, user_image, callback){
    if(user_image == undefined){
      callback(null, "done")
    }else{
      Bean.update({username: user.username, status:"Active"}, {$set: {user_image:user_image}},{multi:true},function(err, beanUpdated){
        if(err){
          err = new Error();
          err.code = 400;
          err.message = "Unexpected error occurred."
          callback(err)
        }else{
          callback(null, "done"); 
        }
      })
    }
  }
  ], function(err, result){
    if(err){
      return res.json({code:err.code, message:err.message})
    }else{
      return res.json({code:200, message:"Successfully updated profile."})
    }
  })

I usually use waterfall and series method of async module for synchronise my Node js code. Help me to switch from async to promise.

回答1:

I will not rewrite your code for you but I will provide you enough information so that you could do it yourself in 3 different styles with examples demonstrating the concepts. Rewriting your code will give you a good opportunity to get familiar with promises.

Instead of functions taking callbacks and composing them with async.waterfall you can use functions returning promises and return those promises from the then callbacks, to use the resolved values of those promises in the next then callback:

f1().then((a) => {
  return f2(a);
}).then((b) => {
  return f3(b);
}).then((c) => {
  // you can use c which is the resolved value
  // of the promise returned by the call to f3(b)
}).catch((err) => {
  // handle errors
});

Which in this simple example can be simplified to:

f1()
  .then(a => f2(a))
  .then(b => f3(b))
  .then((c) => {
    // use c here
  }).catch((err) => {
    // handle errors
  });

Or even this:

f1().then(f2).then(f3).then((c) => {
  // use c here
}).catch((err) => {
  // handle errors
});

Or you can very easily compose them together with async/await:

let a = await f1();
let b = await f2(a);
let c = await f3(b);
// ...

Or even this in this particular case:

let c = await f3(await f2(await f1()));

Here you handle errors with try/catch:

try {
  let c = await f3(await f2(await f1()));
  // use the c here
} catch (err) {
  // handle errors
}

Code using await has to be inside of a function declared with the async keyword but you can use it anywhere by wrapping in something like this:

// not async function - cannot use await here
(async () => {
  // this is async function - you can use await here
})();
// not async function again - cannot use await

The (async () => { ... })() expression itself returns a promise that is resolved to the return value of the async function or rejected with the exception thrown inside.

Note that in the above examples each function can easily depend on the value of a resolved promise returned by the previous function, i.e. the exact use case of async.waterfall but we're not using any library for that, only native features of the language.

The await syntax is available in Node v7.0+ with the harmony flag and v7.6+ without any flags. See:

  • http://node.green/#ES2017-features-async-functions

For more examples see this answer:

  • node.js ~ constructing chained sequence of Promise resolves

And for more background see the updates to this answer for more info:

  • jQuery: Return data after ajax call success