Analyzes the callback and code design modes in Node. js asynchronous programming, and node. js design modes

Source: Internet
Author: User

Analyzes the callback and code design modes in Node. js asynchronous programming, and node. js design modes

The biggest selling point of NodeJS is the event mechanism and asynchronous IO, which is not transparent to developers. Developers need to write code in asynchronous mode to use this selling point, which has also been criticized by NodeJS opponents. However, asynchronous programming is indeed the biggest feature of node. js. It cannot be said that node. js has actually been learned without understanding asynchronous programming. This chapter introduces various knowledge related to asynchronous programming.

In code, the direct embodiment of asynchronous programming is callback. Asynchronous programming relies on callback, but it cannot be said that the program will be asynchronized after callback is used. First, we can look at the following code.

function heavyCompute(n, callback) { var count = 0,  i, j; for (i = n; i > 0; --i) {  for (j = n; j > 0; --j) {   count += 1;  } } callback(count);}heavyCompute(10000, function (count) { console.log(count);});console.log('hello');
100000000hello

As you can see, the callback function in the above Code is still executed before the subsequent code. JS itself runs in a single thread, and it is impossible to run other code when a piece of code is not finished yet. Therefore, there is no concept of asynchronous execution.

However, if a function is used to create another thread or process, and do something in parallel with the main JS thread, and notify the main JS thread after the process is completed, the situation is different. Let's take a look at the following code.

setTimeout(function () { console.log('world');}, 1000);console.log('hello');
helloworld


This time, we can see that the callback function is executed in subsequent code. As mentioned above, JS itself is single-threaded and cannot be executed asynchronously, therefore, we can think that the special functions provided by the runtime environment outside the JS specifications such as setTimeout are used to create a parallel thread and return immediately, so that the main JS process can then execute subsequent code, and then execute the callback function after receiving the notification from the parallel process. In addition to common setTimeout and setInterval functions, these functions also include asynchronous APIs such as fs. readFile provided by NodeJS.

In addition, we still return to the fact that JS is running in a single thread, which determines that JS cannot execute other code, including the callback function, before executing a piece of code. That is to say, even if the parallel thread completes the work, it notifies the main JS thread to execute the callback function. The callback function can be executed only when the main JS thread is idle. The following is an example.

function heavyCompute(n) { var count = 0,  i, j; for (i = n; i > 0; --i) {  for (j = n; j > 0; --j) {   count += 1;  } }}var t = new Date();setTimeout(function () { console.log(new Date() - t);}, 1000);heavyCompute(50000);
8520


As you can see, the callback function that should be called one second later is greatly delayed because the main JS thread is busy running other code.

Code Design Mode
Asynchronous programming has many unique code design patterns. To achieve the same function, the code written in synchronous mode and asynchronous mode is significantly different. The following describes some common modes.

Function return value
It is very common to use the output of one function as the input of another function. In the synchronous mode, the code is generally written as follows:

var output = fn1(fn2('input'));// Do something.

In asynchronous mode, because the function execution result is passed through the callback function instead of the return value, the code is generally written as follows:

