遍历查询数组并将结果附加到JavaScript中的对象

时间:2020-06-25 10:57:25

标签: javascript promise

我想从一个对象中的两个数据库查询返回结果。

function route(start, end) {
    return new Promise((resolve, reject) => {
        const queries = routeQuery(start, end);
        var empty_obj = new Array();
        for (i=0; i<queries.length; i++) {
            query(queries[i], (err, res) => {
                if (err) {
                    reject('query error', err);
                    console.log(err);
                    return;
                } else {
                empty_obj.push(res.rows);
            }});
        }
        console.log(empty_obj);
        resolve({coords: empty_obj});
    });
}

这是我现在的代码,查询工作正常,但是由于某种原因,将每个结果放入一个空数组都无法正常工作。当我控制台记录该空对象时,它保持为空。目的是使用包含两个查询结果的生成的对象来解决promise。我正在使用node-postgres进行查询。

res的输出是一个对象:

{
  command: 'SELECT',
  rowCount: 18,
  oid: null,
  rows: [
    { ...

2 个答案:

答案 0 :(得分:0)

我建议您将query函数转换为Promise,以便可以使用Promise.all

// turn the callback-style asynchronous function into a `Promise`
function queryAsPromise(arg) {
  return new Promise((resolve, reject) => {
    query(arg, (err, res) => {
      if (err) {
        console.error(err);
        reject(err);
        return;
      }
      resolve(res);
    });
  });
}

然后,您可以在route函数中执行以下操作:

function route(start, end) {
  const queries = routeQuery(start, end);

  // use `Promise.all` to resolve with 
  // an array of results from queries
  return Promise.all(
    queries.map(query => queryAsPromise(query))
  )
  // use `Array.reduce` w/ destructing assignment 
  // to combine results from queries into a single array
  .then(results => results.reduce(
    (acc, item) => [...acc, ...item.rows],
    []
  ))
  // return an object with the `coords` property
  // that contains the final array
  .then(coords => {
    return { coords };
  });
}

route(1, 10)
  .then(result => {
    // { coords: [...] }
  })
  .catch(error => {
    // handle errors appropriately
    console.error(error);
  });

参考:

希望这会有所帮助。

答案 1 :(得分:0)

您当前面临的问题是由于以下事实造成的:

resolve({coords: empty_obj});

不在回调内。因此,承诺会在调用查询回调并将行推入empty_obj之前解析。您可以通过以下方式将其移至query回调中:

empty_obj.push(res.rows); // already present
if (empty_obj.length == queries.length) resolve({coords: empty_obj});

这将解决所有行被推送时的承诺,但又给您带来另一个问题。回调可能未按顺序调用。这意味着结果顺序可能与queries顺序不匹配。

解决此问题的最简单方法是将每个单独的回调转换为Promise。然后使用Promise.all等到所有承诺都解决。结果数组将具有相同顺序的数据。

function route(start, end)
  const toPromise = queryText => new Promise((resolve, reject) => {
    query(queryText, (error, response) => error ? reject(error) : resolve(response));
  });

  return Promise.all(routeQuery(start, end).map(toPromise))
         .then(responses => ({coords: responses.map(response => response.rows)}))
         .catch(error => {
           console.error(error);
           throw error;
         });
}