67

Searching in the web about async functions, I found many articles using setTimeout to do this work:

window.setTimeout(function() {
   console.log("second");
}, 0);
console.log("first");

Output:

first
second

This works, but is a best practice?

Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
viniciuswebdev
  • 1,286
  • 1
  • 11
  • 20
  • 2
    It's certainly the simplest technique. However, if you're actually trying to run the asynchronous task in a separate thread, [web workers](https://developer.mozilla.org/en-US/docs/Web/Guide/Performance/Using_web_workers) are more effective. (HTML 5) – Flight Odyssey Oct 28 '13 at 03:19
  • 3
    @minitech: That's exactly my point (that `setTimeout` runs in a single thread, while web workers do not). They serve different purposes, and often people use `setTimeout` when web workers are really what they're looking for. Without knowing more details about what the OP is trying to accomplish, I'm not sure which is best for this case. – Flight Odyssey Oct 28 '13 at 03:24
  • 1
    Practice? Nevermind that. What's your goal? Tell us that and then we can help you best achieve it. – Joe Simmons Oct 28 '13 at 03:24
  • @FlightOdyssey: Oh. I didn’t quite get the meaning of “more effective” there. :P – Ry- Oct 28 '13 at 03:26
  • Thanks all, I need something to handle localStorage in asynchronous way, the setTimeout was a solution that I found to fix this problem. but I dont know if is the best solution – viniciuswebdev Oct 28 '13 at 03:41
  • Why are you handling localStorage in an asynchronous fashion? – Joe Simmons Oct 28 '13 at 06:43
  • Thanks @JoeSimmons, so, I don't need that my code wait the localStorage write the data, the async way will bring better performance, right? – viniciuswebdev Oct 28 '13 at 13:14
  • 1
    Async wont have better performance. You're just delaying what's going to happen. If your code needs to wait before writing, then sure, keep it. – Joe Simmons Oct 28 '13 at 13:31
  • @JoeSimmons but if my code don't need the data that are storing, will be better run the writing in background, right? thanks! – viniciuswebdev Oct 28 '13 at 14:00
  • @viniciuswebdev async != background – tybro0103 Oct 28 '13 at 15:11
  • Thanks @JoeSimmons, can you give some reference for reading? I really do not understand the difference – viniciuswebdev Oct 28 '13 at 17:47
  • I'm not quite sure what you want to read about... setTimeout? – Joe Simmons Oct 29 '13 at 03:27
  • sorry JoeSimmons, wrong mention, is about background/async @tybro0103 – viniciuswebdev Oct 29 '13 at 13:39

3 Answers3

91

setTimeout(function(){...}, 0) simply queues the code to run once the current call stack is finished executing. This can be useful for some things.

So yes, it's asynchronous in that it breaks the synchronous flow, but it's not actually going to execute concurrently/on a separate thread. If your goal is background processing, have a look at webworkers. There's also a way to use iframes for background processing.

Update:

To further clarify, there's a difference between concurrency/backgrounding and asynchronous-ness. When code is asynchronous that simply means it isn't executed sequentially. Consider:

var foo='poo';
setTimeout(function() {
  foo='bar'
}, 100);
console.log(foo);

The value 'poo' will be alerted because the code was not executed sequentially. The 'bar' value was assigned asynchronously. If you need to alert the value of foo when that asynchronous assignment happens, use callbacks:

/* contrived example alert */
var foo = 'poo';

function setFoo(callback) {
  setTimeout(function() {
    foo = 'bar';
    callback();
  }, 100);
};
setFoo(function() {
  console.log(foo);
});

So yes, there's some asynchronous-ness happening above, but it's all happening in one thread so there are no performance benefits.

When an operation takes a long time, it is best to do it in the background. In most languages this is done by executing the operation on a new thread or process. In (browser) javascript, we don't have the ability to create new threads, but can use webworkers or iframes. Since this code running in the background breaks the sequential flow of things it is asynchronous.

TLDR: All backgrounded/concurrent code happens asynchronously, but not all asynchronous code is happening concurrently.

See Also: Understanding Asynchronous Code in Layman's terms

H. Pauwelyn
  • 13,575
  • 26
  • 81
  • 144
tybro0103
  • 48,327
  • 33
  • 144
  • 170
2

By default, JavaScript is asynchronous whenever it encounters an async function, it queued that function for later. But if you want a pause js for you can do it use promises Case 1: output hello(will not wait for setTimeout) https://jsfiddle.net/shashankgpt270/h0vr53qy/

//async 
function myFunction() {
let result1='hello'
//promise =new Promise((resolve,reject)=>{
setTimeout(function(){ 
resolve("done");
result1="done1";
}, 3000);
//});
 //result = await promise
 alert(result1);
}
myFunction();

case 2: output done1(will wait for setTimeout) https://jsfiddle.net/shashankgpt270/1o79fudt/

async function myFunction() {
let result1='hello'
promise =new Promise((resolve,reject)=>{
setTimeout(function(){ 
resolve("done");
result1="done1";
}, 3000);
});
 result = await promise
 alert(result1);
}
myFunction();
  • If you're already writing asynchronous, there's a really handy way to make this _readable_: `function asleep(delay) { return new Promise(resolve => setTimeout(resolve, delay)); }` — then you can trivially `await asleep(2000);` inline in any `async` function – JamesTheAwesomeDude Apr 19 '21 at 10:09
1
var foo = 'poo';
setTimeout(function() {foo = 'bar'}, 100);
alert(foo);

A small correction to @tybro0103 's answer, during the execution of 'alert(foo)' the value 'poo' will not change because the code was not executed sequentially. The 'bar' value was assigned asynchronously and it will execute only after 100 millisecond, by that time alert will be executed.

The value of foo remains unaltered, during the execution of line alert(foo). And will change later on time. Check @vishal-lia comment.

Vaisakh Rajagopal
  • 1,189
  • 1
  • 14
  • 23
  • 1
    * you meant the value 'bar' will not be alerted because `alert` already triggered `foo` – Paul Jan 10 '16 at 17:08
  • Yes correct, you can easily verify it by executing the same on console. – Vaisakh Rajagopal Mar 03 '17 at 10:53
  • I changed the number value in the setTimeout(..) to 0. It turns out it still prints 'poo' i.e. the value has not changed. Could you please explain why? – Sameer Khanal Dec 18 '17 at 06:34
  • @SameerKhanal The function being invoked by setTimeout will have its own call stack, therefore setTimeout (function() {}, n ) runs when the current stack is cleared and after n milliseconds have passed, if no time to delay is given, setTimeout simply runs as soon as the stack unwinds. try below code, var foo = 'poo'; setTimeout(function() { alert('setTimeout zero code'); foo = 'bar' }, 0); alert('after setTimeout'); alert(foo); Output will be: 'after setTimeout', 'poo', 'setTimeout zero code' – Vaisakh Rajagopal Dec 18 '17 at 15:52
  • 1
    @VaisakhRajagopal ok got it so the setTimeout function runs once the current stack is complete plus the number of milliseconds specified (as opposed to just the milliseconds specified). Thanks! – Sameer Khanal Dec 20 '17 at 00:26
  • 1
    When you say "The value of foo remains unaltered." you are actually confusing people. foo definitely changes to 'bar' but after 100 ms, if you log 'foo' it will still print 'poo' because "function() {foo = 'bar'}" is called after 100ms. You can verify in browser console to check change in value. – Vishal-L Apr 03 '18 at 15:56