The Evolution of asynchronous JavaScript combs the development of JavaScript asynchronous functions, first through the callback function, and then through the promise/a+, generator function, And the future will be the async function. Thank Jingzhung for the translation of the article as follows:
Now let's review the evolution of JavaScript asynchronous functions over the years.
callback function callbacks
It seems that everything should start with the callback function.
Asynchronous JavaScript
As we know, in JavaScript, asynchronous programming can only be done through a first-class civic function in the JavaScript language: This means that we can use a function as an argument to another function, Within this function, you can call the function that is passed in (that is, the callback function). This is why the callback function was born: If you pass a function as an argument to another function (which is called a higher order function), then within the function you can call the function to do the task. The callback function does not return a value (do not attempt to use returns) and is used only to perform certain actions within the function. Look at an example:
Something.save (function (err) {
if (err) {
//error handling
return;////No returns value
}
console.log (' Success ');
In the example above we demonstrated a bug-first callback function (Error-first callbacks), which is one of the features of Node.js itself, and most of the modules in Node.js and NPM warehouses follow this feature when they are written.
The challenge of using the callback function over and over:
If you can't organize your code properly, it's very easy to make a callback to Hell (Callback Hell), which makes your code difficult for others to understand.
It is easy to omit error handling code.
You cannot return a value using the returns statement, and you cannot use the Throw keyword.
It is for these reasons that, in the JavaScript world, there is always a way to find a workable solution that makes asynchronous JavaScript development easier.
One feasible solution is the async module. If you've been dealing with a callback function for a long time, you may have a deep sense of how complicated it is to use asynchronous functions in JavaScript if you want something to be done in parallel, serially, or even using asynchronous functions to map elements in an array (mapping). So, thank Caolan McMahon wrote the Async module to solve these problems.
With the Async module, you can easily write code in the following way:
Async.map ([1, 2, 3], Asyncsquaringlibrary.square,
function (err, result) {
//result would be [1, 4, 9]
The async module, though somewhat convenient, is still not simple enough and the code is not easy to read, so promise appears.
Promise
The current JavaScript asynchronous standard dates back to 2012, and until ES6 became available, however, the term promise was not invented by the JavaScript community. The term comes from Daniel P.friedman in a 1976 post.
A promise represents the end result of an asynchronous operation.
Now we use promise to complete the above code, the Promise style code is as follows:
Something.save ()
. Then (function () {
console.log (' success ');
})
. catch (function () {
//error handling
You will find that the callback function is also used in promise. A callback function is passed in both the then and the Catch method, which is executed when the promise is satisfied and rejected. Another advantage of the promise function is that it can be linked up to complete a series of tasks. For example, you can write code like this:
Savesomething ()
. Then (updateotherthing)
. Then (Deletestuff)
When you don't have a ready-made promise, you may need to use some promise libraries, a popular choice is using Bluebird. These libraries may provide more functionality than native scenarios and are not limited to the characteristics specified by the promise/a+ standard.
But why don't you use the sugar method (sugar methods)? It is recommended that you first read promise:the Extension problem this article. For more information on Promise, refer to the promise/a+ standard.
You might ask: if most of the libraries only expose the callback interface, how do I use promise?
Well, this is simple, and the only thing you need to do is use promise to wrap the function call body that contains the callback. For example:
The callback-style code might be like this:
function Savetothedb (value) {
Db.values.insert (value, function (err, user) {
if (err) throw err;
Todo:insert user to DB
});
Now we change it to a code that supports promise style calls:
function Savetothedb (value) {return
new Promise (function (resolve, reject) {
Db.values.insert (value, function (Err, user) {//Remember error;)
if (err) {return
reject (err);//don ' t forget to return here
}
Resolve (US ER);
}
There are already a large number of libraries or frameworks that support both ways of providing both callback style and promise-style API interfaces. Now, if you also want to provide a library, best practices also provide two ways to interface. You can easily use the following methods to achieve this goal:
function foo (CB) {
if (CB) {return
CB ();
}
return new Promise (function (resolve, reject) {
});
Or, more simply, you can start with a promise-style interface and use tools such as callbackify to achieve backwards compatibility. In fact, Callbackify's work is similar to the code snippet above, but it uses a more general approach to implementation, and I recommend that you read Callbackify's source code.
Builder Generators/yield
The JavaScript Builder is a relatively new concept, which is a new feature of ES6 (also known as ES2015). Imagine a scenario like the following:
When you perform a function, you can suspend the execution of the function at some point, and do some other work, and then return to the function, even carrying some new values, and then proceed.
The scenario described above is exactly what the JavaScript builder function is trying to solve. When we call a generator function, it does not execute immediately, but it requires us to manually perform the iterative operation (next method). That is, you call the generator function, and it returns you to an iterator. Iterators traverse each breakpoint.
function* foo () {
var index = 0;
while (Index < 2) {
yield index++;//suspend function execution and perform yield action
}
var bar = foo ();//return is actually an iterator
Conso Le.log (Bar.next ()); {value:0, done:false}
Console.log (Bar.next ()); {value:1, done:false}
Console.log (Bar.next ());
Further, if you want to use the generator function more easily to write asynchronous JavaScript code, we can use the Co as the library, and Co is the famous TJ Great God wrote.
Co is a generator-based process Control tool for Node.js and browsers, and with promise, you can write non-blocking code in a more elegant way.
Using CO, the preceding sample code, we can rewrite it using the following code:
Co (function* () {
yield something.save ();
}). Then (function () {
//Success
})
. catch (function (err) {
//error handling
You might ask: how do you implement parallel operations? The answer may be simpler than you might think, as follows (in fact, it is Promise.all):
Yield [Something.save (), Otherthing.save ()];
Async/await
The concept of the Async function has been introduced in ES7 (which has not yet been formalized) and, if you want to use it, can only be converted to ES5 code using a syntax converter such as Babel. (One caveat: we're talking about the Async keyword, not the async package in NPM).
In short, using the Async keyword, you can easily achieve the work done before using the generator and CO functions. Except hack, of course.
Perhaps you might ask, is it not so important to have the Async keyword in ES7? yield?
In fact, using yield to implement asynchrony is just a hack, yield means lazy order (lazy sequences) and iterators. and await can perfectly separate these two points, first let yield for its original purpose, followed by the use of await to perform asynchronous operations.
Behind this, the async function actually uses promise, which is why the async function returns a promise reason.
So, we use the async function to do something like the previous code, and you can rewrite the code in the following way:
Async function Save (something) {
try {
await something.save ();//wait for the code after await to execute, similar to yield
} catch (ex) {
//error handling
}
console.log (' success ');
As you can see, using the Async function, you need to add the Async keyword to the front of the function declaration. After that, you can use the AWAIT keyword inside the function, and the effect is similar to the previous yield function.
Using the Async function to accomplish parallel tasks is very similar to yiled, except that at this point the promise.all is no longer implicit and you need to display the call to it:
Async function Save (something) {
await promise.all[something.save (), Otherthing.save ()]
KOA also supports async functions, and if you are using KOA, then you can use this feature now with the help of Babel.
Import koa from KOA;
Let app = Koa ();
App.experimental = true;
App.use (Async function () {
this.body = await promise.resolve (' Hello reader! ')
})
App.listen (3000);
The above content for everyone to share the JavaScript asynchronous function development process, I hope to help.