Reputation: 21
I am new to javascript, trying to understand async function invocation. Here is my js program:
var notify = function () {
console.log('before');
doPost('data', (res) => {
console.log('callback received');
});
console.log('after');
}
var doPost = function (data) {
console.log(data);
while (true) {
//do nothing
}
}
notify();
If my understanding is correct, notify()-->doPost() is async manner, therefore 'after' should be printed immediately after 'before'. But that does not happen. My program wait infinite loop to complete first. I know there is some loophole in my understanding. Please help.
I tried these below two programs: This one again shows sync behavior. Prints:- before data
var notify = function () {
console.log('before');
doPost('data').then((res) => {
console.log('callback received');
});
console.log('after');
}
var doPost = function (data) {
console.log(data);
return new Promise((resolve, reject) => {
resolve('resolved');
while (true) {
//do nothing
}
});
};
notify();
However if I just remove the infinitely running while loop, it start showing async behaviour. Prints:- before data after callback received
var notify = function () {
console.log('before');
doPost('data').then((res) => {
console.log('callback received');
});
console.log('after');
}
var doPost = function (data) {
console.log(data);
return new Promise((resolve, reject) => {
resolve('resolved');
while (false) {
//do nothing
}
});
};
notify();
This is beyond my understanding. Any help would be highly appreciated.
Upvotes: 2
Views: 1168
Reputation: 11600
Looking at your examples you seem to think of async as parallel execution since you expect that the code in the main thread keeps executing while an infinite loop is run on another thread. Parallel execution is a form of asynchronous operation but in javascript we generally use a concurrent execution.
But what does sync, async, parallel, concurrent really mean?
Synchronous code is the easiest to work with because it gives best guarantees:
/* 1 */ doWorkSync(() => console.log("callback"));
/* 2 */ console.log("after doWorkSync");
In the above code where doWorkSync
is a synchronous function we know that the callback function will be executed before line 2.
Concurrent code that in javascript is commonly referred to as async gives us a slightly worse guarantee:
/* 1 */ doWorkAsync(() => console.log("callback"));
/* 2 */ console.log("after doWorkAsync");
In the code above we are guaranteed that the callback function will be called after the current synchronous code will be completely executed, that is after line 2. But we don't know exactly when. It may be called immediately but it may be called a lot later.
But the most difficult code to work with is parallel code:
/* 1 */ doWorkParallel(() => console.log("callback"));
/* 2 */ console.log("after doWorkParallel");
In the code above we have no guarantees. The callback code can be run before line 2, at the same time or later. So the code have to be written in a way that it's prepared for any of those situations.
The easiest way to write an asynchronous (concurrent) function in JavaScript is to use Promise
:
console.log("first");
Promise.resolve().then(() => console.log("last"));
console.log("second");
In the code above then
callback is executed immediately after the current synchronous code is run from the microtask queue.
Parallel code can be executed in JavaScript with Worker
s:
function parallel() {
function work() {
block(200); // message from the main thread is logged while this blocks the worker
console.log("second"); // logs from the worker can be seen in the browser console
function block(time) {
const startDate = Date.now();
while (startDate + time > Date.now()) {};
}
}
new Worker(window.URL.createObjectURL(new Blob([`(${work})()`]), {
type: 'application/javascript'
}));
}
function block(time) {
const startDate = Date.now();
while (startDate + time > Date.now()) {}
}
parallel();
// timeout is needed because blob response is handled on the main thread
setTimeout(() => {
console.log("first");
block(500); // message from parallel is logged while this blocks the main thread
console.log("last");
}, 100)
Upvotes: 2
Reputation: 703
Why do you want to write your own async functions? There are so many different utilities already available:
Look at the examples here. Wont that help? https://caolan.github.io/async/
Upvotes: 1
Reputation: 138235
Using callbacks or promises does not necessarily mean that something is asynchronous. Take this example:
console.log("before");
[1, 2, 3].forEach(console.log);
console.log("after");
That will log everything in order, as .forEach
calls the callback synchronously. However, there are also asynchrnous callbacks, setTimeout
for example:
console.log("before");
setTimeout(function later() {
console.log("later");
}, 0);
console.log("after");
Here you will see "before", "after", "later", as the later
function gets executed asynchronously when the timer is done. To get asynchronous behaviour, you need an "asynchronous root callback", all callbacks / promises that are based on something asynchronous are also asynchronous. In Javascript there are just a few such "asynchronous roots", namely setTimeout
and setInterval
, fetch
and the DOM event handlers on browsers or all the IO on nodejs. In your code there is none of these, therefore it is, no matter what you do, completely synchronous.
To make it behave asynchronous, add an asynchronous callback:
function notify() { // function declarations look so much better than function expressions, and they are easier to handle
console.log('before');
doPost('data', (res) => {
console.log('callback received');
});
console.log('after');
}
function doPost(data, callback) { // you pass a callback, so you should take it here
console.log(data);
setTimeout(callback, 1, "result"); // call back asynchronously
}
notify();
Oh and while(true)
is usually an indicator that you made something very wrong.
Upvotes: 2