I've read Why do I have to use await for a method to run asynchronously. What if I don't want to wait for the method to finish before continuing? and Are callbacks always asynchronous? and am still trying to understand when a callback is actually asynchronous.
For example, doThat will need to wait for GET data before doing anything with it. And as the second link above states, javascript is single threaded.
doThis(doThat);
function doThis(callback) {
$.get('http://some_api/some_resource', function (data) {
callback(data);
});
};
function doThat(data) {
// Do something with data
};
The only truly async functionality I've seen is with promises and multiple promises where I can, for example, load other data while animations are wrapping up. I'd like help better understanding when traditional callbacks are actually asynchronous. Concrete examples help.
Starting with the definition:
Asynchrony, in computer programming, refers to the occurrence of events independently of the main program flow and ways to deal with such events. These may be "outside" events such as the arrival of signals, or actions instigated by a program that take place concurrently with program execution, without the program blocking to wait for results.
-- Davies, Alex (2012). Async in C# 5.0, via Wikipedia on Asynchrony (computer programming)
In case of JavaScript, it works like this (simplified): There is a queue of tasks waiting to be executed by the main (and only) thread. When you load a script, it is a task placed on this queue. A task runs until it exits, and no other task can interrupt it. However, a task can cause other tasks to be placed on the queue. When one task finishes, the next task on the queue starts. If the queue is empty, the first task that enters the queue afterwards gets immediately executed.
The main ways for tasks to enter the queue, besides being the main task of script being parsed and executed: triggering an event will place handlers registered for that event on the task queue, and reaching a time scheduled by setTimeout or setInterval will place the associated task on the task queue.
In JavaScript context, everything that executes within the same task ("main program flow") is said to be synchronous. Everything that is executed in a future task is called asynchronous. Another way to tell is - if the next statement executes before the callback, it is asynchronous; if the next statement executes after the callback, it is synchronous.
$.get(opts, callback) is an asynchronous call, because the task that executes the function callback will be placed on the task queue when triggered by the onreadystatechange event. If you have a statement following it, it will get executed first; it is only after that task finishes, that the task which entered the task queue because of an update to your AJAX call will have a chance to run.
In contrast, $.each(collection, callback) is a synchronous call, because callback will be directly called from the each function, without exiting the current task, and will not generate any additional tasks (not by itself anyway, callback of course can generate additional tasks). The next statement will have to wait until each finishes iterating over every element of collection.
Note that promises are simply wrappers over this mechanism. Everything you can do with promises, you can do without them, just the code will not be as pretty and legible.
I can, for example, load other data while animations are wrapping up.
This is exactly what you can do with your code. Note that you can run other code (and indeed the "running other code" is what confuses people) while waiting for doThat to execute. Exactly like your animation example:
function doThis(callback) {
$.get('http://some_api/some_resource', function (data) {
callback(data);
});
};
function doThat(function (data) {
// Do something with data
});
function doAnotherThing(function (data) {
// Do something with data
});
doThis(doThat);
// without waiting for doThat to run, you can IMMEDIATELY call:
doThis(doAnotherThing);
// without waiting for either doThat or doAnotherThing you
// can output some pretty animations:
setInterval(do_animation,100);
// and without waiting for any of the above you can do anything else:
document.body.innerHTML += 'hello';
Note that what confuses most people is that the document.body.innerHTML='hello' part runs BEFORE any of the code above it. Which means that the callbacks are asynchronous because they get executed when data arrives, not when the function is called.
Note that not all callbacks are asynchronous. For example, Array.prototype.forEach() is synchronous:
document.body.innerHTML += 'before<br>';
['hello','world'].forEach(function(x){
document.body.innerHTML += x;
})
document.body.innerHTML += '<br>after';
What determines weather a callback is asynchronous or synchronous is the function that calls it. See also: I know that callback function runs asynchronously, but why?
Related
I am new to Javascript and Ascynchronous programming, and a few things confuse me, please point out the misfacts in my learning.
Callbacks of an Asynchronous function are put in a message queue and
executed via event loop.
Asynchronous execution is non-blocking, done
via event loop.
Functions like setTimeout are asynchronous.
Asynchronous functions are blocking, only their callbacks are
non-blocking.
If any of the above are wrong, please elaborate it.
Callbacks of an Asynchronous function are put in a message queue and executed via event loop.
No.
There are generally two kinds of asynchronous functions - ones that take some sort of callback to run when they are done and ones that produce a Promise as a result.
Callback-based functions
This is an example of a callback-based function:
setTimeout(() => console.log("foo"), 0);
console.log("bar");
/* output:
bar
foo
*/
setTimeout will delay a callback to be executed later. Even with a timeout of zero milliseconds, it still schedules the callback until after the current execution is complete, so the order is:
setTimeout schedules the callback.
console.log("bar") runs.
The callback with console.log("foo") runs.
There isn't a message queue, there is a queue of tasks to execute. As a brief overview, the event loop takes one task from the queueand executes it to completion, then takes the next one and executes it to completion, etc. A simple pseudo-code representation would be:
while(true) {
if (eventQueue.hasNext()) {
task = eventQueue.takeNext();
task();
}
}
See here for more information on the event loop.
With all that said, the event loop has more bearing on setTimeout than many other callback-based functions. Other examples of callback based functions are jQuery's $.ajax() or the Node.js fs module for file system access (the non-promise API for it). They, and others, also take a callback that will be executed later but the bounding factor is not the event loop but whatever underlying operation the function makes. In the case of $.ajax() when the callback would be called depends on network speed, latency, and the server which responds to the request. So, while the callback will be executed by the event loop, so is everything else. So, it's hardly special. Only setTimeout has a more special interaction here, since the timings might be imprecise based on what tasks are available - if you schedule something to run in 10ms and some task takes 12ms to finish, the callback scheduled by setTimeout will not run on time.
Promise-based functions
Here is an example:
async function fn(print) {
await "magic for now";
console.log(print);
}
fn("foo")
.then(() => console.log("bar"));
/* output:
foo
bar
*/
(I'm omitting a lot of details for now for illustration.)
Promises are technically an abstraction over callbacks tailored towards handling asynchronous operations. The .then() method of a promise takes a callback and will execute it after the promise gets resolved, which also happens after the asynchronous operation finishes. Thus, we can sequence together execution in the right order:
async function fn(print) {
await "magic for now";
console.log(print);
}
fn("foo");
console.log("bar");
/* output:
bar
foo
*/
In a way, promises are sort of callbacks because they are here to replace them and do it in broadly the same fashion. You still pass callbacks to be executed when something succeeds or fails. But they aren't just callbacks.
At any rate, a callback given to a promise is still delayed:
Promise.resolve()
.then(() => console.log("foo"));
console.log("bar");
/* output:
bar
foo
*/
But not via the same event queue as the one setTimeout uses. There are two queues:
macrotasks queue - setTimeout places things in it, and all UI interactions are also added here.
microtasks queue - promises schedule their things here.
When the event loop runs, the microtasks queue (so, promises) has the highest priority, then comes the macrotask queue. This leads to:
setTimeout(() => console.log("foo")); //3 - macrotask queue
Promise.resolve()
.then(() => console.log("bar")); //2 - microtask queue
console.log("baz"); //1 - current execution
/* output:
baz
bar
foo
*/
At any rate, I don't think I'm comfortable saying that promise-based functions work via callbacks. Sort of yes but in a reductionist sense.
Asynchronous execution is non-blocking, done via event loop.
No.
What is "blocking"?
First of all, let's make this clear - blocking behaviour is when the environment is busy executing something. Usually no other code can run during that execution. Hence, further code is blocked from running.
Let's take this code as example:
setTimeout(taskForLater, 5000);
while (somethingIsNotFinished()) {
tryToFinish();
}
Here taskForLater will be scheduled to run in 5 seconds. However, the while loop will block the execution. Since no other code will run, taskForLater might run in 10 seconds time, if that's how lot it takes for the loop to finish.
Running an asynchronous function doesn't always mean it runs in parallel with the current code. The environment executes one thing at time in most cases. There is no multi-threading by default in JavaScript, parallel execution is an opt-in behaviour, for example by using workers.
What is "asynchronous execution"?
This can mean a couple of things and it's not clear which one you reference:
Running through the body of an asynchronous function
Waiting until the underlying asynchronous operation is finished
In both cases the quoted statement is wrong but for different reasons.
The body of an async function
Async functions are syntactic sugar over promises. They use the same mechanism but just present the code differently. However, an async function is blocking. As a side note, so are promise executors (the callback given to a promise constructor). In both cases, the function will run and block until something causes it to pause. The easiest way to demonstrate it is with an async function - using await will pause the execution of the function and schedule the rest of it to be finished later.
Whole body is blocking:
async function fn() {
console.log("foo");
console.log("bar");
}
fn();
console.log("baz");
/* output:
foo
bar
baz
*/
Pausing in the middle:
async function fn() {
console.log("foo");
await "you can await any value";
console.log("bar");
}
fn();
console.log("baz");
/* output:
foo
baz
bar
*/
As a point of clarification, any value can be awaited, not just promises. Awaiting a non-promise will still pause and resume the execution but since there is nothing to wait for, this will cause it to be among the first things on the microtask queue.
At any rate, executing the body of an async function might block. Depends on what the operation is.
The underlying asynchronous operation
When talking about "underlying operation", most of the times we mean that we hand off the control to something else, for example the browser or a library. In this case, the operation is not fulfilled by the current JavaScript environment we call something which will perform an operation and only notify the current JavaScript environment when it finishes. For example, in a browser calling fetch will fire off a network request but it's the browser handling it, not our code. So it's non-blocking but not by outside the execution environment.
fetch("https://official-joke-api.appspot.com/random_joke")
.then(res => res.json())
.then(joke => console.log(joke.setup + "\n" + joke.punchline));
console.log("foo");
With that said, we cannot even generalise what a given asynchronous operation will do. It might actually block the execution, at least for a while, or it might be entirely carried out in a separate process to the current JavaScript environment.
Functions like setTimeout are asynchronous.
Yes.
Although, it's probably considering what is like setTimeout. Is it setInterval? Is it any callback-based asynchronous function? The problem is that the definition starts to become circular "asynchronous callback-based functions like setTimeout are asynchronous".
Not every function that takes a callback is asynchronous. Those that are might be considered similar to setTimeout.
Asynchronous functions are blocking, only their callbacks are non-blocking.
No.
As discussed above, asynchronous functions might block. Depends on what exactly they do. For example $.ajax will initiate a network request using the browser, similar to fetch. In the case of $.ajax the function blocks while preparing the request but not after it's sent.
The second problem with the statement is that it's incorrect to call the callbacks non-blocking - executing them will certainly block the execution again. The callback is a normal JavaScript code that will be executed via the event loop when its time comes. While the task is running to completion, execution is still blocked.
If you mean that they are non-blocking in the sense that the callback will be put on the event queue, that's still not guaranteed. Consider the following illustrative code:
function myAsyncFunction(callback) {
const asyncResult = someAsynchronousNonBlockingOperation();
doStuff(result);
callback(result);
doMoreStuff(result);
}
Once someAsynchronousNonBlockingOperation() produces a value executing callback will not be scheduled for later but will be part of the synchronous sequence of code that processes that result. So, callback will be executed later but it will not be a task by itself but part of an overall task that encompasses doStuff and doMoreStuff.
Callbacks of an Asynchronous function are put in a message queue and executed via event loop.
Just in a queue (no messages). By asynchronous function I suppose you mean Promises. Remember async and await are syntactic sugar for Promises. They are execute by the event loop.
Asynchronous execution is non-blocking, done via event loop.
Not really. Javascript is single threaded: whenever it starts executing your async code, it stays there as long as needed, unless you use Workers.
Functions like setTimeout are asynchronous.
Like Promise, setTimeout and similars put the callback in a queue, which will be executed somewhere in the event loop (which may behave different for each kind of async functions).
Asynchronous functions are blocking, only their callbacks are non-blocking.
Right!
console.log('Start');
const myFunc = async () => {
for(let i=0; i<10000000000000; i++){}
console.log('After for loop');
}
myFunc();
console.log('end');
I want async behaviour using async/await. I want my function to pass the entire function to an event loop same as SetTimeout, SetInterval does so that my main thread can continue to do the rest unless that heavy functionality is running behind the scene.
Expected Output: Start, end, After for loop
Current Output: Start, AFter for loop, end
Your understanding of asynchronous javascript code is not correct.
Function passed to setTimeout doesn't execute in the background - it executes on the main thread and while that function is executing, nothing else executes.
It's just that the callback function of setTimeout is pushed in to the call stack after the timer has expired and the call stack is empty. This is why other code can execute before the callback function of setTimeout executes.
Some functions provided by the browser such as HTTP requests happen in the background and once they are complete, Javascript will invoke our callback function and once that callback function starts executing, it blocks everything else from executing until that function is popped off the call stack.
Putting your code inside an async function doesn't makes your code asynchronous; it will execute synchronously until the first await expression. (Promises do not make anything asynchronous. They are just a notification mechanism that notifies you of either successful completion or a failure of something that is already asynchronous.)
What you need is another thread that executes the long running code without blocking the main thread. You can do this using a web worker in the browser or worker thread in NodeJS.
I know JavaScript is synchronous by nature. So that when I call a function with web API It performs synchronously:
setTimeout(function(){
console.log('1');
}, 2000);
console.log('2');
it will print '2' then '1'.
But when I run a loop like for loop and increase the iteration it executes synchronously:
var first = function(){
for(var i=0;i<=100000000;i++){
if(i==100000000){
console.log('first')
};
};
};
var second = function() {
console.log('second')
};
var a = function() {
first();
second();
}
a();
It will print the first second respectively.
So, is JavaScript performing synchronously with native code?
The first example is asynchronous because you've explicitly asked it to be asynchronous by using setTimeout. setTimeout (and its relation setInterval) explicitly set up an asynchronous timed callback to the function you pass them.
The remaining examples don't use anything that creates asynchronousness like setTimeout (and ajax and such) do, so naturally it's synchronous.
I know javaScript is asynchronous by nature
No, JavaScript (the language) is synchronous by nature. Literally the only asynchronous aspect of JavaScript was added in ES2015 and relates to when the callback passed into a promise's then or catch is called. That's it. setTimeout, for instance, is not part of JavaScript; it's part of the host environment where JavaScript is largely used (browsers). (It's also part of a couple of non-browser host environments, like NodeJS.)
JavaScript is primarily used in an environment that encourages asynchronous operations (browsers) where it's used to respond to user events (asynchronous), ajax completions (asynchronous), and timer callbacks (asynchronous), but the language is almost entirely synchronous.
JS is event-driven, this is why you think its async.. But it only has async features..
for loop does not have any event-callbacks, so its just sync
I got to know that
JavaScript is sync and async functionality depends on your functions implementation.
It has an event loop and it executes synchronously but whenever it will get the async function( the function which takes callback i.e setTimeout ,fs.readFile() etc) which is not the part of the javaScript then,
It put the function into the queue and invoke the queue function after all the native code(which is in current scope) execute then it pop the queue and invoke the functions.
and setTimeout explicitly set up an asynchronously timed callback to the function.
check this javaScript Async behavior ;
I am not an experienced developer and I have spent the last couple of days trying to understand few fundamental concepts about Javascript.
Single thread, blocking vs non-blocking and callback.
I have read a lot but I am still confused.
My understanding is that in a simple JS code all the statements are executed sequentially within a single thread.
In a more sophisticated situation where there are long running statements (db calls, network interaction, etc) this can be a huge problem.
The program execution (next statement) is BLOCKED until the current (long running) statement is completed.
Solution is to implement an asynchronous pattern, where the long running statement is executed in back ground (I can be brutally wrong here!) while the next statements are executed and when the long running statement has done, it passes back its result using a callback function provided in the calling statement.
Copy and pasting code from here and there I have written a trivial piece of code where I have a call back function
// function with callback
function doSomething(callback) {
callback();
}
// callback function implementation
function doSomethingElse() {
document.write("<p>Second element in the page</p>");
}
doSomething(doSomethingElse);
document.write("<p>First element in the page</p>");
The result of this code is actually what I would have expected before starting reading about non-blocking and callback (sequential code execution):
- Second element
- First element
So my question is, what's the magic fairy dust that transforms my code into asynchronous non-blocking one?
Cheers, Giovanni
what's the magic fairy dust that transforms my code into asynchronous non-blocking one?
In general, most long running operations will be handled APIs which handle asynchronous operations at a lower level than JavaScript (XMLHttpRequest for making HTTP requests being a prime example).
If you have need to implement a long running function yourself (maybe you want to do some heavy number crunching on the client) then you can use Web Workers.
var myWorker = new Worker("find_prime_numbers.js");
myWorker.onmessage = function(e) {
console.log('Next prime number is ' + e.data);
}
and in find_prime_numbers.js:
// Calculate some primes
postMessage(my_prime_number);
You have used callbacks, but it doesn't mean that this call is asynchronous.
It synchronously runs doSomething, which runs callback and outputs "Second element".
It would be asynchronous, if you had an asynchronous call there - AJAX call, file system access or a simple setTimeout:
function doSomething(callback) {
setTimeout(callback, 1000);
}
// callback function implementation
function doSomethingElse() {
document.write("<p>Second element in the page</p>");
}
doSomething(doSomethingElse);
document.write("<p>First element in the page</p>");
Now, it does the following: runs doSomething, which runs setTimeout and runs doSomethingElse right after that. At the same time, setTimeout asynchronously waits for 1 second and calls the function.
In other cases, it could be any other asynchronous operation, which requires time to complete.
I understand that Javascript doesn't have multiple threads, but I'd like to know if the following code has any chance of breaking. My understanding is that unless an asynchronous function is called, such as setTimeout or an AJAX call, that once a block of code starts executing there's no way for it to pause until it completes or does call an asynchronous function.
Basically, users select multiple checkboxes and then hits a button that executes AJAX processing of their selections. My goal is to have a "Saving..." icon that stays only until all the AJAX processes are complete, and after all are finished display a success message.
Barring any AJAX errors, so long as the callback function in the jQuery.post executes in its entirety without interruption, I don't see how the if(numProcessed == toProcess) would ever execute more than once or less than once. But if two AJAX callbacks get into the callback function, both increment the numProcessed counter before either get to the following if, then it seems that the code inside would be executed twice.
var numProcessed = 0;
var checkedBoxes = jQuery("input[type=checkbox]:checked");
var toProcess = checkedBoxes.size();
checkedBoxes.each(function() {
jQuery.post('somepage.php',{...},function(results) {
numProcessed++;
if(numProcessed == toProcess) {
jQuery("#saving-message").remove();
jQuery("#feedback-panel").text('Successfully processed all selections.');
}
}
}
There is only one thread in JavaScript so every function that want to be execute is put in stack and have to wait until all others are execute. In your case "each" is the first function in the stack, so every callback function have to wait and will be execute in the order they put on the stack.
After all "numProcessed == toProcess" could only one time be true.
The rx.net team has introduced rx for javascript. Reactive extension are for asynchronous programming. they have also written for rxjs for jquery too. My be that suite your need http://msdn.microsoft.com/en-us/devlabs/ee794896.aspx