JavaScript Asynchronous Evolutionary history

Source: Internet
Author: User

Preface

The most basic asynchronous invocation in JS is callback, which passes the callback function callback to the asynchronous API, which notifies the JS engine to invoke callback after the asynchronous completion of the browser or Node. For a simple asynchronous operation, it is sufficient to implement it with callback. But as the interactive page and Node appeared, the drawbacks of the callback scheme began to emerge. The Promise specification was conceived and incorporated into the ES6 norm. Later ES7 the async function into the standard on the basis of Promise. This is a history of JavaScript asynchronous evolution.

synchronous vs. asynchronous

Typically, the code is executed from the top down. If you have more than one task, you must queue, the previous task is completed, and the next task will not execute. This mode of execution is called Synchronization (synchronous). It is easy for beginners to confuse the synchronization in computer terminology with the synchronization in everyday language. For example, "Sync files to the cloud" in sync, meaning "make ... Consistency. " In the computer, synchronization refers to the pattern that the task executes from the top down. Like what:

A (); B (); C ();

In this code, a, B, and C are three different functions, each of which is an unrelated task. In synchronous mode, the computer performs A task, performs A B task, and finally executes the C task. In most cases, the sync mode is fine. But if the B task is a lengthy network request, and the C task happens to be a new page, it will cause the page to stutter.

A better solution would be to divide the B task into two parts. Part of the task that immediately executes the network request, and the other part executes the task after the request comes back. This part is executed immediately, and another part of the future execution pattern is called async.

A ();//In the now send request Ajax (' Url1 ', function B () {//At some time in the future) C ();//execution order A + c = B

In fact, the JS engine does not directly handle the task of the network request, it just invokes the browser's network request interface, the browser sends the network request and listens for the returned data. The nature of JavaScript async capability is the ability of the browser or Node to multithreading.

CallbackThe functions that are executed in the future are often called callback. Using the asynchronous mode of callback solves the problem of blocking, but it also brings some other problems. In the beginning, our function is written from the top down, but also from the top down, this "linear" pattern, very consistent with our thinking habits, but now is callback interrupted! In the above section of code, now it skips the B task to perform the C task first! This asynchronous "non-linear" code is more difficult to read than synchronizing "linear" code, so it's easier to breed bugs.

Try to determine the order of execution of the code below, and you will be more difficult to read than the "linear" code for "nonlinear" code.

