开发者问题收集

JS 循环遍历 API 中的 fetch

2020-11-30
57

最近我一直在研究这段代码,我非常 困惑 和沮丧,为什么它会 随机 地对输出进行排序,但后来我意识到它会加载加载速度最快的频道,然后它的 索引 变为 0,下一个加载速度最快的频道变为 1,下一个加载速度最快的频道变为 2,依此类推。

var channels = [
    "UCIgnIPif1LQxkdbvBmGNNuA", // channel 1
    "UC_Qs0JhHoysG4LItMgGMHHQ", // channel 2
    "UC_puGdwVL1kc5VRhaZc6Arw", // channel 3
    "UCQvwHZVCrljzvaLVX33Qaaw"  // channel 4
      ];

var key = "cant share but i will tell you the output of the code"
var subCounts = [];
    function getSubs(id, key){


for(var i = 0; i < channels.length; i++){
 
         fetch('https://www.googleapis.com/youtube/v3/channels?part=statistics&id='+channels[i]+'&key='+key+'')
        .then(response => {
            return response.json()
        }).then(data => {
        
            //name[i].innerHTML = 
            
    subCounts.push(data['items'][0].statistics.subscriberCount);
    

            });
    } // for loop close
}

setTimeout(function(){
 console.log(subCounts);
 // output example: 4, 5, 6, 7
 // another output: 5, 7, 6, 4
 // another output: 7, 4, 5, 6

}, 1500) // good enough for the fetch to load

它只是随机的(先加载的频道排在 前面 )。

但我希望它这样做:
我希望它根据频道的顺序加载。因此,频道 1 需要先加载,然后是频道 2,然后是频道 3,等等。而不是先加载哪个频道。

任何帮助、建议和提示都将不胜感激。

3个回答

假设您可以等待所有请求完成后再开始处理其响应 ,那么 Promise.all 应该可以让您实现您的目标。下面是使用 Promise.all 大致重写的代码:

var channels = [
    "UCIgnIPif1LQxkdbvBmGNNuA", // channel 1
    "UC_Qs0JhHoysG4LItMgGMHHQ", // channel 2
    "UC_puGdwVL1kc5VRhaZc6Arw", // channel 3
    "UCQvwHZVCrljzvaLVX33Qaaw"  // channel 4
];

var key = "cant share but i will tell you the output of the code"
var subCounts = [];
function getSubs(id, key) {

    var requests = [];
    var currentRequest;

    for (var i = 0; i < channels.length; i++) {

        currentRequest = fetch('https://www.googleapis.com/youtube/v3/channels?part=statistics&id=' + channels[i] + '&key=' + key + '');
        requests.push(currentRequest);
            
    } // for loop close

    Promise.all(requests).then((responses) => {
        for (let j = 0; j < responses.length; j++) {
            const currentResponse = responses[j];
            const data = currentRequest.json();
            subCounts.push(data['items'][0].statistics.subscriberCount);
        }
    });
}

setTimeout(function () {
    console.log(subCounts);
    // output example: 4, 5, 6, 7
    // another output: 5, 7, 6, 4
    // another output: 7, 4, 5, 6

}, 1500) // good enough for the fetch to load

请注意,我通常选择使用现代变量声明 let / const - 您通常不会希望将较旧的 var 混合到代码中 let / const ,因此最好更新所有内容,或者不太理想的是,对所有声明使用 var 。此外,这显然没有经过测试,因此可能需要根据您的目的进行一些修改。

如果每毫秒都很重要,并且您需要按顺序处理它们,但一旦它们进入,就需要以不同的方式编写。如果您这样回复,我可以尝试整理一个 POC。

Alexander Nied
2020-11-30

这对于 Promise.all 来说是一个很好的用途 (docs)

类似于:

Promise.all(
    channels.map(
        channel => fetch('https://www.googleapis.com/youtube/v3/channels?part=statistics&id='+channel+'&key='+key+'')
    )
)
.then(Promise.all((responses) => responses.map(response => response.json()))
.then(responses => {
    // now responses is an array in order of the results that you can process as you wish
});

另一种方法是使 subCounts 的长度与 channels 的长度相同,并将 i 第通道结果放置在 subCounts 数组中的索引 i 处。

rb612
2020-11-30

您可以使用异步等待,

var data = await fetch('https://www.googleapis.com/youtube/v3/channels?part=statistics&id='+channels[i]+'&key='+key+'')
        .then(response => {
            return response.json()
        }).then(data => {
            //name[i].innerHTML = 
            });

subCounts.push(data['items'][0].statistics.subscriberCount);
Naga Raj
2020-11-30