猫鼬异步/等待

Posted

技术标签:

【中文标题】猫鼬异步/等待【英文标题】:mongoose async / await 【发布时间】:2018-08-30 22:10:21 【问题描述】:

我正在使用 mongodb 和 apollo 服务器学习 node js 和 graphql,下面的代码按预期工作,但是我感觉代码可以改进。这是我的 graphql 解析器上的 sn-p:

Mutation: 
...,
createJob: async (parent, args,  Customer, Employee, Job ) => 
  const newJob = await new Job(args).save();
  newJob.assigned.map(async(employeeId) => 
    const assignedEmployee = await Employee.findById(employeeId);
    assignedEmployee.jobsHistory.push(newJob._id);
    await assignedEmployee.save()
  );
  const customer = await Customer.findById(newJob.customer);
  customer.jobs.push(newJob._id);
  await customer.save();
  return newJob;

正如我所说,代码按预期工作,但看着许多等待,我不能停下来想知道是否可以进行改进。任何帮助将不胜感激

【问题讨论】:

为什么你认为很多awaits 会不好? 无论调用createJob 是否理解它返回一个承诺并相应地处理它? (map 肯定不会,所以这是个问题——就像使用 map 而不对它返回的数组做任何事情一样。) 实际上你甚至错过了一个:assigned.map(…) 内部创建的承诺永远不会等待。您需要将其包装在 await Promise.all(…) 中。 【参考方案1】:

多个awaits 只是async/await 的本质。你必须标记每一个你等待异步操作发生的地方。

该代码的主要问题是您忽略了map 的返回值,因此忽略了您传递mapasync 函数创建的promise 的结果。 任何当您调用map 并且不对它的返回值做任何事情时,您就知道您使用了错误的工具(当您不需要数组@987654329 时使用forEach @returns) 或做其他错误。

假设您希望员工更新并行运行,并且您希望在更新客户之前等待所有更新完成,您希望 await Promise.all(...) 数组 map 返回:

createJob: async (parent, args,  Customer, Employee, Job ) => 
  const newJob = await new Job(args).save();
  await Promise.all(newJob.assigned.map(async(employeeId) =>     // ***
    const assignedEmployee = await Employee.findById(employeeId);
    assignedEmployee.jobsHistory.push(newJob._id);
    await assignedEmployee.save();
  ));
  const customer = await Customer.findById(newJob.customer);
  customer.jobs.push(newJob._id);
  await customer.save();
  return newJob;

但大概不需要在找到客户之前等待员工更新,因此我们可以通过在员工更新的同时搜索客户来稍微改进:

createJob: async (parent, args,  Customer, Employee, Job ) => 
  const newJob = await new Job(args).save();
  const customerPromise = Customer.findById(newJob.customer);     // ***
  await Promise.all(newJob.assigned.map(async(employeeId) => 
    const assignedEmployee = await Employee.findById(employeeId);
    assignedEmployee.jobsHistory.push(newJob._id);
    await assignedEmployee.save();
  ));
  const customer = await customerPromise;                         // ***
  customer.jobs.push(newJob._id);
  await customer.save();
  return newJob;

【讨论】:

感谢您的详细回答,我想我的痒是由于该地图操作员缺少返回!只是一个快速的,我似乎看不出你的第一个代码和第二个代码之间的不同。第二个代码似乎与第一个代码运行相同,除了将 Customer promise 分配给一个 const @scubadude:第一个开始所有员工的工作,等待它完成,然后找到客户,更新并保存。第二个开始寻找客户,在运行时启动所有员工工作,等待所有员工工作完成,等待寻找客户完成,然后更新客户。正如我在回答中所说,它运行查找客户的操作与员工操作并行而不是在他们之后连续运行,可能会节省几毫秒的经过时间。 :-) 感谢详细解答

以上是关于猫鼬异步/等待的主要内容,如果未能解决你的问题,请参考以下文章

猫鼬 findById 的异步/等待行为

将回调代码改进为异步等待猫鼬

在猫鼬中执行 CRUD 操作时异步/等待

带有异步操作的猫鼬游标

NodeJS,从异步等待中获取返回值

带有异步队列和瀑布的猫鼬