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

如何延迟JS Promise实现JSON串行发送 避免并发500报错

问题根因

fetch 是异步非阻塞API,当前循环逻辑在攒够单批次15000行后,发起fetch请求不会等待请求响应完成,就会直接进入下一轮循环攒下一批数据、发新的请求,最终所有批次请求几乎在同一时间并发打到PHP后端,后端并发承载不足时就会出现批次截断、500错误。
另外原代码还有两个隐性问题:

  • resp.text 是方法不是属性,需要加()调用才能拿到后端返回的文本内容
  • 读取完Excel就立刻弹出Ready提示,此时实际数据还没开始上传,提示时机错误
实现串行批次发送的修改方案

核心用async/await语法改造异步逻辑,强制等待上一批次请求拿到后端成功响应后,再启动下一批次的发送,具体改动点:

  • 给ProcessjsonBud函数加async关键字,允许内部使用await等待异步操作
  • 发起fetch的位置加await,阻塞当前逻辑直到请求完成
  • 增加错误中断逻辑,某一批次请求失败时直接终止后续批次发送,避免脏数据
  • 修正提示时机,等所有批次全部上传完成后再弹出成功提示
  • 修正原代码中resp.text()的调用错误(原代码漏写括号,拿不到后端返回内容)
修改后可直接运行的代码

首先是Excel读取上传部分的代码(修正了提示时机):

let selectedFile;

document.getElementById('importBUDid').addEventListener('change', (event)=>{
    selectedFile = event.target.files[0];
});

document.getElementById('uploadBud').addEventListener('click', async ()=>{
    let jsonObj;
    if (selectedFile) {
        let fileReader = new FileReader();
        fileReader.readAsBinaryString(selectedFile);
        fileReader.onload = async (event)=>{
            let dato = event.target.result;
            let workbook = XLSX.read(dato, {type:"binary"});
            workbook.SheetNames.forEach(sheet => {
                jsonObj = XLSX.utils.sheet_to_row_object_array(workbook.Sheets[sheet]);
            });
            // 等待所有批次上传完成后再弹提示
            await ProcessjsonBud(jsonObj);
            alert('所有数据上传完成');
        }
    }
}); 

然后是改造后的批次发送逻辑:

async function ProcessjsonBud(dt1){
    let d= new Date();
    let TxtName = [d.getFullYear(),
                d.getMonth()+1,
               d.getDate()].join('_')+'_'+
              [d.getHours(),
               d.getMinutes(),
               d.getSeconds()].join('_');
               
    let Flagfiletxt = true; // 第一批次传true,通知PHP创建存储文件
    const BATCH_SIZE = 15000; // 单批次行数,抽成常量方便后续调整
    let jsonaux = [];

    const rowsavailables = dt1.length;
    
    for(let i = 0; i < rowsavailables; i++){
        jsonaux.push(dt1[i]);
        
        // 攒够单批次大小,或者已经到最后一行,就发送当前批次
        if (jsonaux.length === BATCH_SIZE || i === rowsavailables - 1){
            console.log('当前发送批次行数:', jsonaux.length);

            let data = new FormData();
            let jsonBlob = new Blob([JSON.stringify(jsonaux)], {type: "application/json"});

            data.append("datajson", jsonBlob);
            data.append("Flagcreartxt", Flagfiletxt);
            data.append("TxtName", TxtName);
            
            try {
                // 等待当前批次请求完成,才会继续走后续逻辑
                const resp = await fetch("model/importBud.php", {
                    method: "POST",
                    body: data
                });
                if(!resp.ok) {
                    throw new Error(`批次请求失败,状态码:${resp.status}`);
                }
                // 正确调用text()方法拿返回结果
                const resText = await resp.text();
                console.log('批次处理成功,返回内容:', resText);
            } catch (err) {
                console.error('上传出错,已终止后续批次发送:', err);
                alert(`上传失败:${err.message}`);
                // 出错直接抛错终止整个流程
                throw err;
            }

            // 批次发送成功后再重置参数,准备下一批
            Flagfiletxt = false;
            jsonaux = [];
        }
    } 
    
   return true;
}
额外优化建议
  • 如果20万条数据拆分后批次较多,可以在前端加进度条提示,每完成一个批次更新一次进度,用户体验更好
  • PHP端建议每处理完一个批次就显式返回成功响应,不要等到所有逻辑跑完再返回,避免请求超时
  • 单批次大小可以根据PHP的post_max_size、max_execution_time配置灵活调整,不一定固定15000行

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 06:48:15