@manhng

Welcome to my blog!

JavaScript Async

July 22, 2017 16:40

JavaScript Asynchronous function

(hàm bất đồng bộ trong JavaScript)

1) Question: How should I call 3 functions in order to execute them one after the other?


If I need call this functions one after other,

        $('#art1').animate({'width':'1000px'},1000);       

        $('#art2').animate({'width':'1000px'},1000);        

        $('#art3').animate({'width':'1000px'},1000);       

I know in jQuery I could do something like:

        $('#art1').animate({'width':'1000px'},1000,'linear',function(){

            $('#art2').animate({'width':'1000px'},1000,'linear',function(){

                $('#art3').animate({'width':'1000px'},1000);       

            });       

        });       

But, let's assume that I'm not using jQuery and I want to call:

        some_3secs_function(some_value);       

        some_5secs_function(some_value);       

        some_8secs_function(some_value);       

How I should call this functions in order to execute some_3secs_function, and AFTER that call ends, then execute some_5secs_function and AFTER that call ends, then call some_8secs_function?

UPDATE:

This still not working:

    (function(callback){

        $('#art1').animate({'width':'1000px'},1000);

        callback();

    })((function(callback2){

        $('#art2').animate({'width':'1000px'},1000);

        callback2();

    })(function(){

        $('#art3').animate({'width':'1000px'},1000);

    }));

Three animations start at same time

Where is my mistake.

Answer


In Javascript, there are synchronous and asynchronous functions.

Synchronous Functions

Most functions in Javascript are synchronous. If you were to call several synchronous functions in a row

doSomething();doSomethingElse();doSomethingUsefulThisTime();

they will execute in order. doSomethingElse will not start until doSomething has completed. doSomethingUsefulThisTime, in turn, will not start until doSomethingElse has completed.

Asynchronous Functions

Asynchronous function, however, will not wait for each other. Let us look at the same code sample we had above, this time assuming that the functions are asynchronous

doSomething();doSomethingElse();doSomethingUsefulThisTime();

The functions will be initialized in order, but they will all execute roughly at the same time. You can't consistently predict which one will finish first: the one that happens to take the shortest amount of time to execute will finish first.

But sometimes, you want functions that are asynchronous to execute in order, and sometimes you want functions that are synchronous to execute asynchronously. Fortunately, this is possible with callbacks and timeouts, respectively.

Callbacks

Let's assume that we have three asynchronous functions that we want to execute in order, some_3secs_function, some_5secs_function, and some_8secs_function.

Since functions can be passed as arguments in Javascript, you can pass a function as a callback to execute after the function has completed.

If we create the functions like this

