首页 > 解决方案 > 节点获取循环太慢

问题描述

我有一个 API js 文件,我用 POST 方法调用它,传入一个对象数组,每个对象都包含一个站点 url(大约 26 个对象或 url)作为主体,并使用下面的代码循环遍历这个数组(sites),检查每个对象 url 是否通过添加到 url 来返回一个 json "/items.json",如果是,则将 json 内容推送到另一个siteLists我作为响应发回的最终数组中。

问题是只有 26 个 url,这个 API 调用需要超过5 秒才能完成,我做错了还是它只是fetch在 Node.js 中工作的方式?

const sites内容看起来像:

[{label: "JonLabel", name: "Jon", url: "jonurl.com"},{...},{...}]

代码是:

export default async (req, res) => {

    if (req.method === 'POST') {
        const body = JSON.parse(req.body)

        const sites = body.list  // this content shown above
        var siteLists = []
        
        if (sites?.length > 0){
            
            var b=0, idd=0
            while (b < sites.length){

                let url = sites?.[b]?.url

                if (url){

                    let jurl = `${url}/items.json`

                    try {
                        let fUrl = await fetch(jurl)
                        let siteData = await fUrl.json()
                
                        if (siteData){
                            let items = []
                            let label = sites?.[b]?.label || ""
                            let name = sites?.[b]?.name || ""
                            let base = siteData?.items
                        
                            if(base){
                                var c = 0
                                while (c < base.length){
                                    let img = base[c].images[0].url
                                    let titl = base[c].title

                                    let obj = {
                                        url: url,
                                        img: img,
                                        title: titl
                                    }
                                    items.push(obj)
                                    c++
                                }
                                let object = {
                                    id: idd,
                                    name: name,
                                    label: label,
                                    items: items
                                }
                                
                                siteLists.push(object)
                                idd++
                            }

                        }
                        
                    }catch(err){
                        //console.log(err)
                    }
                }
            
            b++
        }

        res.send({ sites: siteLists })
    }
res.end()
}

编辑:(解决方案?) 因此,似乎带有如下建议的承诺并标记为解决方案的代码在更快的意义上工作,有趣的是它仍然需要超过 5 秒才能加载并且仍然抛出Failed to load resource: the server responded with a status of 504 (Gateway Time-out)错误,因为Vercel,托管应用程序的无服务器功能的最大超时为 5 秒,因此永远不会在响应中加载内容。在本地,我没有超时限制的地方加载速度明显更快,但令我惊讶的是,这样的查询需要这么长时间才能完成,而它应该是毫秒的问题。

标签: javascriptnode.jsapifetchhttpresponse

解决方案


await我在这里看到的最大问题是,fetch在循环开始下一个请求之前,您似乎要完成一个,有效地串行fetch运行它们。如果您重写脚本以同时并行运行所有请求,则可以将每个请求按顺序推送到 a中,然后在它们返回时处理结果。Promise.all

可以这样想——如果每个请求需要一秒钟才能完成,而您有 26 个请求,并且您在开始下一个请求之前等待一个请求完成,则总共需要 26 秒。但是,如果您将它们全部一起运行,如果它们仍然只需要一秒钟来完成整个事情,则只需一秒钟。

伪代码中的一个例子——

你想改变这个:

const urls = ['url1', 'url2', 'url3'];

for (let url of urls) {
    const result = await fetch(url);
    process(result)
}

...进入这个:

const urls = ['url1', 'url2', 'url3'];

const requests = [];

for (let url of urls) {
    requests.push(fetch(url));
}

Promise.all(requests)
    .then(
        (results) => results.forEach(
            (result) => process(result)
        )
    );

推荐阅读