首页 > 解决方案 > Node/Javascript 循环同步

问题描述

我已经关注了多篇关于使用 async / await 的帖子和指南,尝试了多个同步请求库,我尝试了 Promise,然后是块,回调,使用常规循环而不是 foreach 循环,但我已经没有想法了。

此代码调用 Zoom API 以获取我要下载的云记录列表。每个用户可以有 100-200 个,并且它们是大文件,因此我的端或 Zoom 端可以处理的连接数量是有限的,而不会出现可理解的“RequestError:socket hang up”。

由于 Zoom API 的工作方式,您一次只能获得一个月的结果。所以我循环遍历用户,然后循环数月,然后调用各个 URL 以将流下载到我工作站上的文件。

我想要这段代码做的就是在一个月内处理单个用户的录音,并等待它们全部下载,然后再进入该月,然后最终下一个用户。

谁能建议我如何能够做到这一点?

const fs = require("fs");
const path = require("path");
const http = require("follow-redirects").http;
const https = require("follow-redirects").https;
var syncrequest = require("sync-request");
const got = require("got");
const stream = require("stream");
const { promisify } = require("util");

(async function getFiles() {
  var token  = "TOKEN_HERE";

  var zoomUserIDs;
  var users = ["EMAILS_HERE","EMAILS_HERE"];

  var dates = [
    [9, 2020],
    [10, 2020],
    [11, 2020],
    [12, 2020],
    [1, 2021],
    [2, 2021],
    [3, 2021],
    [4, 2021],
    [5, 2021],
    [6, 2021]
  ];

  var path_to_save = "";
  var folder_name = "";

  //Loop over list of users
  for (const user of users) {
    console.log(user);
    folder_name = "output/" + user;
    if (!fs.existsSync(folder_name)) {
      fs.mkdir(path.join("", folder_name), err => {
        if (err) {
          return console.error(err);
        }
        console.log(user + " Directory created successfully!");
      });
    }

    //Loop over months
    for (const date of dates) {
      var url =
        "https://api.zoom.us/v2/users/" +
        user +
        "/recordings?from=" +
        date[1] +
        "-" +
        date[0] +
        "-01&to=" +
        date[1] +
        "-" +
        date[0] +
        "-31&page_size=100";

      //Call Zoom API
      const res = await got.get(url, {
        responseType: "json",
        headers: {
          Authorization: "Bearer" + token
        }
      });

      //Get individual file url
      var reponse = res.body;
      if (reponse.meetings) {
        for (const meeting of reponse.meetings) {
          for (const recording of meeting.recording_files) {
            if (
              recording.recording_type == "shared_screen_with_speaker_view" ||
              recording.recording_type == "shared_screen" ||
              recording.recording_type == "active_speaker"
            ) {
              var path_to_zoom_recording = recording.download_url + "?access_token=" + token;

              //Dowload file    
              const pipeline = promisify(stream.pipeline);
              path_to_save =
                folder_name +
                "/" +
                meeting.topic.replaceAll("/", "_") +
                "_" +
                meeting.start_time.replaceAll(":", "-") +
                ".mp4";

              if (!fs.existsSync(path_to_save)) {
                (async () => {
                  console.log(
                    meeting.topic + " -- " + meeting.start_time + " -- START"
                  );
                  await pipeline(
                    got.stream(path_to_zoom_recording),
                    fs.createWriteStream(path_to_save)
                  ).then(() =>
                    console.log(
                      meeting.topic + " -- " + meeting.start_time + " -- END"
                    )
                  );
                })();
              }
            }
          }
        }
      }
    }
  }
})();

标签: javascriptnode.jsasynchronous

解决方案


我认为如果您摆脱本节的第一行和最后一行,您将大部分时间到达那里

                (async () => {
                  console.log(
                    meeting.topic + " -- " + meeting.start_time + " -- START"
                  );
                  await pipeline(
                    got.stream(path_to_zoom_recording),
                    fs.createWriteStream(path_to_save)
                  ).then(() =>
                    console.log(
                      meeting.topic + " -- " + meeting.start_time + " -- END"
                    )
                  );
                })();

按照您的方式,您的上层不会等待管道。

你也是这个问题接近顶部:

  for (const user of users) {
    console.log(user);
    folder_name = "output/" + user;
    if (!fs.existsSync(folder_name)) {
      fs.mkdir(path.join("", folder_name), err => {
        if (err) {
          return console.error(err);
        }
        console.log(user + " Directory created successfully!");
      });
    }

fs.mkdir也不等待命令。您可以将其包装在 promisify 中,然后也可以等待,就像您在下面使用另一个函数所做的那样。

将它与 async/await 混合起来似乎很奇怪existsSync,但它可能不会受到伤害,因为你一次只发生一件事。最好也承诺fs.exists,然后等待。

在较新的 node.js 中,所有这些方法都有一个预先承诺的版本。我认为你从“fs/promises”导入它们。 https://nodejs.org/api/fs.html#fs_promise_example

此外,对于它的价值,您只需承诺一次功能。这不应该真的在循环中:const pipeline = promisify(stream.pipeline); 但是 node.js 可能不介意每次迭代都这样做,所以这不是您要寻找的问题。


推荐阅读