2

I'm trying to fully understand the concepts of async and promises for more than a year, but I still can't grasp everything about it.

Most of the Promises docs are about 'non blocking' and example codes simulate long requests with a setTimeout along this way:

console.log('foo1');
let promiseA = new Promise(resolv => {
  setTimeout(() => resolv('finished'), 1000);   
})
promiseA.then(answer => {
  console.log(answer);
});
console.log('foo2');

which yields to

"foo1"
"foo2"
"finished"

But isn't this mixing two different concepts at once ? As I understand, setTimeout functions are browser/runtime functions, setTimeout precisely triggering an internal counter in the browser thread, your callback function being re-added to the JavaScript engine at the end of the timeout through the macrotask queue, thus allowing your js below the call the function to still execute.

But what about examples where no setTimeout is used? Consider this:

let promiseA = new Promise(resolv => {
  uselesscounter = 0;
  for(let i = 0; i < 1000000000; i++) {
    uselesscounter+= 1;
  }
  resolv('finished');
})
promiseA.then(answer => {
  console.log(answer);
})
console.log('foo2')

From the top example, we might think that we are going to have "foo1", "foo2", then the loop will take time and we would have the "finished" a couple seconds later. It is not what is happening. As the executor code is executed directly (and not using any browser api) it is blocking the "foo2" underneath, despite in the end the resolving callback being added to the microtask queue and displayed after "foo2".

So, does a callback like that, which do not use browser api functions, make sense?

Jason Aller
  • 3,541
  • 28
  • 38
  • 38
Yoann M
  • 21
  • 2
  • 1
    No, a promise executor does not run "elsewhere". There is no multithreading or other parallel execution magically happening - if you block the thread in the executor, you block the thread. – VLAZ Nov 30 '21 at 18:06
  • Assuming you use "browser api functions" as a synonym for any kind of asynchronous host function, I guess the only reason would be if you need to fulfill some API requirements or if you build an API that you expect to be asynchronous eventually. But in these cases you can also use `Promise.resolve(someValue)` directly. It never makes sense to have blocking processes on the main thread. – Felix Kling Nov 30 '21 at 18:09
  • 1
    Promises are only really "useful" as a way of working with asynchronous operations, where the bulk of the work can be delegated to some other thread. Either a worker thread, a system thread (through the runtime (browser/node/etc)) or an entire other machine (through for example an HTTP request). If the work you are doing inside of a promise takes place entirely in JS (and not in a worker), then that code is going to be blocking the main thread at some point. No matter if it is executing inside of a promise block or not. – Olian04 Nov 30 '21 at 18:10
  • @VLAZ The timeout counter does indeed have to run somewhere while the console.log('foo2'); is running right ? I supposed that it was ran in the browser, not in javascript, like a little chunk of C (or the specific browser language) doing the countdown internally, and when its done, telling javascript "i'm done you can execute your function" (adding it to the macrotask queue) – Yoann M Nov 30 '21 at 18:17
  • @YoannM [whether or not an async task blocks the thread depends on the task](https://stackoverflow.com/a/65836893). `setTimeout` does not block ever. Other examples might be HTTP calls or workers - if the operation is done outside the main thread, then it's non-blocking. But if you have a loop, that is not transformed from blocking to non-blocking code by virtue of putting it in a promise executor. – VLAZ Nov 30 '21 at 18:20
  • "*Does promises only makes sense when the executor uses a web browser/runtime api?*" - yes. Promises are a notification mechanism for this that are already natively asynchronous, not some kind of worker thread for making synchronous code run asynchronously. – Bergi Nov 30 '21 at 20:00
  • @YoannM `setTimeout` is not implemented using a countdown. It's either implemented in the event loop itself which `sleep()`s while idle until the next scheduled timer event, or through an asynchronous OS API which notifies the process once the signal time is reached. – Bergi Nov 30 '21 at 20:05
  • @Bergi Thanks. So is it right to say that functions like setTimeout are a special kind of functions that works in 'parralel' and takes a callback that is going to be "recalled" asynchronously ? – Yoann M Nov 30 '21 at 21:14
  • @YoannM Yes, asynchronous functions are special, you cannot write something like that yourself. It needs some kind of native integration into the event loop. – Bergi Dec 01 '21 at 00:42

1 Answers1

1

Promises are useful to use when waiting for some data or a signal of some kind from outside of the code itself, such as api calls and whatnot.

If your code is entirely self contained then there will be no performance gains using promises.

In your second example the code runs as expected, because promises don't execute "later". In a promise the code will keep on running until encountering an asynchronous operation that doesn't execute in the current context (thread, worker, etc..), when that happens it will not block while waiting for the result, but will run the lines following the promise until the result of the promise is requested (by using await for example), and when that happens your runtime will return the result of the promise if available, or block your program until a result is available.

In your case contents of the promise are all synchronous and therefore blocking.

  • 1
    Ok I think I'm getting the hang of it. But still a little troubled. I must lack the vocabulary. Can we say my promise (the 2nd one) is 'synchronous' because it's not calling an asynchronous function? Well can we say at all that a promise "is" (or is not) asynchronous ? I'm I right to think that from a Javascript developer *only* standpoint, we cannot write "asynchronous function" because an asynchronous fonction uses worker/thread outside of the context ? – Yoann M Nov 30 '21 at 21:04
  • 1
    @YoannM "*can we say at all that a promise "is" (or is not) asynchronous*" I'd say this is the wrong question to ask. A promise is *only* a notification mechanism for some task. It is not inherently synchronous or not. Although it usually doesn't make much sense to use it for synchronous tasks. As a notification mechanism it doesn't tell you anything about what the underlying task is. With that said, having a synchronous task that returns a promise is *very likely* a mistake or bug. It's exceptionally rare to need a promise in these cases. – VLAZ Nov 30 '21 at 21:30
  • @YoannM For terminology, I'd use "a promise that is immediately resolved", where "immediately" means "in synchronous code". – Bergi Dec 01 '21 at 00:44
  • 1
    @YoannM Using promises or async functions just tells the runtime (node, browser, etc..) that the result of that promise is not immediately required, and not to block (wait) on the result of any function calls in the promise that run outside the current context (thread). So any code that you write that runs in the current context will be evaluated immediately, and putting that code in a promise or an async function won't change that, it will only delay returning the results of that promise. So such uses of promises are of no use performance wise. – Ahmad AlHallak Dec 01 '21 at 06:39
  • 1
    @YoannM As to your second question, you can write a truly async function using timeouts for example. Suppose you are expecting a file being created, and you want to read the contents of that file when it's created, and there was no async functions to do that. you would make a promise that uses setInterval to check the existence of the file, clearing the interval when it's found and resolving the promise with the contents of the file. Without promises you would block the rest of your code even if the result wasn't immediately required, or you would have to use a callback instead. – Ahmad AlHallak Dec 01 '21 at 06:52