You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Fetch API打印Promise结果顺序异常的原因及解决方法

为什么获取的HTML内容打印顺序与URL顺序不一致?如何保证顺序?

问题重现

我通过以下代码批量获取两个网页的HTML内容,但发现打印结果中url2的数据先输出,url1的后输出,和预期顺序相反:

主代码

const links = {"url1" : "https://.......", "url2" : "https://......"};
var responses = [];

for(const [key,value] of Object.entries(links)){ 
    let resp = fetch('https://api.codetabs.com/v1/proxy?quest='+value)
    responses.push(resp);
}

Promise.all(responses)
    .then( htmlfiles =>{
        htmlfiles.forEach(file=>{
            file.text().then(function(data){
                gethtmldata(data);
            })
        })
     })

解析函数

function gethtmldata(html_data){ 
    var parser = new DOMParser();
    var htmldoc = parser.parseFromString(html_data, "text/html");
    console.log(htmldoc); // 先显示url2的数据,再显示url1的
 }

原因分析

Promise.all(responses)确实会按传入Promise的顺序返回resolved结果,也就是htmlfiles数组的第一个元素对应url1的响应,第二个对应url2的响应。但问题出在后续的forEach循环里:

  • 每个file.text()都是独立的异步操作,它们的完成速度取决于网络响应的快慢,和数组顺序无关
  • 哪个text()先完成,就会先调用gethtmldata并打印结果,所以最终顺序会乱

修复方案

要保证顺序,需要把text()的异步操作也纳入Promise.all的控制范围,让返回的结果直接是解析好的文本,这样遍历的时候就能严格按原URL顺序处理:

修改后的代码

const links = {"url1" : "https://.......", "url2" : "https://......"};
const requests = [];

for(const [key, value] of Object.entries(links)){ 
    // 把fetch和text()连起来,形成一个完整的Promise链
    const request = fetch('https://api.codetabs.com/v1/proxy?quest='+value)
        .then(resp => resp.text());
    requests.push(request);
}

Promise.all(requests)
    .then(htmlTexts => {
        // htmlTexts的顺序和原links的URL顺序完全一致
        htmlTexts.forEach(text => {
            gethtmldata(text);
        });
    });

另一种直观写法(使用async/await)

const links = {"url1" : "https://.......", "url2" : "https://......"};

async function fetchInOrder() {
    // 收集所有包含text解析的请求Promise
    const requests = Object.values(links).map(url => 
        fetch(`https://api.codetabs.com/v1/proxy?quest=${url}`).then(resp => resp.text())
    );
    // 等待所有请求完成,结果顺序与原数组完全匹配
    const htmlTexts = await Promise.all(requests);
    // 按顺序处理每个文本
    htmlTexts.forEach(text => gethtmldata(text));
}

fetchInOrder();

这样修改后,htmlTexts数组的顺序和links中URL的顺序完全对应,遍历调用gethtmldata时就会先打印url1的内容,再打印url2的内容。


内容的提问来源于stack exchange,提问作者user19835820

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 15:03:34