javascript - 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"
)
);
})();
}
}
}
}
}
}
}
})();
解决方案
我认为如果您摆脱本节的第一行和最后一行,您将大部分时间到达那里
(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 可能不介意每次迭代都这样做,所以这不是您要寻找的问题。
推荐阅读
- javascript - 为什么要在 Node js 中使用消息队列?
- python - 如何为 nlp 任务清理 20newsgroup 数据集
- python - 模块化 PyTest
- c - void* 与 char* 具有相同的表示和内存对齐是什么意思?
- python - 如何定义输入为列名的函数?
- windows - 拒绝连接到“blob:http://XXX”,因为它违反了以下内容安全策略指令:“connect-src 'self'
- node.js - 仅 http cookie Node.js,React 的会话管理问题
- php - json 文件到 mysql 数据库插入为“数组”的列
- aws-lambda - AppSync 与 AWS4 和混合身份验证类型(UserPools 和 IAM)
- firebase - Firebase 扩展删除用户数据不适用于 {DEFAULT} 存储桶