NodeJS中的等forEach的逻辑都执行完

先贴代码

const urls = torrentParser.urls()
const peers = []

let count = 0
await new Promise( (resolve) => {
    urls.forEach( async (url) => {
        try {
            const res = await getPeers(url, torrentParser.infoHash(), torrentParser.size(), 15 * 1000)
            for (const peer of res.peers) {
                peers.push(peer)
            }
        } catch (e) {
            logger.error(e)
        } finally {
            count += 1
            if ( count === urls.length ) {
            resolve()
            }
        }
    })
})

这段代码要实现的逻辑是

 

我有很多urls,我想一下子访问所有的urls,然后得到结果,这里的结果是peers的信息。

 

我不想用for loop,因为我的getPeers是写成了同步函数的概念(要么返回结果,要么timeout),所以如果用for loop的话,就要一个一个url的访问,一个一个urlblocking

 

所以就用forEach了。但是我希望我接下来的逻辑是要等所有的request都完成了才进行。这里就又用到了promise。新建一个promise,然后await住它,就是要等它要么reject(),要么resolve()。这里没有要抛出错误,就没用reject,只用了resolve。等到所有的request都返回了,我就可以resolve了。一开始的方案是可以使用forEachindex参数,当index参数等于array的长度减一的时候就可以resolve这个promise了。但是后来发现因为有些request会有错误,会跑到catch中去。所以就引入了finally,在finally里面我自己累计下返回的request数量,当累计到了所有的request后,就resolve了。因为无论try还是catch都要执行finally的逻辑。

 

理解的核心还是nodejs异步单线程的编程语言

即使感觉forEach好像是同时array里面所有的element就同时处理。(这里不是golang的协程,或者c++的多线程,它们是真的同时)。实际上,还是所有的element的处理是一个一个的处理,不同的是,不是处理完一个再来下一个,而是如果blocking了,就进行下一个,然后所有处理好的结果再排队在一个callback的结果队列中,一个一个的再被处理。

此话题在stack overflow有被讨论

https://stackoverflow.com/questions/38406920/best-way-to-wait-for-foreach-to-complete/60646112#60646112

此代码的完整代码在这里

https://github.com/tw7613781/bittorrent/

 

posted @ 2020-03-12 10:06  唐玮  阅读(2655)  评论(0编辑  收藏  举报