簡體   English   中英

節點獲取循環太慢

[英]Node fetch loop too slow

我有一個 API js 文件,我用 POST 方法調用它,傳入一個對象數組,每個對象包含一個站點 url(大約 26 個對象或 url)作為正文,並使用下面的代碼循環遍歷這個數組( sites ) , 檢查每個對象 url 是否通過向 url 添加"/items.json"返回 json,如果是,則將 json 內容推siteLists我作為響應發送回的另一個最終數組siteLists中。

問題是只有 26 個 url,這個 API 調用需要超過5 秒才能完成,我是否以錯誤的方式進行了操作,或者這只是 Node.js 中fetch工作方式?

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()
}

我在這里看到的最大問題是,在循環啟動下一個fetch請求之前,您似乎在await一次fetch完成,從而有效地連續運行它們。 如果您重寫腳本以同時並行運行所有請求,則可以將每個請求按順序推送到Promise.all ,然后在結果返回時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)
        )
    );

雖然await是一種很好的糖,但有時最好堅持使用then

export default async (req, res) => {
    if (req.method === 'POST') {
        const body = JSON.parse(req.body)
        const sites = body.list  // this content shown above
        const siteListsPromises = []
        if (sites?.length > 0){
            var b=0
            while (b < sites.length){
                let url = sites?.[b]?.url
                if (url) {
                    let jurl = `${url}/items.json`
                    // #1
                    const promise = fetch(jurl)
                        // #2
                        .then(async (fUrl) => {
                            let siteData = await fUrl.json()
                            if (siteData){
                                ...
                                return {
                                    // #3
                                    id: -1,
                                    name: name,
                                    label: label,
                                    items: items
                                }
                            }
                        })
                        // #4
                        .catch(err => {
                            // console.log(err)
                        })
                    siteListsPromises.push(promise)
                }
                b++
            }
        }
        // #5
        const siteLists = (await Promise.all(siteListsPromises))
            // #6
            .filter(el => el !== undefined)
            // #7
            .map((el, i) => el.id = i)
        res.send({ sites: siteLists })
    }
    res.end()
}

在代碼段中查找// #N注釋。

  1. 不要await請求完成。 而是遍歷sites並一次發送所有請求
  2. json()siteData處理后的fetchthen 如果您對siteData的處理計算量更大,那么這樣做會更有意義,而不是在所有承諾解決后才執行所有操作。
  3. 如果您(或您團隊中的某個人)在理解閉包方面遇到一些麻煩,請不要在循環中設置siteData元素的id 我不會深入探討這個問題,但會進一步解決它。
  4. 使用.catch()而不是try{}catch(){} 因為沒有await它不會工作。
  5. 使用Promise.all() await所有請求的結果
  6. 過濾掉那些siteData為假的
  7. 最后設置id字段。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM