简体   繁体   中英

How do I resolve this promise after a for-loop of asynchronous code finishes?

Can't seem to figure out how to make this work without the setTimeout. I want to console log my map only after the asynchronous PostgreSQL stuff is finished and the map contains all the key/value pairs it should.

const map = new Map();
pool.query(`SELECT * FROM trips WHERE destination = $1 AND begin_time >= $2 AND begin_time < $3 ORDER BY begin_time`, ['BROWNSVILLE ROCKAWAY AV', '2018-07-18 00:00-04:00', '2018-07-19 00:00-04:00'])
.then(res => {
    return new Promise((resolve, reject) => {
        const { rows } = res;
        resolve(rows);
    });
})
.then(res1 => {
    return new Promise((resolve, reject) => {
        for (let i = 0; i < res1.length; i++) {
            if (res1[i + 1]) {
                pool.query(`SELECT * FROM get_hwtable($1, $2)`, [res1[i].trip_id, res1[i + 1].trip_id]).then(res => {
                    const { rows: hwRows } = res;
                    map.set([res1[i].trip_id, res1[i + 1].trip_id], hwRows);
                }).catch(e => console.log('20', e));
            }
        }
        setTimeout(() => {
            resolve(map);
        }, 8000);
    });
})
.catch(e => console.log('25', e))
.finally(function () {
    console.log(map);
});

You can simply use Promise.all on an array of promises returned by pool.query

const map = new Map();
pool.query(`SELECT * FROM trips WHERE destination = $1 AND begin_time >= $2 AND begin_time < $3 ORDER BY begin_time`, ['BROWNSVILLE ROCKAWAY AV', '2018-07-18 00:00-04:00', '2018-07-19 00:00-04:00'])
.then(({rows}) => rows)
.then(res1 => Promise.all(res1.map((r, i) => {
    if (res1[i + 1]) {
        return pool.query(`SELECT * FROM get_hwtable($1, $2)`, [r.trip_id, res1[i + 1].trip_id])
        .then(res => {
            const { rows: hwRows } = res;
            map.set([res1[i].trip_id, res1[i + 1].trip_id], hwRows);
        }).catch(e => console.log('20', e))
    }                                 
})))
.catch(e => console.log('25', e))
.finally(function () {
    console.log(map);
});
  1. there are unnecessary constructs in your code. In first then( res => {..} ) , there is no need to return a Promise . You can do

```

pool.query().then(res => {
    const {rows} = res;
    return rows;
}.then ....

```

  1. If you are already using async you should use await and use this for the whole code block. Could write a promisified timeout function too.

```

///returns a promise that resolves after `duration`
function timeoutPromise(duration) {
  return new Promise((resolve, reject) => {
    setTimeout(resolve, duration)
  })
}

async function doSomething() {
  const res = await pool.query()
  const {rows} = res;
  for (...) {
    let hwRows = await pool.query(`SELECT * FROM get_hwtable($1, $2)`, [res1[i].trip_id, res1[i + 1].trip_id]);
    map...
  }
  await timeoutPromise(5000)
}

doSomething()

```

  1. Of course the above might make the user wait too long because the asynchronous operations ( let hwRows = await pool.query() ) will be executed one after another. use Array.map to return an array of Promise and then use Promise.all([Promise]) to get the values.

```

async function doSomething() {
  const res = await pool.query()
  const {rows} = res;
  let hwRowsPromises = rows.map((row) => {
    // ...
    // return the promise
    return pool.query(`SELECT * FROM get_hwtable($1, $2)`, [res1[i].trip_id, res1[i + 1].trip_id])
  })
  let hwRowsResults = Promise.all(hwRowsPromises)
  await timeoutPromise(5000)
}

``` 4. Promise.all resolves the values resolved by promises in an array, so you can use convenience like flatten to flatten the array.

```

_.flatten([1, [2, [3, [4]], 5]]);
// => [1, 2, [3, [4]], 5]

```

References

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