【问题标题】: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 都是单独处理的,这样我就不会在事情发生意外时失去进展。

我愿意使用其他模块/方法,但我也想知道这里发生了什么,因为它不符合我的心智模型。

【问题讨论】:

    标签: javascript node.js


    【解决方案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 中的典型工作方式。

    【讨论】:

      猜你喜欢
      • 2019-11-12
      • 2019-03-07
      • 2013-04-14
      • 2021-12-22
      • 2013-08-12
      • 2021-05-17
      • 2014-10-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多