I'm learning node js callbacks and asynchronous behavior from this site. From the examples given, I've written following code to understand it better.
function callbackTester (callbackFn){
console.log('From callback tester.');
callbackFn();
}
function pollingWait(){
while (true) {}
}
callbackTester(() => {
console.log('From anonymous function.');
setTimeout(()=>{
console.log("I'm waiting!");
}, 500);
// pollingWait();
});
console.log('I am the last one');
Now, when I comment out pollingWait() function, it works as expected. It gives following output:
From callback tester.
From anonymous function.
I am the last one
I'm waiting!
Now when I comment out the setTimeout function and add pollingWait(), program goes in infinite loop. I think this is also an expected behavior as node js is single threaded and cannot avoid infinite loops. So how this asynchronous behavior works under the hood?
How it decides to when to continue execution and when not to? Is it possible to make my own function which acts as asynchronous like setTimeout?
I think this is also an expected behavior as node js is single threaded and cannot avoid infinite loops.
Node.js isn't single-threaded anymore, but there is just one main thread unless you create worker threads.
So how this asynchronous behavior works under the hood?
Node.js's main thread works on a loop: Your top-level code runs and returns, then any queued action (such as a timer callback) is run and returns, and then the next queued action runs and returns, etc. That's how setTimeout works: When it's time for the timer to fire, the event loop sees that and queues a call to the timer callback. Also note that while Node.js has only one main JavaScript thread by default, that doesn't mean Node itself is single-threaded. In particular it may do I/O processing on another internal thread.
Is it possible to make my own function which acts as asynchronous like setTimeout?
Only by using something that already provides asynchronous behavior and wrapping it. Those would include:
setTimeout
setImmediate
process.nextTick
A promise's then or catch callback
At first glance you might think async functions do that, but they don't, really: The code in an async function runs synchronously up until the first time it waits on a promise resolution (or up until it returns). So the asynchronousness is really just the same as the last bullet point above: A then or catch callback.
What you can't do (without a worker thread) is busy-wait like your pollingWait does, because nothing else can happen on the thread that busy-wait is running on.
Try this thing:
let done = false;
setTimeout(() => {
done = true
}, 5);
const eventLoopQueue = () => {
return new Promise(resolve =>
setImmediate(() => {
console.log('event loop');
resolve();
})
);
}
const run = async () => {
while (!done) {
console.log('loop');
await eventLoopQueue();
}
}
run().then(() => console.log('Done'));
Related
I am new to react and I am stuck in this. I am calling functions in a function like so:
submit = () => {
this.props.getValue();
this.props.resetValidation();
this.notify();
this.props.toggle();
this.props.disable();
this.props.actionCost();
//this.props.action();
// this.props.actionTable();
};
What is happening is that all the functions are running simultaneously without a function getting fully executed. Why is this happening shouldnt a function be called only after first function runs successfully?
Also how do I run the functions one after the other after a function is fully executed?
Please help
The only way to stop the execution flow, is by using async/await or a generoator function, and even these are only "syntactic sugar" on top of Promise.
You are probably calling an asynchronous function, and expecting it to "complete" without using await.
Another situation is calling a function that internally using asynchronous calls (Like axios or fetch), and reply back with callbacks. In this situation the execution continues, and the callback will be called later, that's way we call them "callback"
For example:
console.log('before');
setTimeout(() => console.log('timer completed'), 1000);
console.log('after');
Will result in:
before
after
timer completed
In this example I'm logging before, then setting a timeout where I'm providing a callback (a simple function) that will be executed later (1 sec.), meanwhile the execution flow continues, and logs after. once the timer reached the system will execute my callback.
In case that you want to execute the after after the timer completed, you will have to provide a callback that will be called after the execution is done.
like this:
function logTimer(doAfter) {
setTimeout(() => {
console.log('timer completed');
doAfter();
}, 1000);
}
console.log('before');
logTimer(() => console.log('after'));
I am having trouble finding a use for Promises. Wouldn't these 2 approaches below work the same exact way? Since the while loop in loopTest() is synchronous, logStatement() function wouldn't run until it's complete anyways so how would the the 2nd approach be any different ..wouldn't it be pointless in waiting for it to resolve() ?
1st approach:
function loopTest() {
while ( i < 10000 ) {
console.log(i)
i++
})
}
function logStatement() {
console.log("Logging test")
}
loopTest();
logStatement();
2nd approach:
function loopTest() {
return new Promise((resolve, reject) => {
while ( i < 10000 ) {
console.log(i)
i++
if (i === 999) {
resolve('I AM DONE')
}
})
});
}
function logStatement() {
console.log("Logging test")
}
loopTest().then(logStatement());
Promises don't make anything asynchronous,¹ so you're right, there's no point to using a promise in the code you've shown.
The purpose of promises is to provide a standard, composable means of observing the result of things that are already asynchronous (like ajax calls).
There are at least three massive benefits to having a standardized way to observe the results of asynchronous operations:
We can have standard semantics for consuming individual promises, rather than every API defining its own signature for callback functions. (Does it signal error with an initial parameter that's null on success, like Node.js? Does it call the callback with an object with a success flag? Or...)
We can have standard ways of composing/combining them, such as Promise.all, Promise.race, Promise.allSettled, etc.
We can have syntax to consume them with our usual control structures, which we have now in the form of async functions and await.
But again, throwing a promise at a synchronous process almost never does anything useful.²
¹ One very small caveat there: The handler functions to attach to a promise are always triggered asynchronously, whether the promise is already settled or not.
² Another small caveat: Sometimes, you have a synchronous result you want to include in a composition operation (Promise.all, etc.) with various asynchronous operations. In that case, wrapping the value in a promise that's instantly fulfilled is useful — and in fact, all the standard promise combinators (Promise.all, etc.) do that for you, as does await.
There's no point in what you are doing, because your function body is just a blocking loop.
To get a benefit from Promises, use it with APIs that do something with IO, such as a HTTP request, or reading a file from disk.
These APIs all traditionally used callbacks, and are now mostly Promise based.
Anything function that uses a Promise-based function, should itself also be Promise-based. This is why you see a lot of promises in modern code, as a promise only has to be used at 1 level in a stack for the entire stack to be asynchronous in nature.
Is this a better example of how Promises are used? This is all I can think of to make it show use to me:
Version 1
function getData() {
fetch('https://jsonplaceholder.typicode.com/todos/1')
.then(data => data.json())
.then(json => console.log(json))
}
function logInfo() {
console.log("i am a logger")
}
getData()
logInfo()
// "I am a logger"
// {"test": "json"}
Version 2
function getData() {
return fetch('https://jsonplaceholder.typicode.com/todos/1')
.then(data => data.json())
.then(json => console.log(json))
}
function logInfo() {
console.log("i am a logger")
}
getData().then(logInfo);
// "{"test": "json"}
// "I am a logger"
// waits for API result to log _then_ logInfo is run , which makes a log statement
There's definitely benefits to using Promises but that's only in certain scenarios where their usage would seem viable.
Your example could represent what would happen when you retrieve data from an external source synchronously, it would block the thread preventing further code from executing until the loop terminates (I explain below why exactly that happens) - wrapping it in a promise gives no different output in that the thread is still being blocked and when the next message in the queue has to be processed, it gets processed like normal right after it ends.
However an implementation similar to this could achieve a while loop running in a non-blocking manner, just an idea (don't mean to derail this topic with setInterval's implementation):
let f = () => {
let tick = Date.now;
let t = tick();
let interval = setInterval(() => {
if (tick() - t >= 3000) {
console.log("stop");
clearInterval(interval);
}
}, 0);
};
f()
console.log("start");
Basically the time is checked/handled in a separate thread in the browser and the callback is executed every time the time specified runs out while the interval hasn't been cleared, after the call stack becomes empty (so UI function isn't affected) and the current executing function terminates/ends or after other functions above it in the stack finish running. I don't know about the performance implications of doing something like this but I feel like this should only be used when necessary, since the callback would have to be executed very frequently (with 0 timeout, although it's not guaranteed to be 0 anyway).
why it happens
I mainly want to clarify that while the handler functions will be scheduled to be executed asynchronously, every message in the queue has to be processed completely before the next one and for the duration your while loop executes, no new message can be processed in the event queue so it would be pointless to involve Promises where the same thing would happen without them.
So basically the answer to:
wouldn't it be pointless in waiting for it to resolve() ?
is yes, it would be pointless in this case.
I have alot of syncrhounous functions that i want to execute before that are basic ajax requests, these request will render html to the DOM.
In order to do this i had to execute all of this synchrounous
requests one by one. But i somehow want to these synchrounous functions asynchrounous all at the same time and wait for them to finnish in order to speed things up. This has to happen inside a synchrounous function. But my understanding is that this doesnt work in javascript, but i would like to hear what you guys have to say.
So my attempt was to add all of these synchrounous requests into asynchrounous promises and then do a Promise.all call. I cant wait for the promise.all().then because the main thread will keep on execute the rest of the code after this main synchrounous thread/function. So i wonder if there is a way to block the main thread in order to wait for these asynchrounous calls
heres a short illustration of what im talking about
var syncfunc = () => {
var getPromise = () => {
return new Promise((resolve) => {
var asyncAjaxRequest = async function() {
doSomeStuff();
resolve();
}
})
}
var promises = [getPromse(), getPromse(), getPromse()];
Promise.all(promises);
console.log('i want this console.log to execute after all promises executed doSomeStuff');
/**
*
* Promise.all(promises).then(() => {
// I cant use this, because its script in other files that will execute if i wait like this
})
*/
}
I know .then will execute when all resolves are done, but i basiacally want to block this synchrounous thread waiting for all other asynchrounous to finish.
If i could i would ofcourse change the structure into my needs, but the problem and the reason why im trying to do this is because im using sitevision framework, and want to add some content to the dom before a print module opens the print window. To call every function synchrounous is just not the way to go, its to slow. Ive also tried to set window.print = null to make the print function disabled, and then add the print function back when promises resolves, but it simply doesnt work
You cannot make an asynchronous operation turn into a synchronous one in plain Javascript (without external code). The event driven JS engine just doesn't work that way.
By definition, an asynchronous operation starts the operation (handing execution off to native code) and then returns back to the interpreter which then continues to execute the code that follows. The native code will add an event to JS event queue when it finishes to allow the interpreter event loop to service the completion of the asynchronous operation. If you were the create some sort of "block" such as a semi-infinite while loop, that would "block" the interpreter from executing more code, you end up in a stalemate. The loop that is blocking the interpreter prevents the JS interpreter from ever getting to the point where it can ever process the event that signals the end of the asynchronous operation. So, you have a loop waiting for something to finish, but the thing it's waiting for can't finish until the loop finishes - stalemate.
So, because of the single threaded event loop nature of the JS interpreter, you can't (purely in Javascript) block waiting for the end of an asynchronous operation.
Pretty much always, the correct design is to refactor the surrounding code/infrastructure to work with an asynchronous operation and asynchronous result (callback or promise).
If this is node.js, there are a couple of horrific hacks that can get you this result, but they block the entire interpreter so are almost never a desired design.
The first option involves writing a custom nodejs plugin (async operations done in native code) that provides a blocking interface that just doesn't return until the operation is done.
The second option involves using the synchronous child_process operations (such as child_process.execFileSync() to create a blocking child process, run your code in that child process and then continue when that process finishes.
Both I could consider pretty bad hacks and pretty much never the desired way to solve such a problem. But, I did want to show you what has to be done in order to block for an asynchronous operation (it has to be moved out of Javascript or out of the process).
If you can't figure out how to solve your real problem with non-blocking, asynchronous operations, I'd suggest you post a new question where you describe in detail exactly what the real problem is and we can help you find an asynchronous design that would work for your situation. If you post a link to the new question in a comment here, some of the people engaged here may check in on the new question and attempt to help.
You could use async/await to solve this. This is how you do it:
async function promiseSolver() {
var getPromise = () => {
return new Promise((resolve) => {
var asyncAjaxRequest = async function() {
doSomeStuff();
resolve();
}
})
}
var promises = [getPromse(), getPromse(), getPromse()];
await Promise.all(promises);
console.log('i want this console.log to execute after all promises executed doSomeStuff');
/**
*
* Promise.all(promises).then(() => {
// I cant use this, because its script in other files that will execute if i wait like this
})
*/
}
Basically, your code will wait until the .all is completed and then will continue with processing. Take into consideration that while the code execution is synchronous, the code will be non blocking.
This question already has answers here:
Promise.resolve().then vs setImmediate vs nextTick
(3 answers)
Closed 4 years ago.
I have an unsolved JS behavior that I cannot understand.
I'm running this code on node v8.4.0.
I'm running this code twice.
First time with f1()
second time with f2()
f2() the result is as expected. 'start' is printed first and then 'end'.
f1() the result is not as expected. 'end' is printed first and then 'start'.
Can someone please explain to me the result of the code below?
const fs = require('fs')
function f1() { return new Promise((resolve, reject) => { resolve() }) }
function f2() {
return new Promise((resolve, reject) => {
fs.readFile('/Users/adi/Downloads/profile.jpg', resolve)
})
}
async function main() {
setImmediate(() => { console.log('start') })
await f1()
console.log('end')
}
main()
//f1 output:
end
start
//f2 output:
start
end
As far as I know, the result should be 'start' and then 'end'.
What am I missing?
The queue with the resolved Promises will be check before the queue with setImmediate(() => { console.log('start') })
Because the f1 resolves immediately, both the callback of the setImmediate and the resolved Promise are added to the event queue at the same time, but at different stages. Resolved Promises have a higher priority then callbacks added with setImmediate
If you use process.nextTick then the callback will be added with an higher priority then setImmediate and start will be logged before end
function f1() { return new Promise((resolve, reject) => { resolve() }) }
async function main() {
process.nextTick(() => { console.log('start') })
setImmediate(() => { console.log('start') })
await f1()
console.log('end')
}
main()
For f2 the reading of the file will involve a longer lasting async task so the setImmediat will be still called before.
So, in your f1() example, you have a race between setImmediate() and the .then() handler of an immediately resolved promise since both will be in the event queue at the time the next event is ready to be processed.
When both are ready to run, one runs before the other because of the internals of how different async things like setImmediate() and promises are coded to work in the node.js implementation of its event loop. Internal to the event loop in node.js, there is a sequence or priority for some different types of asynchronous operations and some go before others if all are waiting to go. It is possible, though difficult, to fully understand which goes before the others, but it is very complicated and it is mostly an implementation detail, not something fully documented by specification.
In this specific case, native promises in node.js use a microTasks queue (there are apparently a couple separate microTasks queues) and they are run before things like setImmediate(), timers and I/O events.
But, in general, it is best to not rely on fully understanding all that and, if you want one thing to happen before the other, don't allow it to be a race between the two inside of node.js. Just code it with your own code to force the sequence you want. This also makes your code more obvious and declarative what order you expect things to be processed in.
If I read your current code, I would think that you purposely set up a race between f1() and setImmediate() and did not care which one ran first because the code is not declarative and does not define a desired order.
For more info on the details of the internals of different types of async operations in the event loop, you can read these references:
Promise.resolve().then vs setImmediate vs nextTick
Promises, Next-Ticks and Immediates— NodeJS Event Loop Part 3
Promises wiggle their way between nextTick and setImmediate
Here's a quote from this last reference article:
Native promise handlers are executed on a microtask queue which is roughly the same as nextTick, so they run before everything else. Pure javascript [promise] implementations should use nextTick for scheduling.
For your f2() example, it's probably just that fs.readFile() takes some finite amount of time so f2() does not resolve immediately and thus isn't ready to run at the same time that setImmediate() is so the setImmediate() runs before f2() resolves.
It's works like this, because Promise is a microtask. Microtasks are executed at the end of call stack, before macrotasks. You can read more here
Threading-wise, what's the difference between web workers and functions declared as
async function xxx()
{
}
?
I am aware web workers are executed on separate threads, but what about async functions? Are such functions threaded in the same way as a function executed through setInterval is, or are they subject to yet another different kind of threading?
async functions are just syntactic sugar around
Promises and they are wrappers for callbacks.
// v await is just syntactic sugar
// v Promises are just wrappers
// v functions taking callbacks are actually the source for the asynchronous behavior
await new Promise(resolve => setTimeout(resolve));
Now a callback could be called back immediately by the code, e.g. if you .filter an array, or the engine could store the callback internally somewhere. Then, when a specific event occurs, it executes the callback. One could say that these are asynchronous callbacks, and those are usually the ones we wrap into Promises and await them.
To make sure that two callbacks do not run at the same time (which would make concurrent modifications possible, which causes a lot of trouble) whenever an event occurs the event does not get processed immediately, instead a Job (callback with arguments) gets placed into a Job Queue. Whenever the JavaScript Agent (= thread²) finishes execution of the current job, it looks into that queue for the next job to process¹.
Therefore one could say that an async function is just a way to express a continuous series of jobs.
async function getPage() {
// the first job starts fetching the webpage
const response = await fetch("https://stackoverflow.com"); // callback gets registered under the hood somewhere, somewhen an event gets triggered
// the second job starts parsing the content
const result = await response.json(); // again, callback and event under the hood
// the third job logs the result
console.log(result);
}
// the same series of jobs can also be found here:
fetch("https://stackoverflow.com") // first job
.then(response => response.json()) // second job / callback
.then(result => console.log(result)); // third job / callback
Although two jobs cannot run in parallel on one agent (= thread), the job of one async function might run between the jobs of another. Therefore, two async functions can run concurrently.
Now who does produce these asynchronous events? That depends on what you are awaiting in the async function (or rather: what callback you registered). If it is a timer (setTimeout), an internal timer is set and the JS-thread continues with other jobs until the timer is done and then it executes the callback passed. Some of them, especially in the Node.js environment (fetch, fs.readFile) will start another thread internally. You only hand over some arguments and receive the results when the thread is done (through an event).
To get real parallelism, that is running two jobs at the same time, multiple agents are needed. WebWorkers are exactly that - agents. The code in the WebWorker therefore runs independently (has it's own job queues and executor).
Agents can communicate with each other via events, and you can react to those events with callbacks. For sure you can await actions from another agent too, if you wrap the callbacks into Promises:
const workerDone = new Promise(res => window.onmessage = res);
(async function(){
const result = await workerDone;
//...
})();
TL;DR:
JS <---> callbacks / promises <--> internal Thread / Webworker
¹ There are other terms coined for this behavior, such as event loop / queue and others. The term Job is specified by ECMA262.
² How the engine implements agents is up to the engine, though as one agent may only execute one Job at a time, it very much makes sense to have one thread per agent.
In contrast to WebWorkers, async functions are never guaranteed to be executed on a separate thread.
They just don't block the whole thread until their response arrives. You can think of them as being registered as waiting for a result, let other code execute and when their response comes through they get executed; hence the name asynchronous programming.
This is achieved through a message queue, which is a list of messages to be processed. Each message has an associated function which gets called in order to handle the message.
Doing this:
setTimeout(() => {
console.log('foo')
}, 1000)
will simply add the callback function (that logs to the console) to the message queue. When it's 1000ms timer elapses, the message is popped from the message queue and executed.
While the timer is ticking, other code is free to execute. This is what gives the illusion of multithreading.
The setTimeout example above uses callbacks. Promises and async work the same way at a lower level — they piggyback on that message-queue concept, but are just syntactically different.
Workers are also accessed by asynchronous code (i.e. Promises) however Workers are a solution to the CPU intensive tasks which would block the thread that the JS code is being run on; even if this CPU intensive function is invoked asynchronously.
So if you have a CPU intensive function like renderThread(duration) and if you do like
new Promise((v,x) => setTimeout(_ => (renderThread(500), v(1)),0)
.then(v => console.log(v);
new Promise((v,x) => setTimeout(_ => (renderThread(100), v(2)),0)
.then(v => console.log(v);
Even if second one takes less time to complete it will only be invoked after the first one releases the CPU thread. So we will get first 1 and then 2 on console.
However had these two function been run on separate Workers, then the outcome we expect would be 2 and 1 as then they could run concurrently and the second one finishes and returns a message earlier.
So for basic IO operations standard single threaded asynchronous code is very efficient and the need for Workers arises from need of using tasks which are CPU intensive and can be segmented (assigned to multiple Workers at once) such as FFT and whatnot.
Async functions have nothing to do with web workers or node child processes - unlike those, they are not a solution for parallel processing on multiple threads.
An async function is just1 syntactic sugar for a function returning a promise then() chain.
async function example() {
await delay(1000);
console.log("waited.");
}
is just the same as
function example() {
return Promise.resolve(delay(1000)).then(() => {
console.log("waited.");
});
}
These two are virtually indistinguishable in their behaviour. The semantics of await or a specified in terms of promises, and every async function does return a promise for its result.
1: The syntactic sugar gets a bit more elaborate in the presence of control structures such as if/else or loops which are much harder to express as a linear promise chain, but it's still conceptually the same.
Are such functions threaded in the same way as a function executed through setInterval is?
Yes, the asynchronous parts of async functions run as (promise) callbacks on the standard event loop. The delay in the example above would implemented with the normal setTimeout - wrapped in a promise for easy consumption:
function delay(t) {
return new Promise(resolve => {
setTimeout(resolve, t);
});
}
I want to add my own answer to my question, with the understanding I gathered through all the other people's answers:
Ultimately, all but web workers, are glorified callbacks. Code in async functions, functions called through promises, functions called through setInterval and such - all get executed in the main thread with a mechanism akin to context switching. No parallelism exists at all.
True parallel execution with all its advantages and pitfalls, pertains to webworkers and webworkers alone.
(pity - I thought with "async functions" we finally got streamlined and "inline" threading)
Here is a way to call standard functions as workers, enabling true parallelism. It's an unholy hack written in blood with help from satan, and probably there are a ton of browser quirks that can break it, but as far as I can tell it works.
[constraints: the function header has to be as simple as function f(a,b,c) and if there's any result, it has to go through a return statement]
function Async(func, params, callback)
{
// ACQUIRE ORIGINAL FUNCTION'S CODE
var text = func.toString();
// EXTRACT ARGUMENTS
var args = text.slice(text.indexOf("(") + 1, text.indexOf(")"));
args = args.split(",");
for(arg of args) arg = arg.trim();
// ALTER FUNCTION'S CODE:
// 1) DECLARE ARGUMENTS AS VARIABLES
// 2) REPLACE RETURN STATEMENTS WITH THREAD POSTMESSAGE AND TERMINATION
var body = text.slice(text.indexOf("{") + 1, text.lastIndexOf("}"));
for(var i = 0, c = params.length; i<c; i++) body = "var " + args[i] + " = " + JSON.stringify(params[i]) + ";" + body;
body = body + " self.close();";
body = body.replace(/return\s+([^;]*);/g, 'self.postMessage($1); self.close();');
// CREATE THE WORKER FROM FUNCTION'S ALTERED CODE
var code = URL.createObjectURL(new Blob([body], {type:"text/javascript"}));
var thread = new Worker(code);
// WHEN THE WORKER SENDS BACK A RESULT, CALLBACK AND TERMINATE THE THREAD
thread.onmessage =
function(result)
{
if(callback) callback(result.data);
thread.terminate();
}
}
So, assuming you have this potentially cpu intensive function...
function HeavyWorkload(nx, ny)
{
var data = [];
for(var x = 0; x < nx; x++)
{
data[x] = [];
for(var y = 0; y < ny; y++)
{
data[x][y] = Math.random();
}
}
return data;
}
...you can now call it like this:
Async(HeavyWorkload, [1000, 1000],
function(result)
{
console.log(result);
}
);