3

A question asked here before, with the exact same title as this one, was answered with a "You should not use that, use this instead", I am looking to know what it does, not what else could I do, it's about understanding not a simple copy a paste.

My question is quite simple, what is the difference between these three approaches when creating a promise?

const API = (item, fail) =>
  new Promise((resolve, reject) => {
    if (fail) reject(item + ' ...with an error');
    setTimeout(() => resolve(item), 1000);
  });

(async () => {
  const pro1 = Promise.resolve(API('I am inside resolve'));
  const pro2 = Promise.resolve(API('I am inside resolve', true));

  const pro3 = Promise.resolve().then(() => API('I am thenable'));
  const pro4 = Promise.resolve().then(() => API('I am thenable', true));

  const pro5 = new Promise((resolve) => resolve(API('I am a new promise')));
  const pro6 = new Promise((resolve) => resolve(API('I am a new promise', true)));

  const store = [pro1, pro2, pro3, pro4, pro5, pro6];

  const results = await Promise.allSettled(store);

  for (const { status, value, reason } of results) {
    if (status === 'fulfilled') console.log(value)
    else console.log(reason)
  }
})();
Álvaro
  • 2,255
  • 1
  • 22
  • 48
  • 1
    Well if `API` always returns a promise, there's no difference at all. It matters when it returns a plain value or throws an exception instead. – Bergi Oct 11 '21 at 16:54
  • Check [this](https://stackoverflow.com/a/26711782/16602311) answer. – Giusseppe Oct 11 '21 at 17:01
  • @Bergi, so if I do `const pro = API('I am a promise anyway')` would be the same if the function is aways a promise? – Álvaro Oct 11 '21 at 17:36
  • 1
    @Álvaro Yes, if you know that `API` always returns a promise, none of that `Promise.resolve` stuff is necessary – Bergi Oct 11 '21 at 17:46
  • @Álvaro You can write `const store = [API("I'm a new promise")]` without using `Promise.resolve` or other additional Promise wrapping in the case if you call async function or function which returns Promise all the time. But if it's what you've been asking about, then it wasn't clear. And It's better to clarify that, it will help other users. – Paul Rumkin Oct 11 '21 at 19:46
  • No, that's not what I was asking, Bergi just made me see that, but you did answered my question. Thanks – Álvaro Oct 11 '21 at 21:10

2 Answers2

3

The difference is in job to be done. While all of this methods are valid, they have different cost and predictability.

  1. Promise.resolve() produces single resolved Promise instance, and depending on value provided to the call JS engine have information to optimize it. It makes all work to be done in a single call to underlying code of the JS engine (usually C++, but could be Java or WASM). So it's always the best choice.
  2. Promise.resolve().then(() => API(/*...*/)) Produce several Promise instances: one at Promise.resolve() and other at .then() call. It also allocates more memory and make several (3 or more) redundant jumps between JS and the engine. It's hardly optimizable and requires intensive heuristics to be performed to figure out is this call optimizable. It's the worst option.
  3. new Promise((resolve) => resolve(API(/* ... */)) allocates one function and one Promise instance and makes two jumps between JS and the engine. It's harder to optimize this call, due to nature of JS.
Paul Rumkin
  • 6,737
  • 2
  • 25
  • 35
  • 1
    "*The underlying code of the JS engine*" might be written in JS as well - for *better* optimisability and less context switches. – Bergi Oct 11 '21 at 17:47
  • @Bergi Thanks for the addition. I'm agree with you but in this particular case it's near to impossible to outperform Promise.resolve() from JS side. – Paul Rumkin Oct 11 '21 at 18:30
0
Promise.resolve().then() 

In your examples, the then() makes no difference as you just resolve the promise, and get its data.

then() is typically used to chain promises, take this as an example:

Promise.resolve('foo')
  // 1. Receive "foo", concatenate "bar" to it, and resolve that to the next then
  .then(function(string) {
    return new Promise(function(resolve, reject) {
      setTimeout(function() {
        string += 'bar';
        resolve(string);
      }, 1);
    });
  })
  // 2. receive "foobar", register a callback function to work on that string
  // and print it to the console, but not before returning the unworked on
  // string to the next then
  .then(function(string) {
    setTimeout(function() {
      string += 'baz';
      console.log(string); // foobarbaz
    }, 1)
    return string;
  })

Here we chain multiple promises then() off of a previously resolved promise, while maintaining the original data from the first resolve, though in this case we modify it with every new promise.

You can read more about promises and chaining here.

Rawley Fowler
  • 1,366
  • 7
  • 15