function some_3secs_function(value, callback){  //do stuff  callback();}

then you can call then in order, like this:

some_3secs_function(some_value, function() {  some_5secs_function(other_value, function() {    some_8secs_function(third_value, function() {      //All three functions have completed, in order.    });  });});

Timeouts

In Javascript, you can tell a function to execute after a certain timeout (in milliseconds). This can, in effect, make synchronous functions behave asynchronously.

If we have three synchronous functions, we can execute them asynchronously using the setTimeout function.

setTimeout(doSomething, 10);setTimeout(doSomethingElse, 10);setTimeout(doSomethingUsefulThisTime, 10);

This is, however, a bit ugly and violates the DRY principle[wikipedia]. We could clean this up a bit by creating a function that accepts an array of functions and a timeout.

function executeAsynchronously(functions, timeout) {  for(var i = 0; i < functions.length; i++) {    setTimeout(functions[i], timeout);  }}

This can be called like so:

executeAsynchronously(    [doSomething, doSomethingElse, doSomethingUsefulThisTime], 10);

In summary, if you have asynchronous functions that you want to execute syncronously, use callbacks, and if you have synchronous functions that you want to execute asynchronously, use timeouts.

2) Question: Make synchronous function in javascript?

I wanna synchronized functions just like jQuery's $.ajax({ .., async: false, .. });.

function A() { lalala .. };function B() { dadada .. };function C() { .. };

, those all including some effect like fadeIn, Out, slide... etc.

However I just found if those functions called like below..

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

All effect start at almost same time. In my understanding, this happens because the function called synchronously but it doesn't mean that function B() started after function A() was completely finished.. right?

Then, how can I make those functions work in order?

I found a way use callback function but it's not enough for me..

Answer

Have a look at using jQuery $.Deferred();

That can allow you to run each function in sequence, one waiting after the other. For example:

var a = function() {    var defer = $.Deferred();     console.log('a() called');     setTimeout(function() {        defer.resolve(); // When this fires, the code in a().then(/..../); is executed.    }, 5000);     return defer;}; var b = function() {    var defer = $.Deferred();     console.log('b() called');     setTimeout(function () {        defer.resolve();    }, 5000);     return defer;}; var c = function() {    var defer = $.Deferred();     console.log('c() called');     setTimeout(function () {        defer.resolve();    }, 5000);     return defer;}; a().then(b).then(c);

Using defer.resolve(); means you can control when the function yields execution to the next function.

 

3) Question: How can I create an Asynchronous function in Javascript?

You cannot make a truly custom asynchronous function. You'll eventually have to leverage on a technology provided natively, such as:

  • setInterval
  • setTimeout
  • requestAnimationFrame
  • XMLHttpRequest
  • WebSocket
  • Worker
  • Some HTML5 APIs such as the File API, Web Database API
  • Technologies that support onload
  • ... many others

In fact, for the animation jQuery uses setInterval.

4) Question: How do you create custom asynchronous functions in node.js?

I was unsure how node.js was able to realize what functions where async and which were not and how to create a custom ansyc function.

Say I wanted to create a custom asynchronous. I would be surprised if just because I called my last argument to the async function callback or cb that it would just know its an async function:

function f(arg1, callback){  //do stuff with arg1  arg1.doStuff()  //call callback  callback(null, arg1.result());}

I tried something like that and it did not work async. How do you tell node.js that f is actually async?

Answer

To create an asynchronous function, you have to have some async primitive (typically IO-related) on it - timers, reading from the filesystem, making a request etc.

For example, this function takes a callback argument, and calls it 100ms after:

function async(callback) {  setTimeout(function() {    callback();  }, 100);}

A possible reason for making a function async when it doesn't need to be, is for API consistency. For example, suppose you have a function that makes a network request, and caches the result for later calls:

var cache = null;function makeRequest(callback) {  if(!cache) {    makeAjax(function(result) {      cache = result;      callback(result);    });  } else {    callback(cache);  }}

The problem is, this function is inconsistent: sometimes it is asynchronous, sometimes it isn't. Suppose you have a consumer like this:

makeRequest(function(result) { doSomethingWithResult(result); });doSomethingElse();

The doSomethingElse function may run before or after the doSomethingWithResult function, depending on whether the result was cached or not. Now, if you use an async primitive on the makeRequest function, such as process.nextTick:

var cache = null;function makeRequest(callback) {  if(!cache) {    makeAjax(function(result) {      cache = result;      callback(result);    });  } else {    process.nextTick(function() callback(cache); });  }}

The call is always async, and doSomethingElse always runs before doSomethingWithResult.

5) Question: How to synchronously call a set of functions in javascript

I am working on a javascript project that needs to get some data and process it, but I am having trouble with the asynchronous nature of JavaScript. What I want to be able to do is something like the following.

//The set of functions that I want to call in orderfunction getData() {    //gets the data} function parseData() {    //does some stuff with the data} function validate() {    //validates the data} //The function that orchestrates these calls function runner() {    getData();    parseData();    validate();}

Here I want each function to wait for completion before going on to the next call, as I am running into the situation where the program attempts to validate the data before it has been retrieved. However, I also want to be able to return a value from these functions for testing, so I can't have these functions return a boolean value to check completion. How can I make javascript wait on the function to run to completion before moving on to the next call?

Answer

Use promises:

//The set of functions that I want to call in order

function getData(initialData) {

  //gets the data

  return new Promise(function (resolve, reject) {

    resolve('Hello World!')

  })

}

 

function parseData(dataFromGetDataFunction) {

  //does some stuff with the data

  return new Promise(function (resolve, reject) {

    resolve('Hello World!')

  })

}

 

function validate(dataFromParseDataFunction) {

  //validates the data

  return new Promise(function (resolve, reject) {

    resolve('Hello World!')

  })

}

 

//The function that orchestrates these calls

function runner(initialData) {

    return getData(initialData)

        .then(parseData)

        .then(validate)

}

 

runner('Hello World!').then(function (dataFromValidateFunction) {

    console.log(dataFromValidateFunction);

})

Not only are they easy to grasp, it makes total sense from a code readability stand point. Read more about them here. If you are in a browser environment, I recommend this polyfill.

6) Question: What is a simple example of an asynchronous javascript function?

I am really struggling here to get to grips with writing asynchronous JavaScript. Could you please provide an example of a simple JavaScript function which is asynchronous written in plain JavaScript (and not using Node.js or JQuery)

Answer

JavaScript itself is synchronous and single-threaded. You cannot write an asynchronous function; plain JS has no timing API. There will be no side-effects from parallel threads.

What you can do is use some APIs provided by your environment (Node.js, Webbrowser) that allow you to schedule asynchronous tasks - using timeouts, ajax, FileAPI, requestAnimationFrame, nextTick, WebWorkers, DOM events, whatever.

An example using setTimeout (provided by the HTML Timing API):

window.setTimeout(function() {

    console.log("World");

}, 1000);

console.log("Hello");

Update: Since ES6 there are promises as an asynchronous primitive built into plain JavaScript, so you can do

 Promise.resolve("World").then(console.log); // then callbacks are always asynchronous

 console.log("Hello");

However, on their own they're not really helpful when there is nothing you could wait for (such as a timeout). And they don't change anything about the threading model either, all execution is run-to-completion without any events interfering midway.

7) Introduction to asynchronous JavaScript

https://www.pluralsight.com/guides/front-end-javascript/introduction-to-asynchronous-javascript

In JavaScript we often need to deal with asynchronous behavior, which can be confusing for programmers who only have experience with synchronous code. This article will explain what asynchronous code is, some of the difficulties of using asynchronous code, and ways of handling these difficulties.

What is the difference between synchronous and asynchronous code?

Synchronous code

In synchronous programs, if you have two lines of code (L1 followed by L2), then L2 cannot begin running until L1 has finished executing.

You can imagine this as if you are in a line of people waiting to buy train tickets. You can't begin to buy a train ticket until all the people in front of you have finished buying theirs. Similarly, the people behind you can't start buying their tickets until you have bought yours.

Asynchronous code

In asynchronous programs, you can have two lines of code (L1 followed by L2), where L1 schedules some task to be run in the future, but L2 runs before that task completes.

You can imagine as if you are eating at a sit-down restaurant. Other people order their food. You can also order your food. You don't have to wait for them to receive their food and finish eating before you order. Similarly, other people don't have to wait for you to get your food and finish eating before they can order. Everybody will get their food as soon as it is finished cooking.

The sequence in which people receive their food is often correlated with the sequence in which they ordered food, but these sequences do not always have to be identical. For example, if you order a steak, and then I order a glass of water, I will likely receive my order first, since it typically doesn't take as much time to serve a glass of water as it does to prepare and serve a steak.

Note that asynchronous does not mean the same thing as concurrent or multi-threadedJavaScript can have asynchronous code, but it is generally single-threaded. This is like a restaurant with a single worker who does all of the waiting and cooking. But if this worker works quickly enough and can switch between tasks efficiently enough, then the restaurant seemingly has multiple workers.

Examples

The setTimeout function is probably the simplest way to asynchronously schedule code to run in the future:

// Say "Hello."console.log("Hello.");// Say "Goodbye" two seconds from now.setTimeout(function() {  console.log("Goodbye!");}, 2000);// Say "Hello again!"console.log("Hello again!");

If you are only familiar with synchronous code, you might expect the code above to behave in the following way:

  • Say "Hello".
  • Do nothing for two seconds.
  • Say "Goodbye!"
  • Say "Hello again!"

But setTimeout does not pause the execution of the code. It only schedules something to happen in the future, and then immediately continues to the next line.

  • Say "Hello."
  • Say "Hello again!"
  • Do nothing for two seconds.
  • Say "Goodbye!"

Getting data from AJAX requests

Confusion between the behavior of synchronous code and asynchronous code is a common problem for beginners dealing with AJAX requests in JavaScript. Often they will write jQuery code that looks something like this:

function getData() {  var data;  $.get("example.php", function(response) {    data = response;  });  return data;} var data = getData();console.log("The data is: " + data);

This does not behave as you would expect from a synchronous point-of-view. Similar to setTimeout in the example above, $.get does not pause the execution of the code, it just schedules some code to run once the server responds. That means the return data; line will run before data = response, so the code above will always print "The data is: undefined".

Asynchronous code needs to be structured in a different way than synchronous code, and the most basic way to do that is with callback functions.

Callback functions

Let's say you call your friend and ask him for some information, say, a mutual friend's mailing address that you have lost. Your friend doesn't have this information memorized, so he has to find his address book and look up the address. This might take him a few minutes. There are different strategies for how you can proceed:

  • (Synchronous) You stay on the phone with him and wait while he is looking.
  • (Asynchronous) You tell your friend to call you back once he has the information. Meanwhile, you can focus all of your attention on the other tasks you need to get done, like folding laundry and washing the dishes.

In JavaScript, we can create a callback function that we pass in to an asynchronous function, which will be called once the task is completed.

That is, instead of

var data = getData();console.log("The data is: " + data);

we will pass in a callback function to getData:

getData(function (data) {  console.log("The data is: " + data);});

Of course, how does getData know that we're passing in a function? How does it get called, and how is the data parameter populated? Right now, none of this is happening; we need to change the getData function as well, so it will know that a callback function is its parameter.

function getData(callback) {  $.get("example.php", function(response) {    callback(response);  });}

You'll notice that we were already passing in a callback function to $.get before, perhaps without realizing what it was. We also passed in a callback to the setTimeout(callback, delay) function in the first example.

Since $.get already accepts a callback, we don't need to manually create another one in getData, we can just directly pass in the callback that we were given:

function getData(callback) {  $.get("example.php", callback);}

Callback functions are used very frequently in JavaScript, and if you've spent any amount of time writing code in JavaScript, it's highly likely that you have used them (perhaps inadvertently). Almost all web applications will make use of callbacks either through events (e.g. window.onclick), setTimeout and setInterval, or AJAX requests.

Common problems with asynchronous code

Trying to avoid asynchronous code altogether

Some people decide that dealing with asynchronous code is too complicated to work with, so they try to make everything synchronous. For example, instead of using setTimeout, you could create a synchronous function to do nothing for a certain amount of time:

function pause(duration) {  var start = new Date().getTime();  while(new Date().getTime() - start < duration);}

Similarly, when doing an AJAX call, it is possible to set an option to make the call synchronous rather than asynchronous (although this option is slowly losing browser support). There are also synchronous alternatives to many asynchronous functions in Node.js.

Trying to avoid asynchronous code and replacing it with synchronous code is almost always a bad idea in JavaScript because JavaScript only has a single thread (except when using Web Workers). That means the webpage will be unresponsive while the script is running. If you use the synchronous pause function above, or a synchronous AJAX call, then the user will not be able to do anything while they are running.

The issue is even worse when using server-side JavaScript: the server will not be able to respond to any requests while waiting for synchronous functions to complete, which means that every user making a request to the server will have to wait to get a response.

Scope issues with callbacks inside loops

When you create a callback inside of a for-loop, you might encounter some unexpected behavior. Think about what you would expect the code below to do, and then try running it in your browser's JavaScript console.

for(var i = 1; i <= 3; i++) {  setTimeout(function() {    console.log(i + " second(s) elapsed");  }, i * 1000);}

The code above is likely intended to output the following messages, with a second of delay between each message:

1 second(s) elapsed.2 second(s) elapsed.3 second(s) elapsed.

But the code actually outputs the following:

4 second(s) elapsed.4 second(s) elapsed.4 second(s) elapsed.

The problem is that console.log(i + " second(s) elapsed"); is in the callback of an asynchronous function. By the time it runs, the for-loop will have already terminated and the variable i will be equal to 4.

There are various workarounds to this problem, but the most common one is to wrap the call to setTimeout in a closure, which will create a new scope with a different i in each iteration:

for(var i = 1; i <= 3; i++) {  (function (i) {    setTimeout(function() {      console.log(i + " second(s) elapsed");    }, i * 1000);  })(i);}

If you are using ECMAScript6 or later, then a more elegant solution is to use let instead of var, since let creates a new scope for i in each iteration:

for(let i = 1; i <= 3; i++) {  setTimeout(function() {    console.log(i + " second(s) elapsed");  }, i * 1000);}

Callback hell

Sometimes you have a series of tasks where each step depends on the results of the previous step. This is a very straightforward thing to deal with in synchronous code:

var text = readFile(fileName),    tokens = tokenize(text),    parseTree = parse(tokens),    optimizedTree = optimize(parseTree),    output = evaluate(optimizedTree);    console.log(output);

When you try to do this in asynchronous code, it's easy to run into callback hell , a common problem where you have callback functions deeply nested inside of each other. Node.js code and front-end applications with lots of AJAX calls are particularly susceptible to ending up looking something like this:

readFile(fileName, function(text) {  tokenize(text, function(tokens) {    parse(tokens, function(parseTree) {      optimize(parseTree, function(optimizedTree) {        evaluate(optimizedTree, function(output) {          console.log(output);        });      });    });  });});

This kind of code is difficult to read and can be a real pain to try to reorganize whenever you need to make changes to it. If you have deeply nested callbacks like this, it is usually a good idea to arrange the code differently. There are several different strategies for refactoring deeply nested callbacks.

Split the code into different functions with appropriate names

You can give names to the callback functions so that you can reference them by their names. This helps to make the code more shallow, and it also naturally divides the code into small logical sections.

function readFinish(text) {  tokenize(text, tokenizeFinish);}function tokenizeFinish(tokens) {  parse(tokens, parseFinish); }function parseFinish(parseTree) {  optimize(parseTree, optimizeFinish);}function optimizeFinish(optimizedTree) {  evalutate(optimizedTree, evaluateFinish);}function evaluateFinish(output) {  console.log(output);}readFile(fileName, readFinish);

Create a function to run a pipeline of tasks

This solution is not as flexible as the one above, but if you have a simple pipeline of asynchronous functions you can create a utility function that takes an array of tasks and executes them one after another.

function performTasks(input, tasks) {  if(tasks.length === 1) return tasks[0](input);  tasks[0](input, function(output) {    performTasks(output, tasks.slice(1));           //Performs the tasks in the 'tasks[]' array  });}performTasks(fileName,   [readFile, token, parse, optimize, evaluate, function(output) {    console.log(output);  }]);

Tools for dealing with asynchronous code

Async libraries

If you are using lots of asynchronous functions, it can be worthwhile to use an asynchronous function library, instead of having to create your own utility functions. Async.js  is a popular library that has many useful tools for dealing with asynchronous code.

Promises

Promises  are a popular way of getting rid of callback hell. Originally it was a type of construct introduced by JavaScript libraries like  and when.js , but these types of libraries became popular enough that promises are now provided natively in ECMAScript 6 .

The idea is that instead of using functions that accept input and a callback, we make a function that returns a promise object, that is, an object representing a value that is intended to exist in the future.

For example, suppose we start with a getData function that makes an AJAX request and uses a callback in the usual way:

function getData(options, callback) {  $.get("example.php", options, function(response) {    callback(null, JSON.parse(response));  }, function() {    callback(new Error("AJAX request failed!"));  });} // usagegetData({name: "John"}, function(err, data) {  if(err) {    console.log("Error! " + err.toString())  } else {    console.log(data);  }});

We can change the getData function so that it returns a promise. We can create a promise with new Promise(callback), where callback is a function with two arguments: resolve and reject. We will call resolve if we successfully obtain the data. If something goes wrong, we will call reject.

Once we have a function that returns a promise, we can use the .then method on it to specify what should happen once resolve or reject is called.

function getData(options) {  return new Promise(function(resolve, reject) {                    //create a new promise    $.get("example.php", options, function(response) {      resolve(JSON.parse(response));                                //in case everything goes as planned    }, function() {      reject(new Error("AJAX request failed!"));                    //in case something goes wrong    });  });} // usagegetData({name: "John"}).then(function(data) {  console.log(data)}, function(err) {  console.log("Error! " + err);});

The error handling feels a bit nicer, but it's difficult to see how we are making things any better given the size of the function. The advantage is clearer when we rewrite our callback hell  example using promises:

readFile("fileName")  .then(function(text) {    return tokenize(text);  }).then(function(tokens) {    return parse(tokens);  }).then(function(parseTree) {    return optimize(parseTree);  }).then(function(optimizedTree) {    return evaluate(optimizedTree);  }).then(function(output) {    console.log(output);  });

Conclusion

At this point, you should be familiar with strategies for confronting some of the difficulties that arise when using asynchronous code.

In this article I only gave a quick introduction to promises, but it is a large subject and there are many details that I left out. If you decide to use promises I would recommend reading a more in-depth introduction  to them.

I hope you enjoyed this tutorial. If you have any questions or feedback, feel free to leave a comment for me below.

Love this guide? Let the community know by clicking the heart! 20

Contributors

Thanks to the following users who've contributed to making this the best guide possible!

Have an idea for improving this guide? Edit this guide to get on the list!

Peter Olson

Dig into code from peterolson on Github.

Read more guides by Peter Olson on their profile.


Read more at https://www.pluralsight.com/guides/front-end-javascript/introduction-to-asynchronous-javascript/

8) Tham khảo

https://jakearchibald.com/2014/es7-async-functions/

https://blog.risingstack.com/asynchronous-javascript/

https://developers.google.com/web/fundamentals/getting-started/primers/async-functions

Categories

Recent posts