【问题标题】:Block code until first forEach loop finishes to use result in another forEach loop in Node阻塞代码,直到第一个 forEach 循环完成以在 Node 中的另一个 forEach 循环中使用结果
【发布时间】:2019-08-02 16:06:59
【问题描述】:

stackoverflow 中有类似的问题,但我找不到特别解决这个问题的问题。我在 Node 中有两个 forEach 循环,一个(这个: s.forEach((su) => { cw1.push(su.courseWorkId); }); )使用前一个的结果进行迭代,但它在第一个完成之前异步触发,所以它总是告诉我“const s”(第一个 forEach 循环的结果)是空的。代码中的其他所有内容都可以正常工作。任何帮助,将不胜感激。

const fs = require('fs');
const path = require('path');
const {google} = require('googleapis');
const keys = require("./file.json");
const sc = require('./jwt.js');
const scopes = sc.scopes;

const j2 = new google.auth.JWT(keys.client_email,null,keys.private_key,scopes,'me@email.com');

const classroom = google.classroom({version: 'v1', auth:j2});
const cl = classroom.courses;

let cl1 =  ['34809075556', '34800434710'];
let cw1 = [];

function getwi(){
  cl1.forEach((ids) => {                                                   
    cl.courseWork.list({courseId:ids}, (e,r) => {
      const s = r.data.courseWork;
      s.forEach((su) => { cw1.push(su.courseWorkId); });
    });
  });
}

getwi(); 

【问题讨论】:

  • 这段代码中哪些操作是异步的?在我看来,您更有可能在填充完成之前尝试使用 cw1 中的值,但您没有显示该代码。请出示该代码。
  • hmm,这里发生的事情是将 forEach 应用于数组 cl1 以获取有关每门课程的所有数据(包括课程作业、教授、ID 等各种内容)。这全部存储在 r.data.courseWork 中,然后第二个 forEach 应该只从 r.data.courseWork 中获取 courseWorkId 并将其放入 cw1 数组中。大量信息存储在 r.data.courseWork 对象中,所以我不能把它全部扔在这里。问题是第二个 forEach 在第一个 forEach 完成填充之前尝试从 r.data.courseWork 获取信息。

标签: javascript node.js google-classroom


【解决方案1】:

异步修改全局变量通常是个坏主意。而是将异步任务包装到一个 Promise 中,然后将该 Promise 解析为您需要的值。

  const getCourseWork = courseId => new Promise((resolve, reject) => cl.courseWork.list({ courseId, }, (err, result) => err ? reject(err) : resolve(result)));

那么你可以得到如下结果:

  Promise.all( cl1.map(getCourseWork) )
     .then(result => console.log("The result is:", result.flat().map(it => it.id)))
     .catch(error => console.error("An error occured:", error));

这样,所有的调用都是并行完成的,因此一个接一个的执行速度更快。

Read on

【讨论】:

  • 乔纳斯,我不得不稍微修改你的答案,但它最终奏效了。我很感激。
  • 为什么不使用util.promisify() 而不是自己手动编写promisify 代码?
  • @jfriend00 因为隐藏了幕后实际发生的事情。通过明确创建承诺,更容易理解 IMO。
  • 不!使用显示的代码,然后执行results.flat()。不要推到承诺之外的区域,那是有风险的(因为有人可能在它准备好之前访问它)
  • 宾果游戏!好的,这行得通。现在我只需要学习更多。谢谢!第二行是: Promise.all( cl1.map(getcw)).then( r => {r.flat().map(c => c.id); })
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多