Item 62:use Nested or Named callbacks for asynchronous sequencing

Source: Internet
Author: User

Item shows how asynchronous APIs perform potentially expensive I/O operations without blocking the Applic Ation from continuing doing work and processing other input. Understanding the order of operations of asynchronous programs can be a little confusing at first. For example, this program prints out "starting" before it prints "finished", even though the both actions appear in the OPP Osite order in the program source:

Downloadasync ("file.txt",  function(file)  {console.log ("finished");}); Console.log (

The Downloadasync call returns immediately, without waiting for the file to finish downloading.  Meanwhile, JavaScript's run-to-completion guarantee ensures that's next line executes before any other Event handlers is executed. This means, "starting" is sure to print before "finished".

The easiest way to understand this sequence of operations is  to think of an asynchronous api as initiating rather than  performing an operation. the code above first initiates the  download of a file and then immediately prints out  " Starting ". when the download completes, in some  separate   turn  of  the  event  loop,  the  registered   event  handler prints  "finished".  

So,  if  placing  several  statements  in  a   row  only  works  if  you  need 
to  do something after initiating an operation how do you  sequence 
Completed  asynchronous  operations?  for  example,   what  if  we  need 
To look up a url  in an asynchronous database and then download 
the   Contents  of  that  url?  it s  impossible  to  initiate  both   requests 
back-to-back: 

 db.lookupasync ("url", function   (URL) {  // ?  }); Downloadasync (URL,  function  (text) {//<  /span> Error:url is not bound  console.log (" contents of "+ URL +": " + text); }); 

This can " t  possibly work, because the url resulting from the data-
Base lookup is needed as the argument to downloadasync, but  it s not  
In scope. and with good reason: all we ' t  available 
yet. 

The most straightforward answer are to use nesting. Thanks to the power of closures (see Item one), we can embed the second action in the callback to the first:

Db.lookupasync ("url",  function(URL)  {  downloadasync (URL),function( Text)  {console.log ("contents  of  "  +  URL  +  ":  "  +  

There is still and callbacks, but the second was contained within the first, creating a closure that had access to the out ER callback's variables. Notice How the second callback refers to URL.

Nesting asynchronous operations is easy, but it quickly gets unwieldy when scaling up to longer sequences:

 db.lookupasync ("url", function   (URL) {        Downloadasync (URL,  function   (file) {            Downloadasync ( "A.txt", function   (a) {                Downloadasync ( "B.txt", function   (b) {                    Downloadasync ( "C.txt", function   (c) {  //  ...             });        });    });                        });}); 

one way to mitigate excessive nesting is to lift nested  callbacks back 
out as named functions and pass them any  additional data they need 
as extra arguments. the two-step  example above could be rewritten as: 

 db.lookupasync ("url"  function   DownloadURL (URL) {downloadasync (URL,  function  (text) {//  still nested   showcontents (URL, text); });    function   showcontents (URL, text) { Console.log ( contents of "+ URL +": "+ text);}  

This still uses a nested callback inside DownloadURL in order to combine the outer URL variable with the inner text Variab Le as arguments to showcontents. We can eliminate this last nested callback with BIND (see Item 25):

Db.lookupasync ("url",  function  downloadurl (URL)  {downloadasync (URL),  Showcontents.bind (null,  URL));} function   showcontents (URL,  text)  {console.log ("contents  of  "  +  URL  +  ":  "  +  text);}

This approach leads-to-more sequential-looking code, but at the cost of have to name each intermediate step of the Seque NCE and copy bindings from step to step. This can get awkward in cases like the longer example above:

Db.lookupasync ("url", Downloadurlandfiles); functiondownloadurlandfiles (URL) {downloadasync (URL, downloadabc.bind (NULL, URL));}//awkward namefunctiondownloadabc (URL, file) {Downloadasync ("A.txt", //Duplicated BindingsDownloadfiles23.bind (NULL, URL, file));}//awkward namefunctiondownloadbc (URL, file, a) {Downloadasync ("B.txt", //More duplicated bindingsDownloadfile3.bind (NULL, url, file, a));//awkward namefunctiondownloadc (URL, file, a, b) {Downloadasync ("C.txt",//still more duplicated bindingsFinish.bind (NULL, url, file, a, b));}functionFinish (URL, file, a, B, c) {//  ... }

Sometimes a combination of the approaches strikes a better balance, albeit still with some nesting:

Db.lookupasync ("url",function(URL) {downloadurlandfiles (URL);}); functiondownloadurlandfiles (URL) {downloadasync (URL, downloadfiles.bind (NULL, URL));}functiondownloadfiles (URL, file) {Downloadasync ("A.txt",function(a) {Downloadasync ("B.txt",function(b) {Downloadasync ("C.txt",function(c) {//  ...         });  }); });}

Even better, this last step can is improved with an additional abstrac-
tion for downloading multiple files and storing them in an array:

function   downloadfiles (URL,  file)  {downloadallasync (["A.txt",  "B.txt",  "C.txt"  function (All)  {  var  a  =  all[0],  b  =  all[1],  c  =  //    

Using Downloadallasync also allows us to download multiple files
concurrently. Sequencing means that each operation cannot even
be initiated until the previous one completes. and some operations
is inherently sequential, like downloading the URL of We fetched from
A database lookup. But if we had a list of filenames to download,
Chances is there's no reason to wait for each file to finish download-
ING before requesting the next. Item explains how to implement
Concurrent abstractions such as Downloadallasync.

Beyond nesting and naming callbacks, it's possible to build higherlevel abstractions to make Asynch Ronous control flow simpler and more concise. Item describes one particularly popular approach. Beyond that, it'sworth exploring Asynchrony libraries or experimenting with abstractions of your own.

Things to Remember

? Use nested or named callbacks to perform several asynchronous operations in sequence.

? Try to strike a balance between excessive nesting of callbacks and awkward naming of non-nested callbacks.

? Avoid sequencing operations that can be performed concurrently.

Item 62:use Nested or Named callbacks for asynchronous sequencing

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.