Why isn't this asynchronous? - javascript

I'm trying to get my around callbacks in nodeJS. I thought I had them down until I came across the following example:
function async(callback) {
for(var i = 0; i < 10; i++) {
}
callback();
}
async(function() {
console.log('Expected 2nd Printout');
});
console.log('Expected 1st Printout');
My understanding of node and callbacks would be that after the async function has been invoked, "Expected 1st Printout" would be printed while we're waiting for the async function to finish executing then "Expected 2nd Printout" would be printed when it has finished. However, upon executing this simple program, the opposite occurs.
I'm thinking that because this is a processing task and not a situation where the async function is waiting for a file or listening for some network response that the program is run in a procedural way instead of an asynchronous way?

You can use process.nextTick() to make your function asynchronous. Official documentation:
https://nodejs.org/docs/latest/api/process.html#process_process_nexttick_callback
Once the current event loop turn runs to completion, call the callback function. This is not a simple alias to setTimeout(fn, 0), it's much more efficient. It runs before any additional I/O events (including timers) fire in subsequent ticks of the event loop.
Also try to google for "Understanding the Node.js Event Loop" there are plenty of articles which will help you to understand what happens behind the scene.
Run this code:
function async(callback) {
process.nextTick( function() {
for(var i = 0; i < 10; i++) {
console.log('i = ' + i);
}
callback();
});
}
async(function() {
console.log('Expected 2nd Printout');
});
console.log('Expected 1st Printout');

Related

Does setTimeout() run on a separate thread?

Curious to see whether setTimeout() will be fired up asynchronously, I tried the following test script:
function timedText() {
var x = document.getElementById("txt");
setTimeout(function() {
x.value = "1 second"
}, 1000);
setTimeout(function() {
x.value = "2 seconds"
}, 2000);
setTimeout(function() {
x.value = "3 seconds"
}, 3000);
while (true) {}
}
<p>Click on the button below. The input field will tell you when two, four, and six seconds have passed.</p>
<button onclick="timedText()">Display timed text</button>
<input type="text" id="txt">
Sure enough, clicking the button causes the browser to hang.
This tells me that setTimeout() does not run on a separate thread.
But on a recent interview, the interviewer suggested otherwise... Does that mean that setTimeout() is browser/implementation dependent?
JavaScript is not multi threaded. Well there are WebWorkers that run in a different thread, but that's not really multi threading, more like multiple processes, that communicate with each other.
As of that the while (true) {} will block the js context, because it is an endless loop.
The setTimeout will register a function for later execution. But at no time code will run in parallel for the same context.
A while (true) itself does not necessarily create a blocking loop:
async function sleep(time) {
return new Promise((resolve, _) => setTimeout(resolve, time))
}
async function test(val) {
while (true) {
console.log('in while loop ' + val)
await sleep(1000)
}
}
test('foo')
test('bar')
So you can say with await/async you can create some kind of cooperative multitasking like setup, but still no multi threading
There is no thread in javascript.
setTimeout push just the delegate function insto a stack that will pop for the next pass.
You can read that JavaScript and Threads
This tells me that setTimeout() does not run on a separate thread.
Yes. There is only one thread in JS.
But on a recent interview, the interviewer suggested otherwise... Does
that mean that setTimeout() is browser/implementation dependent?
As far as i know only engine changed from browser to browser. Internal mechanism stands the same - event-loop processor.
When you call setTimeout() typically control is passing back into the host environment (the browser or native node.js code for example). What is happening then is that your callback is being registered in a list of timers to execute in the future. setTimeout() will the return back to your code which will continue executing.
When your script finally completes, control again will return to the host environment which has an event loop, this loop keeps spinning until it's finally time to call your registered callback.
You can actually approximate something like this in JavaScript itself by implementing an event loop just for fun:
class EventLoop {
constructor() {
this.entries = []; // a list of all registered callbacks
this.turns = 0; // keep track of how many turns of the loop we make
}
// Adds a new callback to the list
schedule(callback, condition) {
this.entries.push([condition, callback]);
}
// To removes a callback when it's been called
remove(entry) {
this.entries.splice(this.entries.indexOf(entry), 1);
}
// Run the loop until all registered callbacks were called
// Returns the number of turns it made in the while loop
run(timeout) {
this.turns = 0;
while (this.entries.length) {
for (const entry of this.entries) {
const [condition, callback] = entry;
if (condition()) {
callback();
this.remove(entry);
}
}
this.turns++;
}
return this.turns;
}
}
We can use this EventLoop to implement something like a setTimeout():
// Define a handy log function
const log = ((startTime) => (text) => {
console.log(`t+${(Date.now() - startTime).toFixed(3)}ms: ${text}`);
})(Date.now());
// Create an event loop
const loop = new EventLoop();
// Define a setTimeout using the event loop
const defer = (fn, timeout) => {
const start = Date.now();
const end = start + timeout;
loop.schedule(fn, () => Date.now() >= end);
};
// Schedule some nested events
defer(() => {
log('I run second');
defer(() => {
log('I run third');
defer(() => {
log('I run fourth');
}, 200);
}, 200);
}, 200);
// Log syncronously
log('I run first');
// Start the event loop turning (blocks until all events are complete)
const turns = loop.run();
log(`Loop exited after ${turns} turns`);
// This will log after event loop has finished running
log('I run last');
If you run this with node.js you'll get the following output:
t+0.000ms: I run first
t+200.000ms: I run second
t+400.000ms: I run third
t+600.000ms: I run fourth
t+600.000ms: Loop exited after 6441157 turns
t+600.000ms: I run last
We just created an asynchronous timeout in pure JavaScript with a single thread. Now in reality you wouldn't do this in JavaScript, the event loop would be implemented in native code and hosted in the host environment. An example of such an event loop is libuv used by Node.js. Libuv can do things more efficiently than our toy JS example, it can put the current thread to sleep (technically it doesn't do this, it polls for IO but same concept) so it's not wasting CPU cycles.
Those asynchronous functions are handled by the browser. not the JavaScript engine. there are no threads in JavaScript.

