等同于等待多个异步函数的承诺链是什么?

What's the promise chaining equivalent of awaiting multiple async functions?

我正在研究 promsies 和 async/await 的用法。

我编写了以下代码,它执行以下操作:

  1. 它获取一些数据库的数据(使用Knex.js),
  2. 处理该数据,
  3. 将处理的数据分配到指定的属性。

这 3 个步骤进行了多次(在下面的代码中,进行了两次),并且总是 awaited:

async function run() {
   return await getData();
}
async function getData() {
    let handledData = {};
    handledData.res1 = await knex.select('column1').from('table1').where('column1', '1')
                                 .then(data => handleData(data))
                                 .catch(handleError);
    handledData.res2 = await knex.select('column1').from('table1').where('column1', '2')
                                 .then(data => handleData(data, handledData))
                                 .catch(handleError);
    return handledData;
}
async function handleData(data) {
    let res = [];
    data.forEach(item => {
        res.push(item.column1);
    });
    return res; 
}
function handleError (error) {
    console.log(error);
}

现在,我正在尝试编写 getData 的承诺链等价物,这就是我想出的:

async function getData() {
    let handledData = {};
    let promise = new Promise(function(resolve, error){ resolve(); });
    promise
    .then(function () {
        return knex.select('column1').from('table1').where('column1', '1')
                    .then(data => handleData(data))
                    .catch(handleError);
    })
    .then(function(handled){
        handledData.res1 = handled;
        return knex.select('column1').from('table1').where('column1', '2')
                    .then(data => handleData(data))
                    .catch(handleError);
    })
    .then(function(handled){
        handledData.res2 = handled;
        return handledData;
    })
    .catch(handleError);
    return promise;
}

但这并不完全有效。发生的事情是,在第一个 then return 之后, run 内的 await 结束等待,这导致 run 到 return - 并且然后才执行第二个 then

如何使 promise-chaining 版本像 multiple-await 版本一样工作?

(请随时指出我对 promises/async-await 的任何误解)

knex.select().then() return 是一个承诺,所以你不需要将它包装在另一个承诺中,你只需要设置 then() 和 [=23= 的链] 整个东西。结果将是 getData return 上次的承诺。您可以 return 从 then() 中获得您想要的值,这将使调用者可以使用它。例如:

function run() {
    getData()
    .then(handledData => console.log(handledData) /* do something with data */)
}

function getData() {
    let handledData = {};
    // need to return this promise to callers can access it
    return knex.select('column1').from('table1').where('column1', '1')
    .then(data => handledData.res1 = handleData(data))
    .then(() => knex.select('column1').from('table1').where('column1', '2'))
    .then(data => {
        handledData.res2 = handleData(data)
        return handledData
    })
    .catch(handleError);
}

您也可以将其设置为通过链传递 handledData 对象,但在这种情况下您不需要这样做。

函数handleData()是同步函数,所以你不需要将其设为异步函数。

如果可能,我建议改用 Promise.all,它会使您的脚本 运行 更快,同时使逻辑更清晰:

const getData = Promise.all([
  knex.select('column1').from('table1').where('column1', '1')
    // Simply pass the function name as a parameter to the `.then`:
    .then(handleData)
    .catch(handleError),
  knex.select('column1').from('table1').where('column1', '2')
    .then(handleData)
    .catch(handleError)
])
  .then(([res1, res1]) => ({ res1, res2 }));