最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Running code sequentially in Node.js - Stack Overflow

programmeradmin0浏览0评论

I have a function that fetches data from a database:

recentItems = function () {
  Items.find({item_published: true}).exec(function(err,item){
      if(!err)
        return item
  });
};

And I want to use it like this:

var x = recentItems();

But this fails with undefined value due to Async behavior of recentItems. I know that I can change my function to use a callback like this:

recentItems = function (callback) {
  Items.find({item_published: true}).exec(function(err,item){
      if(!err)
        callback(item)
  });
};

And:

recentItems(function(result){
  var x = result;
});

But i dont want to use this method because i have a situation like this. i have a function that should do two operations and pus result to an array and after them, fire a callback and return value:

var calc = function(callback){
   var arr = [];

   var b = getValues();
   arr.push(b);

   recentItems(function(result){
     var x = result;
     arr.push(x);
   });

   callback(arr);
};

In this situation, the value of b pushed to arr and the main callback called and after that value of x fetched from recentItems duo to Async behavior of recentItems. But I need this two operation runs sequentially and one after one. After calculating all of them, then last line runs and the callback fired.

How can I resolve this? I read about the Promises and Async libraries, but I don't know which of them is my answer. Can I overe this with raw Node.js? If so, I would prefer that.

I have a function that fetches data from a database:

recentItems = function () {
  Items.find({item_published: true}).exec(function(err,item){
      if(!err)
        return item
  });
};

And I want to use it like this:

var x = recentItems();

But this fails with undefined value due to Async behavior of recentItems. I know that I can change my function to use a callback like this:

recentItems = function (callback) {
  Items.find({item_published: true}).exec(function(err,item){
      if(!err)
        callback(item)
  });
};

And:

recentItems(function(result){
  var x = result;
});

But i dont want to use this method because i have a situation like this. i have a function that should do two operations and pus result to an array and after them, fire a callback and return value:

var calc = function(callback){
   var arr = [];

   var b = getValues();
   arr.push(b);

   recentItems(function(result){
     var x = result;
     arr.push(x);
   });

   callback(arr);
};

In this situation, the value of b pushed to arr and the main callback called and after that value of x fetched from recentItems duo to Async behavior of recentItems. But I need this two operation runs sequentially and one after one. After calculating all of them, then last line runs and the callback fired.

How can I resolve this? I read about the Promises and Async libraries, but I don't know which of them is my answer. Can I overe this with raw Node.js? If so, I would prefer that.

Share Improve this question edited Sep 21, 2015 at 3:38 New Dev 49.6k12 gold badges96 silver badges138 bronze badges asked Sep 21, 2015 at 3:24 FcoderFcoder 9,22618 gold badges68 silver badges103 bronze badges 13
  • 1 This is probably one of the most popular duplicate questions about node.js. Your operation is ASYNC. You cannot return the result from a synchronous function because the async results happens sometime in the future. If you want to chain multiple operations, then either nest your callbacks or use promises or use the async library. – jfriend00 Commented Sep 21, 2015 at 3:27
  • 1 I gave you three choices in my ment. FYI, promises are built into node.js so they are "raw node.js" now and highly remended. – jfriend00 Commented Sep 21, 2015 at 3:30
  • 1 @Fcoder: If you are new to async code then the proper way to overe it is to not overe it. You already know how to handle it so just do it. Once you have a bit more experience take a look at promises. Note that promises don't remove the need for callbacks, they just restructure your callbacks to remove nesting. So before learning about promises get fortable with regular callbacks first. – slebetman Commented Sep 21, 2015 at 3:34
  • 2 I don't agree with the duplicate flag, since NodeJS 4.0.0 is very new, and there are new ways of doing what the OP wants today. – Buzinas Commented Sep 21, 2015 at 3:38
  • 1 A bunch of questions with examples of sequencing async operations: stackoverflow./questions/32028552/…, stackoverflow./questions/29880715/…, stackoverflow./questions/29454785/async-js-and-series-issue/…, stackoverflow./a/29906506/816620 – jfriend00 Commented Sep 21, 2015 at 3:46
 |  Show 8 more ments

3 Answers 3

Reset to default 3

There are some ways of doing what you want, but none of them are ~perfect~ yet.

There is an ES7 proposal of native async/await that will be the callback heaven, but atm, you can do:

  • Nested callbacks (native, but very ugly and unmaintainable code)
  • Promises (good, but still too verbose)
  • Async/Await library (It's an amazing library, but very far from native, and performance isn't cool)
  • ES7 transpiler - you can write the ES7 code today, and it will transpile for you to ES5 (e.g Babel)

But, if you're already using the newest version of NodeJS (4.0.0 as the time of writing) - and if you're not, you really should - the best way of achieving what you want is to use generators.

Combined with a small library named co, it will help you to achieve almost what the ES7 async/await proposes, and it will mostly use native code, so both readability and performance are really good:

var co = require('co');

var calc = co(function *calc() {
  var arr = [];
  var b = getValues();
  arr.push(b);

  var items = yield recentItems();
  arr.push(items);

  return arr;
});

function recentItems() {
  return new Promise(function(resolve) {
    Items.find({item_published: true}).exec(function(err, item) {
      if(!err)
        resolve(item);
  });
}

You can read more about this subject in this awesome Thomas Hunter's blog post.

You've almost got it. There is no method to work-around callbacks. However, you can certainly use callbacks to do what you want. Simply nest them:

var calc = function(callback){
   var arr = [];

   getValues(function(b){
       arr.push(b);

       recentItems(function(result){
         var x = result;
         arr.push(x);

         callback(arr);
       });
   });
};

You can try something like this. It still nests the callbacks, but the code is a little cleaner.

var callA = function(callback) {
  //Run the first call
  prompt(callback(data));
}


var callB = function(callback) {
  //Some other call
  prompt(callback(data));
}

callA(function(dataA) {
  callB(function(dataB) {
    //Place a handler function here
    console.log(dataA + " " + dataB)
  })
});
发布评论

评论列表(0)

  1. 暂无评论