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

JavaScript中Axios异步请求内字典(对象)键值无法更新的问题排查与解决

Why is testData empty after running async operations, and how to fix it?

I've written this code in my app:

import {getTestData,getUserData} from "./js/apiInteractorModule.js";
const TEST_NAMES = ['CM10'];
var testData = {};
function populateTestData(){
  return axios({
    method: 'post',
    url: '/get-session-cookie'
  }).then(response => {
    // Get decrypted session data
    getUserData(response.data.uuid,response.data.id_token).then(response => {
      // Get user data with decrypted session data (TODO: integrate with test data)
      for (let i = 0; i < TEST_NAMES.length; i++){
        getTestData(TEST_NAMES[i]).then(response => {
          testData[TEST_NAMES[i]] = [];
          for (var key in response.json){
            // Build data in format {name: [{x: time, y: value}]} (TODO: adjust with user data)
            testData[TEST_NAMES[i]].push({
              x: response.json[key].time,
              y: response.json[key].value
            });
          }
        });
      }
    })
    return response;
  }).catch(error => {
    console.log(error);
    return error;
  });
}

The getUserData and getTestData functions interact with external APIs. The getTestData API returns data like:

{success: true/false, json: {stringKey: {time: UNIX timestamp, value: float}}}

When I run populateTestData().then(response => { console.log(testData); });, the console shows testData is empty, and console.log(testData["CM10"]) returns undefined—even though I expect it to be {CM10: [{x: time, y: value}]} matching the API response.

As a test, if I initialize testData outside the function as var testData = {"CM10": 10}, then console.log(testData["CM10"]) outputs 10 correctly after running the same code.

Why is this happening, and how can I fix it?


What's causing this?

The core issue here is asynchronous timing. Let's break it down simply:

  • Every API call you're making (axios.post, getUserData, getTestData) is asynchronous—they run in the background while your main code keeps going.
  • When you call populateTestData().then(...), the outer then triggers as soon as the initial cookie request finishes. But at that moment, the getUserData call inside it is still running, and none of the getTestData callbacks that fill testData have executed yet.
  • So when you console.log(testData) in that outer then, the data hasn't been added to the object yet. That's why it's empty.

Your test with var testData = {"CM10": 10} works because that value is set immediately (synchronously)—no waiting required.


How to fix it

We need to make sure we wait for all asynchronous operations to finish before trying to access testData. The cleanest way to do this is using async/await (a more readable alternative to nested .then() calls) and Promise.all to handle parallel requests efficiently.

Here's the revised code:

import {getTestData, getUserData} from "./js/apiInteractorModule.js";
const TEST_NAMES = ['CM10'];
var testData = {};

async function populateTestData() {
  try {
    // Wait for the initial cookie request to complete
    const cookieResponse = await axios({
      method: 'post',
      url: '/get-session-cookie'
    });

    // Wait for getUserData to finish before moving on
    const userData = await getUserData(cookieResponse.data.uuid, cookieResponse.data.id_token);

    // Wait for ALL getTestData requests to finish at the same time
    await Promise.all(TEST_NAMES.map(async (testName) => {
      const testResponse = await getTestData(testName);
      // Convert the API response to the format you need
      testData[testName] = Object.values(testResponse.json).map(item => ({
        x: item.time,
        y: item.value
      }));
    }));

    // Now testData is fully populated
    return testData;
  } catch (error) {
    console.error(error);
    throw error; // Let the caller handle the error if needed
  }
}

To use the fixed function:

populateTestData().then(data => {
  console.log(data); // Will show the fully populated testData
  console.log(data["CM10"]); // Works as expected now
}).catch(error => {
  // Handle any errors here (e.g., API failures)
});

Key improvements:

  1. async/await makes the code read like sequential, synchronous code, so you can clearly see when each operation finishes.
  2. Promise.all waits for all getTestData requests to complete in parallel (faster than running them one after another).
  3. We return the populated testData directly from the function, so the caller can access it cleanly in the .then() block.
  4. Object.values() replaces the for...in loop, making the code cleaner and more concise when converting the API response to your desired format.

内容的提问来源于stack exchange,提问作者M. Chak

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 14:42:30