setTimeout blocks eventloop

I was reading an article that stated that to create a nonblocking/asynchronous function, usage of setTimeout is crucial. And I thought that the function that is passed to setTimeout runs in the background. Then I read in another article that setTimeout does block the event loop when function is fired. So, I tried the following function to test.
function getit(cb) {
var i = 0;
setTimeout(function() {
while (i < 200000) { i++; console.log(i); }
cb(i);
} , 1000);
console.log(i);
}
getit(function(message) { console.log(message); });
Apparently, when 1000ms passes and it is time to execute the function, the thread is blocked and my browser freezes. My question is, if asynchronous code is not supposed to block the thread, how is that possible when the function is being executed when time elapses and not in the background? It seems like this is just a delay, but eventually, the function is going to be executed line by line and block the loop anyway. Is there something I'm missing or confused about?
Node.js execution model can be represented by the following code:
function main() {
while(running) {
var timerCb = getNextTimedoutCallback();
if( timerCb ) timerCb(); // execute it
var ioCb = getNextCompleteIOOperationCallback();
if( ioCb ) ioCb(); // execute it
}
}
Everything runs in single thread. IO operations run in worker threads and populate internal queue of completed IO operations. That getNextCompleteIOOperationCallback(); just pulls completed operation from the queue.
In the same way setTimeout() simply pushes function alongside with its end time to the timers queue (ordered by end time). And getNextTimedoutCallback() pulls next expired timeout (if any).
As you see either timer function or IO callback can block the whole thing.
That's known as cooperative multitasking.
You first have to understand that JavaScript, under most contexts is single-threaded. Be it asynchronous or not, once your script start executing, it blocks everything.
Your example above therefore enters the busy while-loop after 1000ms and begin blocking other execution.
To overcome this, the busy block has to be broken down to "yield" (Java terminology) execution cycles for other tasks.
E.g.:
function getit(cb) {
setTimeout(function() {
lessBlockingGetIt(cb);
} , 1000);
}
// Note that this is only less blocking, and much slower
function lessBlockingGetIt(cb) {
// Instead of directly looping, we batch-loop with a setTimeout
var numberOfTimes = 1000; // Reduced the size so it doesn't block like forever
var batchSize = 10;
function executeBatch(start) {
// We use a zero-timeout function is achieve a "yield" behavior so other tasks in the event loop can execute
setTimeout(function(){
var i = start, j;
for(j = 0; i < numberOfTimes && j < batchSize; i++, j++){
console.log(i);
}
if(i < numberOfTimes){
executeBatch(i);
} else {
cb(i);
console.log(i);
}
}, 0);
}
// Start the recursion loop
executeBatch(0);
}
getit(function(message) { console.log(message); });
However, you would notice the execution is much slower, and the browser is apparently less responsive than otherwise true multithreading.
To achieve real multithreading, you would need to use web workers http://www.w3schools.com/html/html5_webworkers.asp

