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

如何在fetch的then函数中访问对应请求对象解决异步循环问题?

解决方案

这个问题本质是异步回调和循环变量的作用域冲突导致的——var声明的变量是函数级作用域,循环里的所有迭代共享同一个变量引用,当异步回调执行时,循环已经走完了,变量早就被替换成最后一个元素的值了。给你几个实用的解决办法:

1. 用let/const替换所有var

这是最简单的方案,let和const是块级作用域,每个循环迭代都会创建独立的变量绑定,异步回调里访问的就是当前迭代的对象:

// 把循环里的var全换成let/const
for (let i = 0; i < expectedRows; i++) {
    let row = myArray[i];
    let customerCode = row['customer_code'];
    let customerName = row['customer_name'];
    let customerBalance = row['customer_balance'];
    
    let callBody = {
        user: 'USER',
        code: customerCode,
        name: customerName,
        balance: customerBalance
    };
    
    let fetchOptions = {
        method: "POST",
        cache: "no-cache",
        headers: {
            "Content-Type": "application/x-www-form-urlencoded",
        },
        redirect: "error",
        referrer: "ux-import",
        body: JSON.stringify(callBody),
    };
    
    const epurl = baseEP + '/customer/create';
    fetch(epurl, fetchOptions)
        .then(response => response.json())
        .then(response => {
            if (response.error === 0) {
                console.log('insert ok');
                insertRows++;
            } else if (response.error == 2) {
                console.log('insert error => update');
                const updateEP = baseEP + '/customer/update';
                // 这里的fetchOptions就是当前迭代的对象,不会被覆盖
                fetch(updateEP, fetchOptions)
                    .then(updResponse => updResponse.json())
                    .then(updResponse => {
                        if (updResponse.error === 0) {
                            console.log('update ok.')
                            updateRows++;
                        } else {
                            console.log('update error: ' + updResponse.msg)
                            errorMessages.push(updResponse.msg);
                        }
                    })
                    .catch(error => {
                        console.log('update failure');
                        errorMessages.push(error);
                    });
            } else {
                console.log('insert error.');
                errorMessages.push(response.msg);
            }
        })
        .catch(error => {
            console.log('insert failure.');
            errorMessages.push(error);
        });
}

2. 用forEach遍历数组

forEach的回调函数本身就会创建独立作用域,每个迭代的变量都是独立的,天然避免变量共享问题,代码也更简洁:

myArray.forEach(row => {
    const customerCode = row['customer_code'];
    const customerName = row['customer_name'];
    const customerBalance = row['customer_balance'];
    
    const callBody = {
        user: 'USER',
        code: customerCode,
        name: customerName,
        balance: customerBalance
    };
    
    const fetchOptions = {
        method: "POST",
        cache: "no-cache",
        headers: {
            "Content-Type": "application/x-www-form-urlencoded",
        },
        redirect: "error",
        referrer: "ux-import",
        body: JSON.stringify(callBody),
    };
    
    const epurl = baseEP + '/customer/create';
    fetch(epurl, fetchOptions)
        .then(response => response.json())
        .then(response => {
            // 逻辑和之前一致,这里的fetchOptions完全属于当前迭代
            if (response.error === 0) {
                console.log('insert ok');
                insertRows++;
            } else if (response.error == 2) {
                console.log('insert error => update');
                const updateEP = baseEP + '/customer/update';
                fetch(updateEP, fetchOptions)
                    .then(updResponse => updResponse.json())
                    .then(updResponse => {
                        if (updResponse.error === 0) {
                            console.log('update ok.')
                            updateRows++;
                        } else {
                            console.log('update error: ' + updResponse.msg)
                            errorMessages.push(updResponse.msg);
                        }
                    })
                    .catch(error => {
                        console.log('update failure');
                        errorMessages.push(error);
                    });
            } else {
                console.log('insert error.');
                errorMessages.push(response.msg);
            }
        })
        .catch(error => {
            console.log('insert failure.');
            errorMessages.push(error);
        });
});

3. 用IIFE包裹迭代逻辑(兼容老环境)

如果需要兼容不支持ES6+的老浏览器,可以用立即执行函数表达式(IIFE)把每个迭代的变量封闭起来,形成独立作用域:

for (var i = 0; i < expectedRows; i++) {
    // 把当前迭代的row传入IIFE,形成独立作用域
    (function(currentRow) {
        var customerCode = currentRow['customer_code'];
        var customerName = currentRow['customer_name'];
        var customerBalance = currentRow['customer_balance'];
        
        var callBody = {
            user: 'USER',
            code: customerCode,
            name: customerName,
            balance: customerBalance
        };
        
        var fetchOptions = {
            method: "POST",
            cache: "no-cache",
            headers: {
                "Content-Type": "application/x-www-form-urlencoded",
            },
            redirect: "error",
            referrer: "ux-import",
            body: JSON.stringify(callBody),
        };
        
        var epurl = baseEP + '/customer/create';
        fetch(epurl, fetchOptions)
            .then(response => response.json())
            .then(response => {
                // 这里的fetchOptions是当前IIFE内的变量,不会被后续循环覆盖
                if (response.error == 2) {
                    const updateEP = baseEP + '/customer/update';
                    fetch(updateEP, fetchOptions)
                        .then(updResponse => updResponse.json())
                        .then(updResponse => {
                            if (updResponse.error === 0) {
                                console.log('update ok.')
                                updateRows++;
                            } else {
                                console.log('update error: ' + updResponse.msg)
                                errorMessages.push(updResponse.msg);
                            }
                        })
                        .catch(error => {
                            console.log('update failure');
                            errorMessages.push(error);
                        });
                } else if (response.error === 0) {
                    console.log('insert ok');
                    insertRows++;
                } else {
                    console.log('insert error.');
                    errorMessages.push(response.msg);
                }
            })
            .catch(error => {
                console.log('insert failure.');
                errorMessages.push(error);
            });
    })(myArray[i]);
}

关于this的补充说明

你在then回调里用this指向window,是因为默认情况下普通函数的this在非严格模式下会绑定到window。其实根本不需要依赖this来获取请求对象——通过上面的作用域绑定,我们已经能直接访问到当前迭代的fetchOptions和callBody,直接用这些变量就可以实现你想要的逻辑,比如你期望的this.request.body,直接用callBody或者fetchOptions.body就行。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 09:30:06