fn2('input', function (output2) { fn1(output2, function (output1) {  // Do something. });});

As you can see, this method is a callback function with more than one callback function, so it is easy to write> shape code.

Traverse Arrays
When traversing an array, it is also common to use a function to process data members in sequence. If the function is executed synchronously, the following code is generally written:

var len = arr.length, i = 0;for (; i < len; ++i) { arr[i] = sync(arr[i]);}// All array items have processed.

If the function is executed asynchronously, the above Code cannot guarantee that all array members are processed after the loop ends. If the array members must be processed in serial mode, asynchronous code is generally written as follows:

(function next(i, len, callback) { if (i < len) {  async(arr[i], function (value) {   arr[i] = value;   next(i + 1, len, callback);  }); } else {  callback(); }}(0, arr.length, function () { // All array items have processed.}));

As you can see, the above Code is passed into the next array member and starts the next round of execution only after the asynchronous function is executed once and the execution result is returned. After all the array members are processed, call back to trigger subsequent code execution.

If the array members can be processed in parallel, but the subsequent code still needs to be executed after all array members are processed, the asynchronous code will be adjusted to the following form:

(function (i, len, count, callback) { for (; i < len; ++i) {  (function (i) {   async(arr[i], function (value) {    arr[i] = value;    if (++count === len) {     callback();    }   });  }(i)); }}(0, arr.length, 0, function () { // All array items have processed.}));

As you can see, compared with the version of asynchronous serial traversal, the above Code processes all array members in parallel, and uses counter variables to determine when all array members are processed.

Exception Handling
The exception capture and processing mechanism provided by JS itself-try... catch..., can only be used for Synchronous execution of code. The following is an example.

function sync(fn) { return fn();}try { sync(null); // Do something.} catch (err) { console.log('Error: %s', err.message);}
Error: object is not a function

As you can see, exceptions are always bubbling along the code execution path until the first try statement is captured. However, because asynchronous functions interrupt the code execution path, exceptions generated during and after the asynchronous function execution bubble to the position where the execution path is interrupted, if you have never encountered a try statement, it is thrown as a global exception. The following is an example.

function async(fn, callback) { // Code execution path breaks here. setTimeout(function () {  callback(fn()); }, 0);}try { async(null, function (data) {  // Do something. });} catch (err) { console.log('Error: %s', err.message);}
/home/user/test.js:4  callback(fn());     ^TypeError: object is not a function at null._onTimeout (/home/user/test.js:4:13) at Timer.listOnTimeout [as ontimeout] (timers.js:110:15)

Because the code execution path is interrupted, we need to capture the exception with the try statement before the exception bubbles to the breakpoint, and pass the caught exception through the callback function. So we can rebuild the above example as below.

function async(fn, callback) { // Code execution path breaks here. setTimeout(function () {  try {   callback(null, fn());  } catch (err) {   callback(err);  } }, 0);}async(null, function (err, data) { if (err) {  console.log('Error: %s', err.message); } else {  // Do something. }});
Error: object is not a function

We can see that the exception is captured again. In NodeJS, almost all asynchronous APIs are designed in the above way. The first parameter in the callback function is err. Therefore, when writing our own asynchronous functions, we can also handle exceptions in this way, consistent with the NodeJS design style.

With the exception handling method, we can then think about how we write code. Basically, our code is to do some things, then call a function, then do some things, and then call a function, so that the loop. If we are writing Synchronous Code, you only need to write a try statement at the code entry point to capture all the exceptions on the bubble. The example is as follows.

function main() { // Do something. syncA(); // Do something. syncB(); // Do something. syncC();}try { main();} catch (err) { // Deal with exception.}

However, if we write asynchronous code, it will be okay. Since every asynchronous function call interrupts the code execution path and can only pass exceptions through the callback function, we need to judge whether an exception occurs in each callback function, therefore, the following code is generated when only three asynchronous function calls are used.

function main(callback) { // Do something. asyncA(function (err, data) {  if (err) {   callback(err);  } else {   // Do something   asyncB(function (err, data) {    if (err) {     callback(err);    } else {     // Do something     asyncC(function (err, data) {      if (err) {       callback(err);      } else {       // Do something       callback(null);      }     });    }   });  } });}main(function (err) { if (err) {  // Deal with exception. }});

As you can see, the callback function has complicated the code, and the exception handling in asynchronous mode has increased the complexity of the Code.

Articles you may be interested in:
  • Asynchronous Concurrency Control in Nodejs crawler advanced tutorial
  • Nodejs implements the bigpipe asynchronous page loading scheme
  • In-depth analysis of node. js concurrent asynchronous callback Processing
  • Async asynchronous programming in node. js
  • Blocking and non-blocking calls of node. js callback Functions
  • Nodejs asynchronous callback's elegant Processing Method
  • Use Promise in NodeJS to encapsulate asynchronous Functions
  • Node. js asynchronous IO Performance

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.