javascript - 如何同步运行嵌套的异步方法?

标签 javascript node.js promise

如何将此例程包装在 Promise 中,以便仅在获取所有数据时才解析?

var accounts = [];
getAccounts(userId, accs => {
    accs.forEach(acc => {
        getAccountTx(acc.id, tx => {
            accounts.push({
                'id': acc.id,
                'tx': tx
            });
        });
    })
});

编辑:如果我这样做有什么问题吗?

function getAccountsAllAtOnce() {

    var accounts = [];
    var required = 0;
    var done = 0;

    getAccounts(userId, accs => {
        required = accs.length;
        accs.forEach(acc => {
            getAccountTx(acc.id, tx => {
                accounts.push({
                    'id': acc.id,
                    'tx': tx
                });

                done = done + 1;
            });
        })
    }); 

    while(done < required) {
        // wait
    }

    return accounts;
}

最佳答案

让我们把这个例程放到一个单独的函数中,这样以后更容易重用它。此函数应返回一个 promise ,该 promise 将通过帐户数组解决(我也会尽可能小地修改您的代码):

function getAccountsWithTx(userId) {
  return new Promise((resolve, reject) => {
    var accounts = [];
    getAccounts(userId, accs => {
      accs.forEach(acc => {
        getAccountTx(acc.id, tx => {
          accounts.push({
            'id': acc.id,
            'tx': tx
          });
          // resolve after we fetched all accounts
          if (accs.length === accounts.length) {
            resolve(accounts);
          }
        });
      });
    });
  });
}

唯一的区别只是返回一个 promise 并在获取所有帐户后进行解析。然而,当你有很多嵌套的回调时,回调往往会使你的代码库具有这种“回调 hell ”的风格,并且很难对其进行推理。您可以使用良好的纪律来解决它,但是您可以大大简化它切换到从所有异步函数返回 promise 。例如,您的函数将如下所示:

function getAccountsWithTx(userId) {
  getAccounts(userId)
    .then(accs => {
       const transformTx = acc => getAccountTx(acc.id)
         .then(tx => ({ tx, id: acc.id }));

       return Promise.all(accs.map(transformTx));
    });
}

它们两者是绝对等价的,并且有大量的库可以“promisify”您当前的回调式函数(例如,bluebird 甚至原生 Node util.promisify)。此外,新的 async/await syntax它变得更加容易,因为它允许在同步流程中思考:

async function getAccountsWithTx(userId) {
  const accs = await getUserAccounts(userId);

  const transformTx = async (acc) => {
    const tx = getAccountTx(acc.id);

    return { tx, id: acc.id };
  };

  return Promise.all(accs.map(transformTx));
}

如您所见,我们消除了任何嵌套!它使对代码的推理变得更加容易,因为您可以在实际执行时阅读代码。但是,所有这三个选项都是等效的,因此您可以根据自己的项目和环境选择最有意义的选项。

关于javascript - 如何同步运行嵌套的异步方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47615542/

相关文章:

javascript - 如何从 JS 文件获取变量到 Node JS 文件

ruby-on-rails - 检测点击了哪个反向链接

javascript - 如何使用 Express 跨端口/域共享 cookie

javascript - TypeScript 将类型保存为未定义

node.js - 如何使用 mocha 在 ReactJS 中测试此异步方法调用

javascript - 可能未处理的 promise 拒绝(id : 0) React Native

javascript - 在express js mongoose中发送带有页面渲染的对象

javascript - 声云 CORS

javascript - 如何判断用户是否重复访问?

javascript - jQuery 元素移除