Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does .then() work without a promise in JavaScript?

Why does calling the second function .then(notPromise) still pass the argument to the third function .then(promiseC) even though notPromise() is just a regular function?

I thought only promises can be used with .then() but somehow it still executes (and passes the arguments) properly.

promiseA()
    .then(notPromise)
    .then(promiseC);


function promiseA() {
    return new Promise(function (resolve, reject) {
        const string = "a";
        resolve(string);
    });
}


function notPromise(string) {
    const nextString = "b"
    const finalString = string + nextString;

    return finalString;
}


function promiseC(string) {
    return new Promise(function (resolve, reject) {
        const nextString = "c";

        const finalString = string + nextString;

        alert(finalString);
        resolve(finalString);
    });
}
like image 776
jjrabbit Avatar asked Feb 14 '19 18:02

jjrabbit


People also ask

What does then () do in JavaScript?

The then method returns a Promise which allows for method chaining. If the function passed as handler to then returns a Promise , an equivalent Promise will be exposed to the subsequent then in the method chain.

Does promise run without then?

The code inside the Promise constructor runs when the promise is created and it runs synchronously which surprises some people. So even without then() everything still runs.

Does .then return a promise?

When you return something from a then() callback, it's a bit magic. If you return a value, the next then() is called with that value. However, if you return something promise-like, the next then() waits on it, and is only called when that promise settles (succeeds/fails).

What is promise resolve () then?

resolve() The Promise. resolve() method "resolves" a given value to a Promise . If the value is a promise, that promise is returned; if the value is a thenable, Promise. resolve() will call the then() method with two callbacks it prepared; otherwise the returned promise will be fulfilled with the value.


2 Answers

The then() method returns a Promise. See docs.

A promise has a handler method. Once a Promise is fulfilled or rejected, the respective handler function will be called asynchronously. The behavior of the handler function follows a specific set of rules as stated here.

Let's go over them one by one. Here is the code we will inspect side by side. Its nothing special, just a chain of promises returning values.

let sequence = new Promise(function (resolve) {
  console.log('Say 1')
  resolve(1)
})

sequence
  .then(() => {
    console.log('Say 2')
    return 2
  })
  .then(() => {
    console.log('Say 3')
  })
  .then(() => {
    console.log('Say 4')
    return Promise.resolve(4)
  })
  .then(() => {
    return new Promise(function (resolve) {
      console.log('Say 5')
      setTimeout(() => { resolve(5) }, 1000)
    })
  })
  1. returns a value, the promise returned by then gets resolved with the returned value as its value;

In code, this is Say 2, and your original question. When a value is returned, then() returns a Promise which is resolved with the value your returned.

  1. doesn't return anything, the promise returned by then gets resolved with an undefined value;

same as above.

  1. throws an error, the promise returned by then gets rejected with the thrown error as its value;

same as above, except now then() returns a Promise which is rejected with your error.

  1. returns an already resolved promise, the promise returned by then gets resolved with that promise's value as its value;

In code this is Say 4, where the promise has already been resolved. So now then() returns a Promise which is resolved with the value 4.

  1. returns an already rejected promise, the promise returned by then gets rejected with that promise's value as its value;

same as above, except it now rejects.

  1. returns another pending promise object, the resolution/rejection of the promise returned by then will be subsequent to the resolution/rejection of the promise returned by the handler. Also, the value of the promise returned by then will be the same as the value of the promise returned by the handler.

In code, this is Say 5. If you return a promise which has not been resolved yet, then() will return a Promise with the results of your promise i.e. 5.

One thing to note, that I also actually learned recently (suggested by @Bergi in comments) was that the then() method always constructs and returns a new Promise before the chain callbacks have even started to execute. The callbacks that you pass to then() simply tells the promise the value/error that the promise should resolve/reject with.

In summary, that is why then() chaining works even when you don't specifically return a new Promise - because then() method always constructs a new promise behind the scenes and rejects/resolves that promise with the value you returned. The most complex case in above scenarios is when you return a Promise in your callback, in which case your callback promise's results are passed to the then() promise.

like image 129
Rash Avatar answered Nov 15 '22 23:11

Rash


It has to do with the promise chain, it doesn't matter if subsequent calls to then() are not promises, they are all part of the promise chain, the good thing is you can continue chaining promises, which allows you to do several async/promise operations in a row (as your example described), here is a real world example:

  // This is the generic http call
  private callServer(url: string, method: string, body?: any) {
    const uri = env.apiUrl + url;
    const session = this.sessionToken;

    const headers = {
      'Content-Type': 'application/json',
      'credentials': 'same-origin',
      'x-auth-token': session,
    };

    return fetch(uri, {
      method,
      headers,
      body: JSON.stringify(body),
    })
      .then(this.wait) // this is a timer, returns a promise
      .then(this.checkStatus) // this is a sync call
      .then((r) => r.text()) // r.text() is async
      .then((tx) => tx ? JSON.parse(tx) : {}); // this is sync
  }

You can read more about the promise chain here

like image 45
Oscar Franco Avatar answered Nov 15 '22 21:11

Oscar Franco