Write this question is because recently saw some beginners with call back the exhilaration, the last code left to tune to again very not intuitive.
The first conclusion: the recommended use of async/await or Co/yield, followed by promise, again is the event, callback do not use.
The next is to parse, why I have this conclusion
The first is the callback, the simplest thing to understand is that I assign the task, and when you are done I can get the result from you and execute the corresponding callback.
Here is a package for settimeout that prints the results after a specified time and executes the callback function
And this function passed the parameter to the callback function according to the node standard, the first is the error information, if error is not NULL, normal execution is null
vari = 0;functionSleep (MS, callback) {SetTimeout (function() {Console.log (' I'm done! ‘); I++; if(I >= 2) callback (NewError (' I is greater than 2 '),NULL); ElseCallbackNULL, i); }, MS);} Sleep (3000,function(err,val) {if(err) Console.log (' ERROR: ' +err.message); ElseConsole.log (val);})//execution Result: 3s after printing "I'm Done", "1"
This kind of code doesn't look uncomfortable, and it's better understood, but what if I had to pause it a lot?
The code that is called becomes the following:
Sleep (function (err, Val) { Span style= "COLOR: #0000ff" >if (Err) return Console.log (err.message); Console.log (Val); Sleep ( function (err, Val) { if (Err) return Console.log (Err.message); Console.log (Val); Sleep ( function (err, Val) {if (err) Console.log (err.message); else Console.log (Val); }) })})
Can be seen, nested deep, you can think of these three operations as three asynchronous tasks, and it is possible to continue nesting, this is clearly anti-human.
Deep nesting first an ugly look very uncomfortable, the second if the callback function error, it is difficult to determine where the error.
The improved method is the event listener, which returns an Eventemitter object each time an asynchronous function is invoked, and invokes the done event when execution succeeds.
Calling the error event upon failure
vari = 0;functionSleep (ms) {varEmitter =NewRequire (' Events ')(); SetTimeout (function() {Console.log (' I'm done! ‘); I++; if(I >= 2) emitter.emit (' Error ',NewError (' I is greater than 2 '))); ElseEmitter.emit (' Done ', i); }, MS);}varemit = Sleep (3000); Emit.on (' Done ',function(val) {Console.log (' Success: ' +val);}) Emit.on (' Error ',function(Err) {Console.log (' Something went wrong: ' +err.message);})
The advantage of writing this way is that you can add multiple callback functions, each of which can get the value and operate accordingly. But this does not solve the problem of callback nesting,
For example, the function of multiple calls or must be written in the Ondone callback function, it seems to be very inconvenient.
So the more common solution is promise.
Promise is similar to an event, you can think of it as an event object that only triggers two events, but the event is instantaneous and the state does not exist after it is triggered.
The event has already been triggered, you can no longer get the value, and promise different, promise only two states resolve and reject, when it triggers any state
It caches the current value and attempts to invoke the callback function when a callback function is added, and if the resolve or reject is not triggered at this time, then
The callback function is cached, waits for the call, and if it already has a state (resolve or reject), call the callback function immediately. And all the callback functions are executed immediately after execution.
Be destroyed.
The code is as follows:
vari = 0;//function returns promisefunctionSleep (ms) {return NewPromise (function(Resolve, Reject) {SetTimeout (function() {Console.log (' I've done it. '); I++; if(I >= 2) reject (NewError (' i>=2 ')); ElseResolve (i); }, MS); })}sleep (). Then (function(val) {Console.log (val); returnSleep (1000)}). Then (function(val) {Console.log (val); returnSleep (1000)}). Then (function(val) {Console.log (val); returnSleep (1000)}).Catch(function(Err) {Console.log (' ERROR: ' +err.message);})
In this example, first it expands the originally nested callback function and now looks more comfortable, and because of the bubbling nature of the promise, when any of the promise chains
Function error will be thrown directly to the bottom of the chain, so we uniformly used a catch to capture, each time promise callback returns a promise, this promise
Take the next then as your callback function, execute after resolve, or catch it after reject. This chain of notation makes the process of the function clearer,
Discard the nesting, finally can be flat writing code.
But promise only solves the problem of callback nesting, and does not resolve the callback itself, the code we see is still blocked with callbacks. So this is the introduction of async/await
Key word.
Async/await is the new standard for ES7, and has been supported in node7.0, but needs to be run using Harmony mode.
The async function is defined as follows
function fn () { return 0;}
Even if you modify the function with the Async keyword, the async function is characterized by a call to return that is not an ordinary value, but a Promise object, if
Normal return returns Promise.resolve (return value), or Promise.reject (exception) If an exception is thrown. Which means that the return of the async function
The value must be a promise, just what you write out is an ordinary value, this is just a syntactic sugar.
The await keyword can only be used in an async function, meaning you cannot use await anywhere. After the await keyword is followed by a Promise object, the function exits the function after it executes to await, until the event polling checks to promise the state resolve or reject to re-execute the contents after the function.
First, I'll show you the magic of async/await with just an example.
vari = 0;//function returns promisefunctionSleep (ms) {return NewPromise (function(Resolve, Reject) {SetTimeout (function() {Console.log (' I've done it. '); I++; if(I >= 2) reject (NewError (' i>=2 ')); ElseResolve (i); }, MS); })} (Asyncfunction () { Try { varVal; Val= Await sleep (1000); Console.log (Val); Val= Await sleep (1000); Console.log (Val); Val= Await sleep (1000); Console.log (Val); } Catch(Err) {Console.log (' ERROR: ' +err.message); }} ())
It appears that the code is fully synchronized, output once per wait for 1s, and can be try...catch when the status is reject in the promise returned by sleep.
So what the hell is going on here? Let's see a picture.
This code is just like the code, only after the async function is called and output a "main program is not called", the result is as follows
We find that the output is printed first, which seems to be different from our code, what's going on here.
In general async/await is the promise syntax sugar, but it can write the original asynchronous code in the form of synchronization, Try...catch is also a relatively friendly way to catch exceptions
So in the future when you write node as much as possible with promise or async/await, for callbacks do not use, a lot of nesting is really anti-human.
node. js asynchronous control flow callbacks, events, promise, and async/await