Callback to Hell
For JavaScript programmers, the process callback is homely, but the processing level of the callback is not so good, the following example code fragment with a three-layer callback, and then brain more layers of scenes, is simply sour, this is the legendary callback hell.
GetDirectories (function (dirs) {
GetFiles (dirs[0), function (files) {
getcontent (files[0), function (file, Content) {
console.log (' filename: ', file);
Console.log (content);
});
};
function GetDirectories (callback) {
settimeout (function () {
callback (['/home/ben ']);
}, 1000);
function GetFiles (dir, callback) {
settimeout (function () {
callback (dir + '/test1.txt ', dir + '/ Test2.txt ']);
}, 1000
}
function getcontent (file, callback) {
settimeout (function () {
Callback (file, ' content ');
}, 1000)
}
Solution
There are many asynchronous solutions in the biosphere that can handle the problem of callback hell, such as Bluebird, Q, etc., this article focuses on the support for asynchronous programming in the ECMAScript 6/7 specification.
ES6 Promise
Promise is a solution of asynchronous programming and a sharp weapon to solve the problem of callback hell.
Promise in the JavaScript Biosphere was accepted by the Dojo framework in 2007 to add Dojo. The Deferred function. With Dojo. The popularity of Deferred, in 2009 Kris ZYP proposed the COMMONJS promises/a specification. Subsequently, a large number of Promise were realized in the biosphere, including Q.js, Futuresjs and so on. Of course Promise's popularity is largely due to the existence of jquery, but jquery does not fully comply with the COMMONJS promises/a specification. Then, as you can see, the ES 6 specification contains Promise.
MDN in the Promise is described in this way:
The Promise object is a proxy that returns a value that is not necessarily known when the Promise object is created. It allows you to specify the processing method for the success or failure of an asynchronous operation. This allows the asynchronous method to return a value like a synchronous method: The asynchronous method returns a value that contains the original return
The following code is the example in the "Callback Hell" section that is implemented by Promise, which seems to be not very concise, but is more maintainable and readable than traditional hierarchical callbacks.
GetDirectories (). Then (function (dirs) {return
GetFiles (dirs[0));
Then (function (files) {return
getcontent (files[0]);
}). Then (function (val) {
console.log (' filename: ', val.file);
Console.log (val.content);
});
function GetDirectories () {return
new Promise (function (resolve, reject) {
settimeout (function ()
{ Resolve (['/home/ben ']);
}, 1000)
;} function GetFiles (dir) {return
new Promise (function (resolve, reject) {
settimeout (function () {
Resolve ([dir + '/test1.txt ', dir + '/test2.txt ']);
}, 1000)
;} function getcontent (file) {return
new Promise (function (resolve, reject) {
settimeout (function ()
{ Resolve ({file:file, Content: ' content '});
}, 1000);
}
ES6 Generator
Promise's implementation is not simple enough, we need a better choice, CO is one of the options. Co is an asynchronous flow controller based on generator (generator), and understanding generator is first needed before understanding Co. Students familiar with C # should be aware that the C # 2.0 version introduces the yield keyword for iterative generators. The ES 6 generator is similar to C # and uses the yield syntax sugar, which implements the state machine internally. Specific use can refer to the MDN document function* section, the principle can refer to Alloyteam team Blog in-depth understanding generator. Using CO cleverly combines ES6 generator and ES6 Promise to make asynchronous calls more harmonious.
Co (function* () {
var dirs = yield getdirectories ();
var files = yield GetFiles (dirs[0]);
var contentval = yield getcontent (files[0));
Console.log (' filename: ', contentval.file);
Console.log (contentval.content);
});
Co is very ingenious, its core code can simplify the following example, the general idea is to use the recursive traversal generator until the state is complete, of course, CO do more.
Rungenerator ();
function* run () {
var dirs = yield getdirectories ();
var files = yield GetFiles (dirs[0]);
var contentval = yield getcontent (files[0));
Console.log (' filename: ', contentval.file);
Console.log (contentval.content);
}
function Rungenerator () {
var gen = run ();
function go [result] {
if (result.done) return;
Result.value.then (function (r) {Go
(Gen.next (R));}
);
Go (Gen.next ());
}
ES7 async/await
ES6 generator is really good, but unfortunately needs the support of Third-party libraries. The good news is that ES 7 will introduce the ASYNC/AWAIT keyword to solve the problem of asynchronous invocation perfectly. Well,. NET is a step ahead, and the. NET Framework 4.5 has been the first to support it.
The next code is written like this:
Run ();
Async function Run () {
var dirs = await getdirectories ();
var files = await GetFiles (dirs[0]);
var contentval = await getcontent (files[0));
Console.log (' filename: ', contentval.file);
Console.log (contentval.content);
}
Conclusion
From the classic callback asynchronous programming, to the ES6 Promise specification to the improvement of asynchronous programming, and then to the co-integration ES Generator elegant processing, finally ES7 async/await perfect finale, can let us know why ECMAScript will appear these characteristics and solutions What is the problem, more clearly see the development of JavaScript asynchronous programming context.