Nodejs Chat Asynchronous

Source: Internet
Author: User
Tags generator iterable readfile

We all know that Nodejs is based on event callbacks to handle events, so we often have the question, for example, we will use DB or Redis or FS modules to store our information, when we need to return a real-time data and processing, asynchronous notification is not so humane, At this point we need to turn asynchrony into synchronization, and in the process we have several knowledge points to grasp, including the generartor function of the generator in JavaScript, with the yield keyword pause, thunk and promise use, And the Co module and frame thunkify are used together.

Builder Generartor

The generator function is written as: function* functionname () {}, which is essentially a function, so it has all the attributes of a normal function. In addition, it has the following useful features:

1. Executes the generator function to return a generator (generator), and the generator has a throw () method that can throw an exception manually, and is often used to determine whether it is a generator;

2. You can use yield (or yield*) inside the generator function to suspend execution when the function executes to yield and return the yield right value (the function context, such as the binding of the variable, will remain), and the next () method of the generator returns an object, Information that contains the value (Value property) of the right expression for the current yield, and whether the generator function has been executed (the Done property). Each time the next () method is executed, it is yield from the last execution place until the next yield is encountered and the object that contains the related execution information is paused, and then waits for the next next () execution;

3. The next () method of the builder returns an object that contains the yield right expression value and whether the completion information is executed, and the parameter in the next () method is the return value of the yield at the previous pause. var a = yield ... The value of the parameter is assigned to the A variable.

Example 1:

function test () {return
' B ';
}

function* func () {
var a = yield ' a ';

Console.log (' Gen: ', a);//gen:undefined 
var b = yield test (); 
Console.log (' Gen: ', b);//gen:undefined
} 

var func1 = func (); 
var a = Func1.next (); 
Console.log (' Next: ', a);/Next: {value: ' A ', done:false} 
var b = Func1.next (); 
Console.log (' Next: ', b);/Next: {value: ' B ', done:false} 
var c = Func1.next (); 
Console.log (' Next: ', c);/Next: {value:undefined, done:true}

According to article 3rd of the above, the implementation guidelines: "The Next () method of the builder returns an object that contains the yield right expression value and whether the completion information is executed, and the next () method's argument is the return value of the yield at the last pause, because we do not go to the generator's next () So: var a = yield ' a ', and the value of a is undefined.
Then we can modify the example slightly:

function test () {return
' B ';
}

function* func () {
var a = yield ' a ';
Console.log (' Gen: ', a);//Gen:1
var b = yield test ();
Console.log (' Gen: ', b);//Gen:2
}
var func2 = func ();
var a = Func2.next ();
Console.log (' Next: ', a);/Next: {value: ' A ', done:false}
var b = func2.next (1);
Console.log (' Next: ', b);/Next: {value: ' B ', done:false}
var c = func2.next (2);
Console.log (' Next: ', c);/Next: {value:undefined, done:true}

about yield

Common yield Examples:

function* outer () {
yield ' begin ';
Yield inner ();
Yield ' end ';
}
function* inner () {
yield ' inner ';
}
var it = outer (), V;
v = It.next (). value;
Console.log (v); -> output: Begin
v = it.next (). value;
Console.log (v); -> output: {}
Console.log (v.tostring ());//-> output: [Object Generator]
v = it.next (). value;
Console.log (v); -> Output: End

Agent Yield instance:

function* outer () {
yield ' begin ';
* * This line is equivalent to yield ' inner '; that's to replace the code inside the inner. At the same time, the RT is just the return value of inner
/var RT = yield* inner ();
Console.log (RT); -> output: Return to inner
yield ' end ';
}
function* inner () {
yield ' inner ';
Return ' return ' to inner ';
}
var it = outer (), V;
v = It.next (). value;
Console.log (v); -> output: Begin
v = it.next (). value;
Console.log (v); -> output: Inner
v = it.next (). value;
Console.log (v); -> Output: End

Based on the description of the document, Yield* takes a Iterable object as an argument and then iterates (iterate) the iterator (Iterable object), and the value of the expression yield* itself is the completion of the iterator iteration (done: True) returns the value. Invoking the Generator function returns a generator object itself, which is also a Iterable object, so we can use the yield* generator_function () notation.
Ah, well around. In my actual use, yield* is generally used to "execute" another generator function in a generator function and to obtain its return value.

about yield and co

Co (function* () {

//yield promise
var a = yield promise.resolve (1);
Console.log (a); -> output: 1

//yield thunk
var b = yield later (a);
Console.log (b); -> output: Ten

//yield generator function
var c = yield fn;
Console.log (c); -> output: fn_1

//Yield generator
var d = yield fn (5);
Console.log (d); -> output: fn_5

//yield array
var e = yield [
promise.resolve (' a '),
later (' B '),
FN,
fn (5)
];
Console.log (e);  -> output: [' A ', ' B ', ' fn_1 ', ' fn_5 ']

///Yield object
var f = yield {
' a ': promise.resolve (' a '),
' B ': Later (' B '),
' C ': FN,
' d ': FN (5)
};
Console.log (f); -> output: {A: ' A ', B: ' B ', C: ' Fn_1 ', D: ' Fn_5 '}

function* fn (n) {
n = n | | 1;
var a = yield later (n);
Return ' fn_ ' + A;
}

function later (n, t) {
t = t | 1000;
return function {
settimeout (function () {done (null, n);}, T);
};}}

). catch (function (e) {
console.error (e);
});

