
Let’s make a JavaScript Wait function - dpweb
https://hackernoon.com/lets-make-a-javascript-wait-function-fa3a2eb88f11
======
hdhzy
I don't get what's the point of his article. Promises and async/await are here
for ages. Moreover it does not highlight issues with await such as if you
forget to await a promise you've just introduced a subtle but in your code.
Sounds unlikely? Check out the last snippet in the article (waitForHello(2000)
missing await, doesn't do any harm in this case as there are no code after it
but it's a hidden bug).

~~~
CodeWriter23
I also am confused by using the Pyramid of Doom as a pseudo rationale for
needing this. Pyramid too tall? Use a function call. Nothing at all wrong
with:

    
    
        function multiStepAsyncProcess() {
            hitServer(params, function() {
                multiStepAsyncProcessStep2();
            });
        }
    
        function multiStepAsyncProcessStep2() {
            hitServer(params, function() {
                ...
            });
        }

~~~
rmrfrmrf
Now do it with error handling and recovery.

~~~
xg15
Moreover, async/await allows you to preserve multiple intermediary results
between async steps - which is awkward in both promises and un-nested pyramids
like the OP's:

(not even starting with conditions, loops and recursive calls that contain
async steps...)

Async/Await:

    
    
      async function f(a) {
       var b = await foo(a);
       var c = await bar(a, b);
       return baz(a, b, c);
      }
    

Promises:

    
    
      function f(a) {
       var _b;
       return foo(a)
        .then(b => {
          _b = b;
          return bar(a, b);
        })
        .then(c => baz(a, _b, c))
      }
    

Callbacks:

    
    
      function f(a, done) {
       foo(a, b => bar(a, b, c => baz(a, b, c, done)));
      }
    

Callbacks untangled:

    
    
      function f(a, done) {
       var _b;
       foo(a, step2);
    
       function step2(b) {
        _b = b;
        bar(a, b, step3);
       }  
    
       function step3(c) {
        baz(a, _b, c, done);
       }
      }

------
_Marak_
The callback style pseudo code they posted as an example is not a good example
of callback style JavaScript code.

The first code posted is showing callback style with a nested loop over a
directory listing to perform an image resize using graphics magick. Aside from
the fact the author isn't actually calling any callbacks to indicate a
complete event ( and won't be able to unless they have an async iterator ),
there is a concurrency problem with usage of gm.

You really actually want to a run something like an async eachLimit in order
to set the amount of open GM instances running concurrently or run the risk of
running out of memory / cpu.

The second example using async/await doesn't mention anything about using
async iterators either.

see:

[http://caolan.github.io/async/docs.html#eachLimit](http://caolan.github.io/async/docs.html#eachLimit)

[https://github.com/tc39/proposal-async-
iteration](https://github.com/tc39/proposal-async-iteration)

------
masswerk
A bit OT, but may I suggest for a style guide to not use the shorthand, w/o
brackets, in single-argument arrow functions, as in

    
    
      var wait = ms => new Promise((r, j)=>setTimeout(r, ms))
    

Here, the semantics of "ms" are not resolved by its lefthand side, but only by
its righthand side (i.e., if this was anything but an arrow, "ms" would be a
value assigned to "wait", while here it's the beginning of a functional
construct, spanning over the rest of the line.) Opposed to this, using
brackets for arguments anytime conveys the meaning much more clearly:

    
    
      var wait = (ms) => new Promise((r, j) => setTimeout(r, ms));
    

_Edit:_ The amount of look-ahead introduced by the shorthand syntax is rather
foreign to JS, as is the switch in syntax that goes with the number of
arguments (as illustrated by the example). I'm not convinced that this was the
greatest idea in the history of JS syntax ever.

~~~
ng12
Isn't that always the case? You always need to take into consideration the
evaluation of the rhs. Consider:

    
    
       var wait = ms * foo()
    

And that's not even considering the complexity introduced by the comma
operator. I think the arrow is the key to visually identifying a function, not
the parentheses.

~~~
masswerk
It's really about the arrow operator starting with "=", which is most likely
the beginning of a chained assignment as in

    
    
      a = b = c = 0;
    

Also (as noted in the edit), I'm not the greatest of fans of the syntax
switching with the number of arguments. In the example given, there are two
arrow functions defined, each of them coming in a different appearance, due to
the number of arguments used. Using always brackets, the nature of "ms" and it
being used and passed as an argument would be more striking on first sight.
Ease of understanding and readability aren't just luxury for a codebase.

(The real difference as for pragmatics is this: In any other case, anything on
the righthand side of the first "=" is a value resolved on first execution
whenever the code is hit, while in this case it's a parameter that becomes
evaluated whenever the function defined by this assignment is called – and
this relation isn't resolved without look-ahead. Possible errors introduced by
a sloppy (mis)reading are numerous.)

~~~
ng12
> is most likely the beginning of a chained assignment

I wouldn't think so at all. I almost never do chain assignment in modern
JavaScript but I write functions which return functions somewhat often.

I guess there's a possibility that someone quickly skimming code would misread
=> as =. It hasn't yet happened to me though.

~~~
masswerk
> in modern JavaScript

You are probably right on this – but there's still old code around and ease of
context switching may be a thing. Also, I guess, you can't be too defensive in
your approaches, when setting up a shared codebase that may be around for some
time. (With JS being extended on a yearly basis, we hardly can imagine what
will be around a few years from now.)

 _Edit:_ However, also related to modern JS, another possible counter argument
to mine: With the omission of terminating semicolons and frequent use of
multiline statements determining the semantics has also become a question of
scanning the next line anyway. Look-ahead is now a thing.

------
ajkjk
I love async/await, but it's not because it's "aesthetically pleasing". It's
because having execution jump around from the outer body to the inner
anonymous functions fucks with all my intuition and, especially, with the way
debuggers work.

If I want a series of steps to execute in order, I should be able to write
them down in sequential lines of code, and it's, imo, a historical artifact
that I was ever _not_ able to do that -- because (oops), JS was traditionally
conceived to have sequential lines of code execute immediately after each
other, instead of blocking until they're able to proceed.

That is, it's not required that "single threaded language" _meant_ "non-
blocking execution" and thus _required_ "callbacks and promises to do
asynchronous behavior". It just ended up that way -- and we're finally
(almost) free of it.

~~~
always_good
Thinking that it's a historical accident that everything is async in
Javascript is a fundamental misunderstanding of async-everything.

~~~
ajkjk
Want to elaborate? I disagree, but I'm happy to be corrected. Anyway, what I
said was that it's a historical artifact that JS has a single thread of
execution, and by that I meant, "it was standard to do that at the time that
JS was conceived, so that's how it was done". If you were inventing web
browsers today I don't think you'd ever intentionally choose to do it that
way.

------
throw401
The problem with async await is that it is build upon promises, which sucked
already from the start.

For all those Promises proponents out there ready to burn me down, this is how
you do it in C:

    
    
      delay(1000);
    

And here the amazing Promises with await:

    
    
      var wait = ms => new Promise((r, j)=> setTimeout(r, ms));
      await wait(1000);
     

Is it really that difficult to at least abstract this wait function away in
the Javascript language?

~~~
ledriveby
Yes it is. Synchronous calls monopolize the event loop so everything -
including page interactions - freeze until the control flow finishes busy-
waiting. Yay, single threading.

~~~
marcosdumay
Everybody solves that by having multiple threads (either at the OS or runtime
level), so you can run in parallel the stuff that don't conflict with each
other.

~~~
rmrfrmrf
Do you, as a user, want web pages to spawn multiple threads on your machine?

~~~
marcosdumay
Well, first, you are completely ignoring the possibility of runtime threads.

Also, why not? Do you see any problem with that? As long as their numbers are
limited, I don't see any problem?

------
lootsauce
The longer I see people debate the value of promises and their obscured use
via async/await vs callbacks I am more assured of the value of simple
callbacks. If you are experiencing callback hell you have bigger problems than
callbacks. If you love promises great! But please don't force them on me or
I'll find another api to use thank you.

~~~
saas_co_de
I haven't heard or read a lot of debate claiming that callbacks are superior
to promises and async/await.

From the people I work with and everything I have read there is almost
universal agreement that promise based code is easier to work with than
callback based code and async/await is superior to both.

Callbacks do have superior performance, so if you are writing some really
performance sensitive code then it might be worth using them, but like all
optimization techniques that should only be done if the case truly requires
it. Most don't.

------
sparrish
Promises and Async/Await are just too slow. I'll stick with Callbacks.

[https://kyrylkov.com/2017/04/25/native-promises-async-
functi...](https://kyrylkov.com/2017/04/25/native-promises-async-functions-
nodejs-8-performance/)

~~~
GhostVII
Shouldn't we be more focused on which is easier to use though? Even if
promises are slower, they probably aren't going to be a major performance
issue, so I think if you find promises easier to use and less bug-prone, they
are better regardless of preformance.

~~~
untog
> Shouldn't we be more focused on which is easier to use though?

In JS I think this depends a lot on whether you are writing client-side code
or not. Prioritizing developer ease of use over end-user performance is a very
bad habit to get into. But it matters less when writing code that'll run in
Node.

(that said, I'm not at all convinced that the performance difference mentioned
in this article matters a whole lot. It's not actually that significant.)

~~~
GhostVII
> Prioritizing developer ease of use over end-user performance is a very bad
> habit to get into

Why is that? Whenever you use a high level language, you are making
development easier at the cost of end-user performance. Or using a foreach
loop instead of a regular for loop, is usually a bit slower, but makes
development easier and less bug prone. Premature optimisation is the root of
all evil and all that. Obviously at some point you have to prioritise end-user
performance, when making decisions that will have a big impact on performance,
but when making decisions on the level of promises vs callbacks, I don't think
end-user performance should be a priority.

------
saas_co_de
Should mention that Bluebird does this.

[http://bluebirdjs.com/docs/api/delay.html](http://bluebirdjs.com/docs/api/delay.html)

~~~
iEchoic
Yup, Bluebird has allowed for:

    
    
      await Promise.delay(1000);
    

For as long as I can remember. I'm surprised Bluebird isn't more widely-
adopted; it's been way better than native promises for at least 2 years now.
The transform-async-to-module-method plugin with Bluebird is the way to go.

------
johnhenry
I made something like this a while back.
[https://github.com/johnhenry/asynchronous-
delay](https://github.com/johnhenry/asynchronous-delay). It's a useful
pattern.

~~~
johnhenry
Also this: [https://github.com/brummelte/sleep-
promise](https://github.com/brummelte/sleep-promise).