JavaScript execution order of setTimeout() callbacks with different delays

If multiple callbacks are registered at the same time, is it guaranteed that the first callback to be called will be the one with the least delay?
Consider the following code:
function foo(i) {
setTimeout(function () {
console.log(i);
}, i);
}
for (var i = 0; i < 1000; i++) {
foo(i);
}
Is this code guaranteed to output 1-1000 in order?
Please note: This question is not about using equal delays. It has been established that multiple setTimeout() calls with equal delays are not guaranteed to execute in order.
Yes!!
function foo(i) {
setTimeout(function () {
console.log(i);
}, i);
}
for (var i = 1; i <= 1000; i++) {
foo(i);
}
Explanation :
As you are Calling setTimeout it will execute independently doesn't matter how much setTimeout are running or will run,So its dependent on time you call and timing you set.Hope you get this.
I know many of the people have already answered this question. But, most of the people don't know exactly how the event loop works. Even I got it recently. So, I thought it would be helpful to all whoever gets to this post.
setTimeout() function works in accordance with the event callback and render queue. Rendering queue is the reason why it is not guaranteed that your callback would execute after the exact timeout. There are concepts like
call stack,
web apis and
callback queue
You have this below function called multiple times,
function foo(i) {
setTimeout(function () {
console.log(i);
}, i);
}
so the flow would be something like, each call to foo(i) would first go to call stack. Once the call stack reaches to its top (when loop is over), one by one the web api(browser specific)would handle the poped out function from the stack and then it moves to the callback queue when the timeout has reached. Depending on the availability that is, if rendering is not happening, the callback gets executed.
Inside the callback queue the functions are lined up in the order of calling.
So, the order is guaranteed.
A better place to understand the event queue is the below article.
Philip Roberts: What the heck is the event loop?

Delayed Ajax calls to same URL using same data

