2

I am experiencing inconsistent behavior in Google Chrome 60.0.3112.78 (Official Build) (64-bit) when using modern ES6+ async/await, depending on whether I use brackets in the arrow function that returns a Promise. The same happens in Node.js. I am having trouble understanding why.

I understand that this is not how to implement a sleep() function but it is the easiest way to demonstrate. Consider the following example code snippet.

function sleep(ms = 0) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

(async () => {
  console.log('a');
  await sleep(5000);
  console.log('b');
})()

As expected, this will write a to the console, wait 5 seconds and then write b to the console.


Shorter notation using an arrow function to return the Promise.

const sleep = ms => { return new Promise(resolve => setTimeout(resolve, ms)) }

(async () => {
  console.log('a');
  await sleep(5000);
  console.log('b');
})()

As expected this code behaves the same. a and b are written to the console with a 5000 millisecond interval in between.


The following code does not work. The only difference is that I am not wrapping the return of the Promise in brackets on the first line.

const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))

(async () => {
  console.log('a');
  await sleep(5000);
  console.log('b');
})()

In this case, await sleep does not work. In fact, this code does absolutely nothing at all. It does not log anything to the console, not a and not b.

I consider myself fairly experienced but I don't currently understand this. Why do the brackets matter in this particular case? The return value is identical, right? And how come not even the character a is console logged?

Somebody please explain to me exactly and specifically why this is the way it is. Is this a bug or do I just need sleep myself?

Thank you very much.

Jochem Stoel
  • 1,371
  • 1
  • 13
  • 23
  • 3
    Related: [Do you recommend using semicolons after every statement in JavaScript?](https://stackoverflow.com/q/444080/5743988) – 4castle Aug 04 '17 at 22:39
  • @4castle If you refer to [this answer](https://stackoverflow.com/a/1169596/1048572), I recommend to use function *declarations* instead (`function sleep(ms) { return … }`) which don't need a semicolon at all :-) – Bergi Aug 04 '17 at 22:43

1 Answers1

9

It's the semicolon after the arrow function that matters. Write

const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
//                                                                 ^

and it will work. Notice that the next line starts with (, which is a syntactically valid continuation, so ASI doesn't jump in. Your code is parsed and interpreted as

const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))(async () => { … })()

but the function sleep is never called.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • 1
    @Matthew They are, but if you want to omit semicolons and let them be automatically inserted where ever possible, you will [need to put one at the *begin*](http://inimino.org/~inimino/blog/javascript_semicolons) of every line that starts with `(`, `[`, `/`, `+`, `-` or `\``. – Bergi Aug 04 '17 at 22:37
  • Haha yes, but the obscurity of this bug makes me appreciate the extra keystroke. – Wolfie Aug 04 '17 at 22:39
  • Thanks! You're right I can't believe I missed that. Phew! On a sidenote I actually religiously never use semi colons unless there is no other way and believe you can identify good developers by this habit. But I'm biased. Thanks again! :) – Jochem Stoel Aug 04 '17 at 23:44
  • 1
    "The rationale is that it’s easier to always include semicolons than to try to remember when they are or are not required, and thus decreases the possibility of introducing an error." – Jaime Aug 05 '17 at 02:04
  • @JochemStoel I would have guessed that if you had omitted them in the async function as well :-) – Bergi Aug 05 '17 at 08:10
  • @Jaime I disagree. Having to remember every time whether you need to use a semi colon or not keeps you focused as a developer. It forces you into it. Nothing on auto-pilot. – Jochem Stoel Aug 06 '17 at 14:50
  • 1
    @JochemStoel I assume that you waste at least one hour trying to figure out why your code wasn't working as expected. Automatic semicolon insertion (ASI) is considered one of the more controversial features of JavaScript. We should treat ASI as if it didn’t exist. – Jaime Aug 07 '17 at 00:00
  • @Jaime We just should not forget semicolons. Whether at the end of every line, or the beginning of every line (that starts with parenthesis) does not matter. It's entirely a personal preference, and once you get accustomed to either method you should be able to spot missing ones easily. Or let your linter do it, there are rules for both styles. – Bergi Aug 07 '17 at 00:39
  • @Bergi, would you mind updating your answer to include OP's code with a leading semicolon before the IIFE? – Mihail Malostanidis Mar 03 '18 at 15:57
  • @MihailMalostanidis No, isn't including the part that was fixed enough? – Bergi Mar 03 '18 at 16:01