Through the above code, we see the fact that the CO module in the yield behind the only promise, generator, thunk functions, and he just synchronized, in the previous we discussed, if we want this code var a = Yield ' value ' A variable, then we need to pass in the parameter value when we call next, but in the Co module, he assigns the value of the Promise notification value (that is, resolve) and the thunk function to the A variable.

Promise Function

The Promise object is a specification proposed by the COMMONJS workgroup to provide a unified interface for asynchronous operations.
So, what is promises.
First, it is an object, that is, the use of other JavaScript objects, and second, it acts as an agent (proxy), acting as an intermediary between an asynchronous operation and a callback function. It enables the asynchronous operation to have the synchronization operation interface, causes the program to have the normal synchronization operation flow, the callback function does not have to be nested layer by layer.
Simply put, the idea is that each asynchronous task returns a Promise object immediately, and since it is returned immediately, the process of synchronizing can be used. This promises object has a then method that allows you to specify a callback function that is invoked after the asynchronous task completes.
For example, an asynchronous operation F1 returns a Promise object, and its callback function F2 as follows. (New Promise (F1)). then (F2);

Traditional notation
step1 (function (value1) {
  Step2 (value1, function (value2) {
    step3 (value2, function (value3) {
      STEP4 (Value3, function (value4) {
        //...
      }

);}); Promises (
new Promise (STEP1)). Then (STEP2). Then (STEP3)
  . Then (STEP4);

From the above code can be seen, using the promises interface, the program flow becomes very clear, very easy to read.
Note that for ease of understanding, the resulting format of the Promise object of the above code is simplified, and the real syntax is referred to below.
In general, the traditional callback function method makes the code mix together, becoming horizontal development rather than downward development. The promises specification is designed to address this problem, and the goal is to use the normal program flow (sync) to handle asynchronous operations. It first returns a Promise object, followed by the operation in a synchronized manner, sent to the object above. Wait until the asynchronous operation has a result, and then perform the other actions that were hosted on it earlier.
Promises was originally just a community proposed a concept, some external function library to achieve this function first. ECMAScript 6 writes it to the language standard, so the current JavaScript language natively supports promise objects.

With regard to the Promise interface, as mentioned earlier, the basic idea of the promise interface is that the asynchronous task returns a Promise object. He has only three states pending (unfinished), Resolved (completed), rejected (failed), then when it returns, only two concepts of success and failure, the execution of a successful Promise object returns a value, the state becomes resolved, the asynchronous operation fails, The Promise object throws an error and the state changes to rejected.

The Promise object uses the then method to add a callback function. The then method can accept two callback functions, the first of which is a callback function when the asynchronous operation succeeds (becomes a resolved state), and the second is the callback function (which can be omitted) when the asynchronous operation fails (becomes rejected). Once the state has changed, the corresponding callback function is invoked.

Po.then (Console.log, console.error);
In the code above, the Promise Object PO uses the then method to bind two callback functions: The callback function console.log when the operation succeeds, and the callback function Console.error (which can be omitted) when the operation fails. Both of these functions accept the value returned by the asynchronous operation as an argument. Of course, then can support chained programming.

In the code above, once the status of the PO becomes resolved, it calls each subsequent callback function specified in then, each step must wait until the previous step is completed before execution. The last then method's callback function is Console.log and console.error, with a little important difference in usage. Console.log displays only the return value of the callback function Step3, and console.error can display any error that occurs in Step1, Step2, or step3. That is, assuming that the Step1 operation fails and throws an error, then Step2 and Step3 are no longer performing (because they are the callback function that succeeds, not the callback function that failed the operation). The promises object starts looking for the next callback function when the first operation fails, which is console.error in the code above. This means that the error of the promises object is transitive.

ES6 provides a native promise constructor that is used to generate promise instances.

var promise = new Promise (function (resolve, reject) {
  //asynchronous operation's code
  if (/* Asynchronous operation succeeded/*) {
    resolve (value);
  } els e {
    reject (error);
  }
);
Here we may have a bit of a conflict with the then usage, but there's no, here's an AJAX match using the Promise usage:
function Search (term) {
  var url = ' http://example.com/search?q= ' + term;
  var xhr = new XMLHttpRequest ();
  var result;

  var p = new Promise (function (resolve, reject) {
    xhr.open (' Get ', url, true);
    Xhr.onload = function (e) {
      if (this.status = =) {Result
        = Json.parse (this.responsetext);
        Resolve (result);
      }
    ;
    Xhr.onerror = function (e) {
      reject (e);
    };
    Xhr.send ();
  });

  return p;
}

Search ("Paramvalue"). Then (Console.log, Console.error);

It's clear at this point ...

So we've said so much, and we want to promise with the Co module to use once, the asynchronous into a synchronization of the use of the method can be, the example is as follows:

var fs = require (' FS ');

var readFile = function (filename) {return
  new Promise (function (resolve, reject) {
    fs.readfile (filename, function (Error, data) {
      if (Error) reject (error);
      Resolve (data)

;});}; var Gen = function* () {
  var f1 = yield readFile ('/etc/fstab ');
  var F2 = yield readFile ('/etc/shells ');
  Console.log (F1.tostring ());
  Console.log (F2.tostring ());

Here, see, this cooperation with the Co module to achieve the synchronization of the operation of the bar

For more detailed explanations of promise, refer to http://javascript.ruanyifeng.com/advanced/promise.html official, http://www.ruanyifeng.com/blog/ 2015/05/co.html Ruan a peak this one of several points to note is that, first promise is an asynchronous pyramid management into then call, he will immediately return a state, when one of the successful execution, then to execute the next asynchronous callback function, please note that its three states , one of the API Promise.resolve (value), this API just immediately returns a value to return use.

thunk function

The CO module can automate the execution of our generators, we do not need to do next manually, but in the application of Co, in order to write asynchronous code in the same way as writing synchronous code, the more used method is to use the thunk function (but not the only way, it can be: Promise). For example, to read the contents of the file one step function Fs.readfile () method, converted to the Thunk function in the following way:

function ReadFile (path, encoding) {return
       function (CB) {
             fs.readfile (path, encoding, CB);
       }

The Thunk function has the following two elements:

1. A function with and only one parameter is callback;

2. The first parameter of the callback is error.

In fact, to look at these two points, the callback function in node can be written as a thunk function to execute. Using the Thunk function, together with the co we can write the asynchronous code in the same way as the write synchronization code, let's take an example to feel:

var co = require (' Co '),
fs = require (' FS '),
Promise = require (' es6-promise '). Promise;

function ReadFile (path, encoding) {return function
(CB) {//Thunk functions
fs.readfile (path, encoding, CB);
}

Co (function* () {//Outside is not visible, but in fact it has been converted into promise.then (). then (). The form of a chained call
var a = yield readFile (' a.txt ', {encoding: ' UTF8 '});
Console.log (a); A
var b = yield readFile (' b.txt ', {encoding: ' UTF8 '});
Console.log (b); b
var c = yield readFile (' c.txt ', {encoding: ' UTF8 '});
Console.log (c); C return
yield promise.resolve (a+b+c);
}). Then (function (val) {
console.log (val);//ABC
}). catch (function (error) {
console.log (error);
});
In fact, for each time to write a thunk function is still more troublesome, there is a framework thunkify can help us easily implemented, the revised code is as follows:
var co = require (' Co '),
    thunkify = require (' thunkify '),
    fs = require (' FS '),
    Promise = require (' es6-promise ' ). Promise;
 
var readFile = thunkify (fs.readfile);
 
Co (function* () {//Outside is not visible, but in fact it has been converted into promise.then (). then (). The form of a chained call
    var a = yield readFile (' a.txt ', {encoding: ' UTF8 '});
    Console.log (a); A
    var b = yield readFile (' b.txt ', {encoding: ' UTF8 '});
    Console.log (b); b
    var c = yield readFile (' c.txt ', {encoding: ' UTF8 '});
    Console.log (c); C return
    yield promise.resolve (a+b+c);
}). Then (function (val) {
    console.log (val);//ABC
}). catch (function (error) {
    console.log (error);
});

Distinguishing the use of thunkify, it can contain an asynchronous thunk function with a callback function that is provided to the Co module for use.

All right, let's get to the end. A summary in Nodejs asynchronous, first because the generator and yield can suspend the program, but do not have the ability to return the return value of the asynchronous function to var a variable, then we joined the Co module to use, Co can return the returned value of whatever callback after yield to the variable a, but there is a problem, yield if there are more than one or more asynchronous how to do, we use thunk and promise to execute all the asynchronous serial, and finally join the Co module, Perfect. Again, we recommend using thunk, because most of the time we need a return value for an asynchronous function, and there is a thunkify frame support, and promise is something else, for example, sometimes when you're taking the return value of it, it's not so easy. Then if you write a console.log, because the last value passed into the log, the log did not come out with the result, such as the code seems to be like this

var promise = new Promise (function (resolve, reject) {if
  (true) {
    //success, 2 as the return value, passed into the next then parameter, if there is no next then, Will eat the value of the village in the Promise._result
    resolve (2); 
  } else {
    reject (error);}
)
; var result = Promise._result;







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.