While waiting for the back end devs to implement a "cancel all" feature, which cancels all tasks tracked by the back end, I am attempting to makeshift it by cancelling each individual task. The cancel REST service accepts an ID in the form of a data object {transferID: someID}.
I use a FOR loop to iterate over an array of IDs that I have stored elsewhere. Anticipating that people MAY end up with dozens or hundreds of tasks, I wanted to implement a small delay that will theoretically not overflow the number of HTTP requests the browser can handle and will also reduce a blast of load on the back end CPU. Here is some code with comments for the purpose of this discussion:
ta.api.cancel = function (taskArray, successCallback, errorCallback) {
// taskArray is ["task1","task2"]
// this is just the latest attempt. I had an attempt where I didn't bother
// with this and the results were the same. I THOUGHT there was a "back image"
// type issue so I tried to instantiate $.ajax into two different variables.
// It is not a back image issue, though, but one to do with setTimeout.
ta.xhrObjs = ta.xhrObjs || {};
for (var i = 0; i < taskArray.length; i++) {
console.log(taskArray); // confirm that both task1 and task2 are there.
var theID = taskArray[i];
var id = {transferID: theID}; // convert to the format understood by REST
console.log(id); // I see "task1" and then "task2" consecutively... odd,
// because I expect to see the "inside the setTimeout" logging line next
setTimeout(function () {
console.log('inside the setTimeout, my id is: ')
console.log(id.transferID);
// "inside the setTimeout, my id is: task2" twice consecutively! Y NO task1?
ta.xhrObjs[theID] = doCancel(id);
}, 20 * i);
}
function doCancel(id) {
// a $.Ajax call for "task2" twice, instead of "task1" then "task2" 20ms
// later. No point debugging the Ajax (though for the record, cache is
// false!) because the problem is already seen in the 'setTimeout' and
// fixed by not setting a timeout.
}
}
Thing is: I know setTimeout makes the containing function execute asynchronously. If I take out the timeout, and just call doCancel in the iterator, it will call it on task1 and then task2. But although it makes the call async, I don't understand why it just does task2 twice. Can't wrap my head around it.
I am looking for a way to get the iterator to make the Ajax calls with a 20ms delay. But I need it to call on both! Anybody see a glaring error that I can fix, or know of a technique?
You must wrap your function setTimeout and pass the id variable into it, like this:
(function(myId, i) {
setTimeout(function () {
console.log('inside the setTimeout, my id is: ', myId);
}, 20 * i);
}(theId, i));
This pattern does not create a unique variable1 for each instance of the loop as one might expect.
function () {
for (var i = 0; i < length; i++) {
var variable1;
}
}
In javascript variables are "hoisted". To quote Mozilla:
"Because variable declarations (and declarations in general) are
processed before any code is executed, declaring a variable anywhere
in the code is equivalent to declaring it at the top."
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var
So it should be re-written as:
function () {
var variable1;
for (var i = 0; i < length; i++) {
}
}
What this means is that after the loop has finished, any asynchronous callbacks that reference this variable will see the last value of the loop.

node.js: while loop callback not working as expected

Knowing that while Node.js is working asynchronously, writing something like this:
function sleep() {
var stop = new Date().getTime();
while(new Date().getTime < stop + 15000) {
;
}
}
sleep();
console.log("done");
...would call the sleep(), block the server for the duration of the while loop (15secs) and just THEN print "done" to the console. As far as I understand, this is because Node.js is giving JavaScript only access to the main thread, and therefore this kidn of thing would halt further execution.
So I understand the solution to this is to use callbacks:
function sleep(callback) {
var stop = new Date().getTime();
while(new Date().getTime() < stop + 15000) {
;
}
callback();
}
sleep(function() {
console.log("done sleeping");
});
console.log("DONE");
So I thought this would print 'DONE' and after 15 secs. 'done sleeping', since the sleep() function gets called and is handed a pointer to a callback function. While this function is working (the while loop), the last line would be executed (print 'done'). After 15 seconds, when the sleep() function finishes, it calls the given callback function, which then prints 'done sleeping'.
Apparently I understood something wrong here, because both of the above ways block. Can anybody clarify please?
Thanks in advance,
Slagjoeyoco
Javascript and node.js are single threaded, which means a simple while blocks; no requests/events can be processed until the while block is done. Callbacks don't magically solve this problem, they just help pass custom code to a function. Instead, iterate using process.nextTick, which will give you esentially the same results but leaves space for requests and events to be processed as well, ie, it doesn't block:
function doSleep(callback) {
var stop = new Date().getTime();
process.nextTick(function() {
if(new Date().getTime() < stop + 15000) {
//Done, run callback
if(typeof callback == "function") {
callback();
}
} else {
//Not done, keep looping
process.nextTick(arguments.callee);
}
});
}
doSleep(function() {
console.log("done sleeping");
console.log("DONE");
});
You are calling sleep right away, and the new sleep function blocks. It keeps iterating until the condition is met. You should use setTimeout() to avoid blocking:
setTimeout(function () {
console.log('done sleeping');
}, 15000);
Callbacks aren't the same thing as asynchronicity, they're just helpful when you want to get a... callback... from an asynchronous operation. In your case, the method still executes synchronously; Node doesn't just magically detect that there's a callback and long-running operation, and make it return ahead of time.
The real solution is to use setTimeout instead of a busy loop on another thread.
As already mentioned, asynchronous execution should be achieved by setTimeout() rather than while, because while will freeze in one "execution frame".
Also it seems you have syntax error in your example.
This one works fine: http://jsfiddle.net/6TP76/

Categories