A (); Ajax (' Url1 ', function () {B ();    Ajax (' Url2 ', function () {C ();    } D (); }); E ();//A = + E = B = D and C

In this code, the order of execution from the top down is Callback. Our reading code line of Sight is a, B, C, D, and E, but the order of execution is a and E and B and D and C, which is the bad thing about the nonlinear code.

By advancing the tasks performed behind Ajax, it is easier to understand the order in which the code is executed. Although the code looks ugly because of nesting, the order of execution now is a "linear" approach from top to bottom. This technique is useful when writing multiple nested code.

A ();    E (); Ajax (' Url1 ', function () {B ();    D ();    Ajax (' Url2 ', function () {C (); });//A = E = B and D = C

The last piece of code only handles a successful callback and does not handle the exception callback. Next, add the exception handling callback and discuss the problem of "linear" code execution.

A (); Ajax (' Url1 ', function () {B ();    Ajax (' Url2 ', function () {C ();    },function () {D ();    });    },function () {E (); });

After the exception handling callback, URL1 's successful callback function B and the exception callback function, E, are separated. This "non-linear" situation has arisen again.

In node, the error-first strategy was developed in order to solve the "nonlinear" problem caused by the abnormal callback. The first parameter of callback in node, specifically to determine if an exception occurred

A (); Get (' Url1 ', function (Error) {if (error) {E ()};        }else {B ();            Get (' Url2 ', function (Error) {if (error) {D ();            }else{C ();    }        }); }});

To this, the "nonlinear" problem caused by callback is basically solved. Unfortunately, using callback nesting, layer if else, and callback functions is not very convenient to read once the number of nested layers is multiple. In addition, callback can only handle exceptions within the current callback function once an exception occurs.

Promise

In the history of the asynchronous evolution of JavaScript, there emerges a series of libraries to solve callback's drawbacks, and Promise becomes the ultimate winner and is successfully introduced into ES6. It provides a better "linear" notation and resolves an issue in which an asynchronous exception can only be captured in the current callback.

Promise is like an intermediary that promises to return a trustworthy asynchronous result. First, Promise and asynchronous interface signed a protocol, when successful, call resolve function notification Promise, exception, call reject Notification Promise. On the other hand, Promise and callback also signed an agreement by Promise to return the trusted values in the future to the callback registered in then and catch.

Create a Promise instance (asynchronous interface and Promise signing protocol) var Promise = new Promise (function (resolve,reject) {ajax (' url ', resolve,reject);} )///The then catch method of the invocation instance (success callback, exception callback with Promise sign agreement) Promise.then (function (value) {//success}). catch (function (error) {/ /error})

Promise is a very good intermediary, it only returns the trusted information to callback. It makes some processing of the results of the third-party asynchronous library, which guarantees that the callback will be called asynchronously and will only be called once.

var promise1 = new Promise (function (resolve) {//May cause synchronization to call resolve (' B ') for some reason;});  /promise will still execute asynchronously promise1.then (function (value) {Console.log (value)}), Console.log (' a ');/a B (first a after B) var promise2 = new  Promise (function (resolve) {///successful callback was notified 2 times setTimeout (function () {resolve (); },0)});//Promise will only be called Once Promise2.then (function () {Console.log (' a ')});/A (only one) var promise3 = new Promise (function (res    Olve,reject) {//successful callback is notified first, and the failure callback SetTimeout (function () {resolve () is notified;  Reject (); },0)});//Promise only invokes the successful callback Promise3.then (function () {console.log (' A ')}). catch (function () {console.log (' B ')});// A (only a)

After describing the features of Promise, we look at how it uses chained calls to solve the problem of the readability of asynchronous code.

var fetch = function (URL) {//Returns a new Promise instance return Promise (function (resolve,reject) {Ajax (Url,resol    Ve,reject); });}    A (); Fetch (' URL1 '). Then (function () {B (); Returns a new Promise instance of return fetch (' Url2 ');}).    The catch (function () {////exception can also return a new Promise instance of return fetch (' url2 ');    Use chained notation to invoke the then method of this new Promise instance}). Then (function () {C (); Continue to return a new Promise instance ...}) A B C ...

Again and again, a Promise object is returned, which is invoked continuously in a chained way. The problem of callback layer nesting and the "nonlinear" execution of asynchronous code are Promise.

Another difficulty Promise solves is that callback can only catch the current error exception. Promise and callback different, each callback can only know their own error situation, but Promise agent all callback, all callback error, can be handled by Promise Unified. Therefore, catch can be used to catch an exception that was not previously caught.

Promise solves the callback asynchronous invocation problem, but Promise does not get rid of callback, it simply puts callback into a trusted intermediary, an intermediary that links our code to the asynchronous interface.

Asynchronous (Async) Functions

Asynchronous (Async) function is a new feature of ES7, it combines Promise, let us get rid of the callback of the binding, directly with the class synchronous "linear" way, write asynchronous function.

To declare an asynchronous function, simply add a keyword async before the normal function, such as async function main () {}. In an async function, you can use the await keyword, which represents the result of waiting for the execution of the subsequent expression, typically followed by an Promise instance.

Async function main{//timer is the var value defined in the previous example = await timer (100); Console.log (value); Done (after 100ms)}main ();

The Async function calls main () just like a normal function. After the call, the first line of code in the async function is executed immediately var value = await timer (100). The next line of code is not executed until the asynchronous execution completes.

In addition, asynchronous functions are basically similar to other functions, which use Try...catch to catch exceptions. You can also pass in parameters. However, do not use return in an async function to return a value.

var timer = new Promise (function Create (resolve,reject) {if (typeof delay!== ' number ') {Reject (' type ' ERROR  ‘)); } setTimeout (Resolve,delay, ' done ');});    Async function Main (delay) {try{var value1 = await timer (delay);    var value2 = await timer (');  var value3 = await timer (delay);      }catch (Err) {console.error (err);  Error:type error//at Create (<ANONYMOUS>:5:14)//AT timer (<ANONYMOUS>:3:10)//AT A (<anonymous>:12:10)}}main (0);

Asynchronous functions can also be treated as values, passed into normal functions and executed in asynchronous functions. However, in asynchronous functions, it is important to note that asynchronous functions are executed synchronously if you do not use await.

Async function Main (delay) {var value1 = await timer (delay);  Console.log (' A ')}async function Doasync (main) {main (0); Console.log (' B ')}doasync (main);//b A

The value printed at this time is B a. Indicates that the Doasync function did not wait for the asynchronous execution of main to execute the console. If you want the console to execute after the asynchronous execution of main, we need to add the keyword await before main.

Async function Main (delay) {var value1 = await timer (delay);    Console.log (' A ')}async function Doasync (main) {await main (0); Console.log (' B ')}doasync (main);//A B

Because asynchronous functions are written in a class-synchronous way, a novice may write as follows when dealing with multiple concurrent requests. This causes the URL2 request to be sent only when the URL1 request comes back.

var fetch = function (URL) {return new Promise (function (resolve,reject) {ajax (Url,resolve,reject); });}    Async function Main () {try{var value1 = await fetch (' URL1 ');    var value2 = await fetch (' url2 ');  Conosle.log (value1,value2); }catch (Err) {Console.error (err)}}main ();

Use the Promise.all method to solve this problem. Promise.all is used to wrap multiple Promise instances into a new Promis e instance, when all Promise The resolve function of Promise.all is triggered after success, and the Reject function of Promise.all is called immediately when there is a failure.

var fetch = function (URL) {return new Promise (function (resolve,reject) {ajax (Url,resolve,reject); });}    Async function Main () {try{var arrvalue = await Promise.all[fetch (' URL1 '), fetch (' url2 ')];  Conosle.log (arrvalue[0],arrvalue[1]); }catch (Err) {Console.error (err)}}main ();

Currently using Babel has supported transcoding of ES7 async functions, and you can start experimenting on your own projects.

JavaScript Asynchronous Evolutionary history

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.