Hacker News new | past | comments | ask | show | jobs | submit login

> But the classic "callback hell" is when you have async code calling other async code. In that case, a callback can absolutely return a meaningful value to the other async callback.

But then it ceases to be a callback? It's a one-shot function called within the context of a callback. A use case promises are particularly good at enabling.




>But then it ceases to be a callback?

No, it is a synchronous callback called in an async context. I think the confusion here is that you think that "callback" and "asynchronous callback" are synonyms when they are not[1]. A callback is simply any function passed into another function to be executed at a later time. An async callback is such a function which will be called asynchronously.

In JS, asynchronous callbacks are not allowed to return values (or well they can return values they just cannot be meaningfully accessed). Synchronous callbacks, however, certainly are.

Yes indeed, promises are incredibly good at un-nesting said synchronous-inside-of-asynchronous code.

[1]: https://en.wikipedia.org/wiki/Callback_(computer_programming...


Can you show me an example of a "synchronous callback" in JavaScript code that is labeled as such in open source code?

Because generally what I call those is "higher order functions." For example, by the definition you've offered Array.map takes a "synchronous callback" and that seems quite wrong.


Do the MDN docs count?

> The then() method returns a Promise. It takes up to two arguments: callback functions for the success and failure cases of the Promise.

Both of these functions may be synchronous, and may return values. Thus

    Promise.resolve(2)
           .then(x => x + 1)
           .then(x => x + 1)
           .then(console.log);
Will print 4, not undefined. The documentation also refers to these as "handler" functions, but uses "callback" interchangeably, although less often.

Generally speaking, "callback" is only used in the context of the function being executed in an async context, but again there's nothing stopping a sync code from being executed in an async context, and indeed this is pretty common (anytime one invokes a promise, as a simple example).

[1]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...


> Both of these functions may be synchronous, and may return values. Thus

That promise chain is not synchronous. You can prove this by putting your code sample and a following console.log("meep") into a function. The console.log("meep") will always fire before your promise's final handler runs, when you call the function. That's because it's scheduled after your calling function returns.

Try it.

> Will print 4, not undefined.

That's indeed true, but it's a special property of promises that you can extend the construction of a callback with `then` calls. You can never return that value to the calling context. Creating the illusion that you can is what async/await is for. The promise context extended the computation to the final callback, which executed the side effect.

It would be a much neater implementation if the underlying resolve/reject functions that construct the promise were synchronously calling the functions supplied by then. That'd be awesome. Sadly, that's not possible with this implementation, because you can then-extend a resolved promise. But I confess I like how algebraic this implementation is.

It's not wrong to call a then-extension a "callback" if it's the final one in the chain. It's computed value is forever discarded, as ultimately is the value of the entire promise. All promises terminate with a callback who's value is discarded.

As I said, Promises are special and expose a continuation monad, in that they're a way to construct callbacks piece-wise. It's a very useful piece of functionality for JavaScript to have and enables the underlying syntactic transformations that make async/await work.


>That promise chain is not synchronous.

The promise chain is executed synchronously in an asynchronous context. You seem to misunderstand this nuance. `x => x + 1` is a synchronous function. It will always execute synchronously and will return a result when it is invoked and block (within its context) until that invocation is complete. However, its calling context may be paused/pre-empted.

Importantly though, the promise won't be pre-empted during the evaluation of a synchronous function:

    function sleep(ms) {
        var start = new Date().getTime(), expire = start + ms;
        while (new Date().getTime() < expire) { }
        return;
    }

    Promise.resolve(0).then(
        (x) => {
            for (i = 0; i < 15; i++) {
                sleep(1000);
                console.log(`doing stuff ${i}`);
            }
        }).then(console.log); 
If you run this in your console and then try to do anything, you will be unable to. You'll be blocked by the asynchronous code (because it never releases). Replace my blocking sleep with setTimeout, a nonblocking alternative, and you'll find that things work normally. You're executing synchronous, blocking code in an asynchronous context.

Promises aren't doing anything magical, they're simply syntactic sugar for flattening otherwise nested chains of this (where +1 is a standin for the action that this specific function is taking):

    f = (cb, v) => cb(v + 1)
which quickly balloons to

    f = (cb, v) => cb(v + 1)
    (v) => (f(console.log, v))
    f((v) => (f(console.log, v)), 1)
    f((v) => (f((v) => (f(console.log, v)), v)), 1)
    
back to something sane:

    Promise.resolve(1)
           .then(f)
           .then(f)
           .then(f)
           .then(console.log)
There's really no major difference between those two constructs (well, promises also provide infrastructure for releasing to another control.

All of those are synchronous functions, executed synchronously, in an asynchronous context, and all of them are called callbacks by what is perhaps the most authoritative source on web programming today.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: