当我期望它在 forEach 中时,为啥 node.js 不等待? [复制]
Posted
技术标签:
【中文标题】当我期望它在 forEach 中时,为啥 node.js 不等待? [复制]【英文标题】:Why doesn't node.js wait when I'd expect it to inside a forEach? [duplicate]当我期望它在 forEach 中时,为什么 node.js 不等待? [复制] 【发布时间】:2022-01-04 22:29:19 【问题描述】:我正在编写一个节点脚本来从带有https module 的 URL 中提取状态代码。该脚本有一组 URL。我正在使用 forEach 循环遍历它们并进行 https.get() 调用。
我看到的问题是 https 调用似乎不会发生(或者,至少不会触发它们的回调函数),直到整个 forEach 循环完成,它们似乎都在运行。
这是我正在使用的代码:
const https = require('https')
const urls = [
'https://www.example.com/',
'https://www.example.org/',
'https://www.example.net/',
'https://www.example.com/',
'https://www.example.org/',
'https://www.example.net/',
'https://www.example.com/',
'https://www.example.com/',
'https://www.example.com/',
'https://www.example.com/',
'https://www.example.org/',
'https://www.example.net/',
]
function processResponse(response)
console.log(`$Date.now() - response.statusCode`)
urls.forEach((url) =>
console.log(`Getting: $Date.now() - $url`)
https.get(url, (response) =>
processResponse(response)
)
)
输出始终是这样的:
Getting: 1637980537771 - https://www.example.com/
Getting: 1637980537810 - https://www.example.org/
Getting: 1637980537811 - https://www.example.net/
Getting: 1637980537813 - https://www.example.com/
Getting: 1637980537816 - https://www.example.org/
Getting: 1637980537818 - https://www.example.net/
Getting: 1637980537820 - https://www.example.com/
Getting: 1637980537821 - https://www.example.com/
Getting: 1637980537823 - https://www.example.com/
Getting: 1637980537827 - https://www.example.com/
Getting: 1637980537830 - https://www.example.org/
Getting: 1637980537832 - https://www.example.net/
1637980537989 - 200
1637980537992 - 200
1637980537995 - 200
1637980537997 - 200
1637980538005 - 200
1637980538006 - 200
1637980538022 - 200
1637980538023 - 200
1637980538024 - 200
1637980538026 - 200
1637980538032 - 200
1637980538035 - 200
状态码的时间戳总是在 forEach 循环的最后一项之后。这就是我不明白的。
由于有数千个 URL 和损坏的 URL,我想确保每个 URL 都是单独处理的,这样我就不会在事情发生意外时失去进展。
我愿意使用其他模块/方法,但我也想知道这里发生了什么,因为它不符合我的心智模型。
【问题讨论】:
【参考方案1】:您的https.get()
是一个非阻塞函数。它不等待完成。它只是开始操作并立即返回。因此,您的 .forEach()
循环最终会启动所有操作,然后某个时间之后,每个操作都会完成并调用其回调。
如果您想要一个循环等待每个异步操作的循环,那么您应该使用常规的for
循环并使用返回承诺的异步操作。然后,您可以在返回承诺的异步操作上使用await
,它会暂停循环。
例如,您可以通过使用 async/await
和返回承诺的 http 库来做到这一点:
const got = require('got');
const urls = [
'https://www.example.com/',
'https://www.example.org/',
'https://www.example.net/',
'https://www.example.com/',
'https://www.example.org/',
'https://www.example.net/',
'https://www.example.com/',
'https://www.example.com/',
'https://www.example.com/',
'https://www.example.com/',
'https://www.example.org/',
'https://www.example.net/',
]
async function runAll()
for (let url of urls)
console.log(`Getting: $Date.now() - $url`)
try
let result = await got(url);
console.log(`$Date.now() - $result.statusCode`)
catch(e)
console.log(`$Date.now() - $e.message - $e.response.statusCode`);
runAll().then(() =>
console.log("all done");
).catch(err =>
console.log(err);
);
我愿意使用其他模块/方法,但我也想知道这里发生了什么,因为它不符合我的心智模型。
https.get()
是非阻塞的。它开始操作,然后立即返回。这允许您的循环继续进行而无需等待完成。这就是非阻塞异步操作在 javascript 中的典型工作方式。
【讨论】:
以上是关于当我期望它在 forEach 中时,为啥 node.js 不等待? [复制]的主要内容,如果未能解决你的问题,请参考以下文章
当我尝试将数据保存在 txt (java) 中时,为啥我会得到这些符号
当我将 UIView 动画放在不同类的 containerView 中时,为啥我的 UIView 动画不起作用?
当我在网格/面中实现索引时,为啥它会返回 OpenGL 错误?
当我尝试将用户上传的图像保存在视图中时,为啥 ImageField 中的 upload_to 根本不起作用