简体   繁体   中英

How promises and promise chaining works? [Problem with code]

I'm learning Node.js and trying to properly use the mysql2 module. Because of this, I have recently started researching about promises.

I'm writing a kind of "library", so I can practice all these topics, and while doing that, I got into a problem with promise chaining I can't really understand. Any help is well appreciated!

The problem is the following:

Let's say that I have a query function which fetches the database, process the data and returns a promise, so I can get that data and work with it in some other file.

Now, if I write my query function like this:


query(){
        let p = new Promise((resolve, reject) => {
            resolve("Hello world")
        });


        p.then(data => {
            console.log("Hello world a second time!");
        }).then(data => {
            console.log("Hello world a third time")
        })
        return p;
    }

and I try to "consume" that promise from other file like this:


DBObject.query().then((data) => {
    console.log("Hello world from the other file!");
})

Then the output is in the wrong order, the program prints this:

Hello world a second time!
Hello world from the other file!
Hello world a third time


On the other hand, if I change the code in the first file, and I don't try to separate promise chaining, like this:

query(){
        let p = new Promise((resolve, reject) => {
            resolve("Hello world")
        }).then(data => {
            console.log("Hello world a second time!");
        }).then(data => {
            console.log("Hello world a third time")
        })

        return p;
    }

It works just fine, and it prints:

Hello world a second time!
Hello world a third time
Hello world from the other file!

I don't understand this behaviour, I was thinking that declaring then blocks separately from the promise definition would be the same thing as do promise chaining right when I declare the promise, and it is clearly not like that!

Thanks beforehand for the answers you can give me. Also, It would be great if you could give me some suggestion on how to write code like this correctly. I mean, if I write code that uses promises, what should I return to the user? Another promise? Or just data for they to work with? I would really like writing code that follow the "standard" way of doing things.

Greets to you all! Thank you again.

When you have one Promise, you can chain any number of Promises onto its .then . For example

const p = Promise.resolve();
p.then(() => console.log('then 1');
p.then(() => console.log('then 2');

means that p has two Promises that branch from it when it resolves: 1 and 2 (in addition to the promise p itself).

  p
 / \
/   \
1   2

What you're doing in your first code

let p = new Promise((resolve, reject) => {
  resolve("Hello world")
});
p.then(data => {
  console.log("second");
}).then(data => {
  console.log("third")
})
return p;

is like

"Hello world" = <Promise you return>
    |
    |
    |
  second
    |
    |
    |
  third = <unused Promise expression that the then chain resolves to>

You have two branches: the Promise you're returning resolves when Hello world runs, not when third runs.

On the other hand, when you call .then multiple times on a Promise, the whole expression evaluates to the Promise that resolves when the final .then runs :

let p = new Promise((resolve, reject) => {
  resolve("Hello world")
}).then(data => {
  console.log("Hello world a second time!");
}).then(data => {
  console.log("Hello world a third time")
})

return p;

is like

"Hello world"
     |
     |
'Hello second'
     |
     |
'Hello third' = <Promise you return>

where the returned Promise is the one that resolves right after Hello third runs.

Instead of returning p in the segregated version... return the p.then() chain. The final one will be added to the end of that chain, rather than creating two different chains

then() returns a new promise resolved by any return or undefined if no return

 const query = () => { let p = new Promise((resolve, reject) => { resolve("Hello world") }); return p.then(data => { // from `resolve()` console.log('Then 1: ', data) // return to next then() return ("Hello world a second time!"); }).then(data => { // from previous then() console.log('Then 2: ', data) // return to next then() return ("Hello world a third time") }); } query().then(res => console.log('Final: ', res)) 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM