【问题标题】:JS promise losing data variable [duplicate]JS承诺丢失数据变量[重复]
【发布时间】:2021-04-28 19:58:38
【问题描述】:

我遇到了这个承诺的问题。在 forEach 带有返回用户对象的函数之后,数组(客户端)的变量变为空( [] )。 Ngl 我不知道如何解决这个问题。感谢您的时间:))

function getAdminUsers(adminGroups) {
        return new Promise(async (resolve) => {
          try {
            var clients = new Array();
            console.log(adminGroups);
            await adminGroups.forEach(async (group) => {
              clients[group] = await teamspeak.serverGroupClientList(group);
            });
            console.log('CLIENTS', clients);
            resolve(clients);
          } catch (error) {
            handleServerQueryError(error);
          }
        });
      }

adminGroups 数组:

module.exports = {
  adminGroups: [6, 277, 14, 18, 17, 16, 13, 528, 568],
};

终端输出:

New user connected from 188.146.229.188
[
    6, 277, 14,  18,
   17,  16, 13, 528,
  568
]
CLIENTS []

【问题讨论】:

  • 这个构造 await adminGroups.forEach(...) 不起作用。使用await 的常规循环或查看Promise#all()
  • 请不要这样做new Promise(async ...) 每个async function 都会总是返回一个Promise。那么你需要new Promise() 做什么?另外,在您的特定情况下,带有catch (error) 的部分会造成内存泄漏,因为它永远不会解决您创建的new Promise()
  • @Thomas Never-resolved Promise 不会泄漏内存,它们会像其他所有东西一样被垃圾回收。

标签: javascript node.js arrays promise async-await


【解决方案1】:

forEach() 不是异步的。 It returns undefined,因为你 await 它会自动转换为 Promise,然后立即解析为 undefined。回调已运行,但您无需等待它们完成。

您可以对await 一些Promises 做两种不同的事情:

如果您想让它们一个接一个地运行(例如forEach()),您可以使用for-of 循环。另请注意,我删除了return new Promise(async resolve => ...),因为异步函数总是返回一个承诺,所以这是多余的。

async function getAdminUsers(adminGroups) {
  try {
    var clients = new Array();
    console.log(adminGroups);
    for (const group of adminGroups) {
      clients[group] = await teamspeak.serverGroupClientList(group);
    }
    console.log('CLIENTS', clients);
    return clients;
  } catch (error) {
    handleServerQueryError(error);
  }
}

您可以做的另一件事是使用Promise.all()(或变体,如Promise.allSettled())来并行运行承诺。它可能看起来像:

async function getAdminUsers(adminGroups) {
  try {
    var clients = new Array();
    console.log(adminGroups);
    await Promise.all(adminGroups.map(async group => {
      clients[group] = await teamspeak.serverGroupClientList(group);
    }));
    console.log('CLIENTS', clients);
    return clients;
  } catch (error) {
    handleServerQueryError(error);
  }
}

【讨论】:

  • 在第二个示例中使用 .map 和单独的 clients 数组是多余的,此时它可能只是 clients = await Promise.all...
  • 不是这样,因为在原始代码中并非所有clients 的索引都被分配(可能有漏洞),我想保留它
  • 它们也没有被订购。
  • 啊,我认为这也是一个错误,并且 OP 想要的是更像 .forEach((group, i) => { clients[i] = ...
  • 也许吧,但这不是 OP 的代码:P
【解决方案2】:

您的代码中不需要Promise constructor,您似乎正在使用属性名称而不是索引将项目分配到数组中(forEach((group, idx) 和使用idx 可能是您想要的,或clients.push)。当您可以使用Promise.all on a .map 时,无需创建new Array 并推送到它。

async function getAdminUsers(adminGroups) {
  try {
    const clients = await Promise.all(
      adminGroups.map(async (group) => {
        const list = await teamspeak.serverGroupClientList(group)
        return list
      })
    )
    return clients
  } catch (error) {
    handleServerQueryError(error)
  }
}

【讨论】:

  • adminGroups.map(group => teamspeak.serverGroupClientList(group)) 怎么样?
  • 是的@Thomas - 好点。这肯定会奏效。
  • @Thomas 这行得通,有些人喜欢任何一种写作风格
  • 是的,因为它以任何一种方式返回一个 Promise,并且它被包裹在 Promise.all 中,所以应该可以正常工作。
猜你喜欢
  • 2018-01-31
  • 1970-01-01
  • 2023-03-21
  • 2018-03-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-05
  • 2017-10-09
相关资源
最近更新 更多