114

I've tried to research on how exactly asynchronous functions should be written. After a lot of plowing through a lot of documentation, it's still unclear to me.

How do I write asynchronous functions for Node? How should I implement error event handling correctly?

Another way to ask my question would be this: How should I interpret the following function?

var async_function = function(val, callback){
    process.nextTick(function(){
        callback(val);
    });
};

Also, I found this question on SO ("How do I create a non-blocking asynchronous function in node.js?") interesting. I don't feel like it has been answered yet.

Community
  • 1
  • 1
Kriem
  • 8,666
  • 16
  • 72
  • 120
  • 14
    That's why I'm asking. It's not apparent to me how these functions are any different. – Kriem Aug 01 '11 at 13:26
  • I recommend you look at `setTimeout` and `setInterval` in your favourite browser and play around with them as well. Or ajax callbacks (probably the closest thing to the node experience), or event listeners for things you're familiar with like click and load events. The asynchronous model exists already in the browser, and they're exactly the same in node. – davin Aug 01 '11 at 13:33
  • @davin - Guess I don't fully comprehend the asynchronous model then. – Kriem Aug 01 '11 at 13:47
  • @Kriem, I answered something yesterday that might help: http://stackoverflow.com/questions/6883648/how-to-send-a-return-form-a-callback-function-to-the-main-function/ It's not an answer to your question, but it's on-topic. Try and read the question and answer there and play around with the code to try and understand what is going on. – davin Aug 01 '11 at 13:52
  • @davin - Thanks! Interesting read. The asynchronicity with its callback functions really has me baffled. – Kriem Aug 01 '11 at 13:58
  • 2
    @Raynos What is the definition of "asynchronous function"? – Anderson Green Oct 02 '12 at 17:10
  • I thought that anything that uses a socket (database, streams..) causes the function to be asynch, but I may be excluding other cases where the function behaves asynch'ly too – Purefan Oct 28 '13 at 21:29
  • https://howtonode.org/understanding-process-next-tick – Maciej Krawczyk Jun 11 '17 at 08:20
  • I see a lot of examples using setTimeout or setInterval, but I don't understand why they are used. Are they used to simulate something, as to provide some academic exercise to understand how asynchronous transactions work with no real or clear business use case, or are they fundamentally required for any asynchronous function regardless of business use case and/or requirements? – barrypicker Oct 23 '19 at 15:22

6 Answers6

86

You seem to be confusing asynchronous IO with asynchronous functions. node.js uses asynchronous non-blocking IO because non blocking IO is better. The best way to understand it is to go watch some videos by ryan dahl.

How do I write asynchronous functions for Node?

Just write normal functions, the only difference is that they are not executed immediately but passed around as callbacks.

How should I implement error event handling correctly

Generally API's give you a callback with an err as the first argument. For example

database.query('something', function(err, result) {
  if (err) handle(err);
  doSomething(result);
});

Is a common pattern.

Another common pattern is on('error'). For example

process.on('uncaughtException', function (err) {
  console.log('Caught exception: ' + err);
});

Edit:

var async_function = function(val, callback){
    process.nextTick(function(){
        callback(val);
    });
};

The above function when called as

async_function(42, function(val) {
  console.log(val)
});
console.log(43);

Will print 42 to the console asynchronously. In particular process.nextTick fires after the current eventloop callstack is empty. That call stack is empty after async_function and console.log(43) have run. So we print 43 followed by 42.

You should probably do some reading on the event loop.

