Mongoose eachAsync with async function = 内存泄漏?

ken*_*tor 3 mongoose node.js

我不确定这是猫鼬的错误还是我做错了什么。一旦我在游标上迭代时开始使用异步函数,eachAsync我就会遇到内存泄漏(快速上升到 4GB 然后崩溃)。在尝试了一些事情之后,我注意到如果我不使用异步函数作为回调就不会发生这种情况。

无内存泄漏:

const playerCursor: QueryCursor<IPlayerProfileModel> = PlayerProfile.find({}, projection).lean().cursor();
    await playerCursor.eachAsync(
      (profile: IPlayerProfileModel) => {
        return;
      },
      { parallel: 50 }
    );
Run Code Online (Sandbox Code Playgroud)

内存泄漏:

const playerCursor: QueryCursor<IPlayerProfileModel> = PlayerProfile.find({}, projection).lean().cursor();
    await playerCursor.eachAsync(
      async (profile: IPlayerProfileModel) => {
        return;
      },
      { parallel: 50 }
    );
Run Code Online (Sandbox Code Playgroud)

显然上面的代码没有任何意义,但我需要在函数内执行异步操作。

题:

是什么导致内存泄漏/如何避免它?

Tho*_*ire 5

它与async函数的工作方式有关。

引用文档:

当 async 函数返回一个值时,Promise 将使用返回值进行解析。

意思是,函数返回的async值将自动包装到Promise.

在您的第一个代码示例中,您的代码返回,undefined而在第二个代码示例中,您的代码返回Promise.resolve(undefined).

是什么导致内存泄漏?

我没有看mongoose代码,但文档指出:

如果 fn 返回一个承诺,将在迭代下一个承诺之前等待承诺解决。

由于您的第一个示例没有返回 a Promise,我认为您的回调是一次性对每个结果执行的,而不是按顺序执行的。

我怎样才能避免它?

我建议async/wait您在第二个代码示例中使用它。

查看代码后(自己寻找答案),如果提供了不返回承诺eachAsync的回调,则会尽可能快地运行回调。

这一行是执行回调的地方。下一行检查它是否是 a Promise,如果不是,则立即执行 callback这有效地eachAsync在下一个结果上调用您的回调。如果您的回调有任何类型的异步操作但立即返回,那么您最终会同时运行成千上万个异步操作。

最重要的是,你设置的选项parallel,以100使它执行eachAsync并行回调的一百倍

这不是一个错误,mongoose因为在某些情况下需要这种行为并且它确实提供了使用Promise. 文档应该提到使用不返回Promise.

更进一步,express使用next中间件回调来对它们进行排序。