[Effective JavaScript notes] 67th: Never invoke asynchronous callback functions synchronously

Source: Internet
Author: User

Imagine a variant of the Downloadasync function that holds a cache (implemented as a dict) to avoid downloading the same file multiple times. Immediately invoking a callback function is an optimal choice if the file is already cached.

var cache=new Dict();function downloadCachingAsync(url,onsuccess,onerror){  if(cache.has(url)){    onsuccess(cache.get(url));    return;  }  return downloadAsync(url,function(file){    cache.set(url,file);    onsuccess(file);  },onerror);}

Typically, it provides data immediately, but this is in violation of the expectations of the asynchronous API client. First, it changes the expected order of operations. The 62nd article shows the following example, for a routine asynchronous API should always record log messages in a predictable order.

downloadAsync(‘file.txt‘,function(file){  console.log(‘finished‘);});console.log(‘starting‘);

Using the Downloadcachingasync implementation above, such client code may eventually log events in any order, depending on whether the file has been cached.

downloadCachingAsync(‘file.txt‘,function(file){  console.log(‘finished‘);});console.log(‘starting‘);

The order of the log messages is one thing. More generally, the purpose of the asynchronous API is to maintain strict separation of each round in the event loop. As explained in article 61st, this simplifies concurrency by reducing the amount of code per round of event loops without worrying about other code concurrently modifying the shared data structure. A synchronous call to an asynchronous callback function violates this separation, causing the code to perform a round of isolated event loops before the current wheel completes.
For example, an application might hold a remaining file queue to download and display messages to the user.

downloadCachingAsync(remaining[0],function(file){  remaining.shift();});status.display(‘Downloading ‘+remaining[0]+‘...‘);

If the callback function is called synchronously, a message with the wrong file name is displayed (or worse, "undefined" is displayed if the queue is empty).
Synchronous calls to asynchronous callback functions can even cause some subtle problems. The 64th article explains that the asynchronous callback function is essentially called with an empty call stack, so it is safe to implement the asynchronous loop as a recursive function without accumulating the risk of exceeding the call stack space at all. Synchronous calls do not guarantee this, making it possible for an asynchronous loop on a surface to run out of call stack space. Another problem is the exception. For the above Downloadcachingasync implementation, if the callback function throws an exception, it will throw the exception in each round of the event loop, which is the start of the download and not the expected split round.
To ensure that callback functions are always called asynchronously, we can use an existing asynchronous API. As we did in 65th and 66th, we use the Universal library function settimeout to add a callback function to the event queue after every minimum time-out. There may be a more perfect alternative to scheduling immediate events than the SetTimeout function, depending on the specific platform.

var cache=new Dict();function downloadCachingAsync(url,onsuccess,onerror){  if(cache.has(url)){    var cache=cache.get(url);    setTimeout(onsuccess.bind(null,cached),0);    return;  }  return downloadAsync(url,function(file){    cache.set(url,file);    onsuccess(file);  },onerror);}

This uses the BIND function to save the result as the first parameter of the onsuccess callback function. Tips

    • Never call an asynchronous callback function synchronously, even if you can get the data immediately

    • A synchronous call to an asynchronous callback function disrupts the expected sequence of operations and may lead to unexpected interleaved code

    • Calling asynchronous callback functions synchronously can result in stack overflow or incorrectly handling exceptions

    • Use asynchronous APIs, such as the settimeout function, to dispatch asynchronous callback functions to run in another round

[Effective JavaScript notes] 67th: Never invoke asynchronous callback functions synchronously

Related Article

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.