Raynos
  • 166,823
  • 56
  • 351
  • 396
  • I've seen the Dahl vids, but I don't seem to get a grasp on the matter I'm afraid. :( – Kriem Aug 01 '11 at 13:47
  • 1
    @Kriem see updated answer and read [about the event loop](http://en.wikipedia.org/wiki/Event_loop) – Raynos Aug 01 '11 at 14:30
  • 1
    Thanks fort the insights. I'm now more aware of what I lack in knowledge. :) Your last example helped by the way. – Kriem Aug 01 '11 at 18:13
  • I think you're statement about asynchronous IO is "better" is too general. In this sense yes, but overall that may not be the case. – Jake B Dec 19 '14 at 16:37
  • In your first code example, you check the err argument, but didn't return afterward. In the case of an error, the code will continue and potentially cause serious problems in your application. – Gabriel McAdams Jan 05 '16 at 22:15
9

Just passing by callbacks is not enough. You have to use settimer for example, to make function async.

Examples: Not async functions:

function a() {
  var a = 0;    
  for(i=0; i<10000000; i++) {
    a++;
  };
  b();
};

function b() {
  var a = 0;    
  for(i=0; i<10000000; i++) {
    a++;
  };    
  c();
};

function c() {
  for(i=0; i<10000000; i++) {
  };
  console.log("async finished!");
};

a();
console.log("This should be good");

If you will run above example, This should be good, will have to wait untill those functions will finish to work.

Pseudo multithread (async) functions:

function a() {
  setTimeout ( function() {
    var a = 0;  
    for(i=0; i<10000000; i++) {
      a++;
    };
    b();
  }, 0);
};

function b() {
  setTimeout ( function() {
    var a = 0;  
    for(i=0; i<10000000; i++) {
      a++;
    };  
    c();
  }, 0);
};

function c() {
  setTimeout ( function() {
    for(i=0; i<10000000; i++) {
    };
    console.log("async finished!");
  }, 0);
};

a();
console.log("This should be good");

This one will be trully async. This should be good will be writen before async finished.

chharvey
  • 8,580
  • 9
  • 56
  • 95
Pikachu
  • 1,973
  • 3
  • 20
  • 27
5

You should watch this: Node Tuts episode 19 - Asynchronous Iteration Patterns

It should answers your questions.

NessDan
  • 1,137
  • 1
  • 16
  • 34
Cris-O
  • 4,989
  • 3
  • 17
  • 11
3

If you KNOW that a function returns a promise, i suggest using the new async/await features in JavaScript. It makes the syntax look synchronous but work asynchronously. When you add the async keyword to a function, it allows you to await promises in that scope:

async function ace() {
  var r = await new Promise((resolve, reject) => {
    resolve(true)
  });

  console.log(r); // true
}

if a function does not return a promise, i recommend wrapping it in a new promise that you define, then resolve the data that you want:

function ajax_call(url, method) {
  return new Promise((resolve, reject) => {
    fetch(url, { method })
    .then(resp => resp.json())
    .then(json => { resolve(json); })
  });
}

async function your_function() {
  var json = await ajax_call('www.api-example.com/some_data', 'GET');
  console.log(json); // { status: 200, data: ... }
}

Bottom line: leverage the power of Promises.

ryanwaite28
  • 1,804
  • 2
  • 24
  • 40
2

Try this, it works for both node and the browser.

isNode = (typeof exports !== 'undefined') &&
(typeof module !== 'undefined') &&
(typeof module.exports !== 'undefined') &&
(typeof navigator === 'undefined' || typeof navigator.appName === 'undefined') ? true : false,
asyncIt = (isNode ? function (func) {
  process.nextTick(function () {
    func();
  });
} : function (func) {
  setTimeout(func, 5);
});
hexacyanide
  • 88,222
  • 31
  • 159
  • 162
Pradeep
  • 117
  • 5
0

I've dealing too many hours for such task in for node.js. I'm mainly front-end guy.

I find this quite important, because all node methods asyncronous deal with callback, and transform it into Promise is better to handle it.

I Just want to show a possible outcome, more lean and readable. Using ECMA-6 with async you can write it like this.

 async function getNameFiles (dirname) {
  return new Promise((resolve, reject) => {
    fs.readdir(dirname, (err, filenames) => {
      err !== (undefined || null) ? reject(err) : resolve(filenames)
    })
  })
}

the (undefined || null) is for repl (read event print loop) scenarios, using undefined also work.

Yoarthur
  • 909
  • 9
  • 20