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

使用jQuery的$.ajax/getJSON按原数组顺序获取Twitch频道数据问题

解决Twitch API数据获取的顺序与异步问题

我来帮你一步步解决这三个问题,先从根源说起,再给你具体的代码方案:

问题2:为什么console.log(channels)能看到数据但channels.length为0?

这是异步操作的时序问题。你第二个$.ajax用了async:'true'(注意这里应该写布尔值true,不是字符串),意味着浏览器发送请求后会直接执行后续代码,不会等待请求完成。当你执行console.log(channels)和console.log(channels.length)时,所有异步请求还没返回数据,channels数组还是空的,所以length显示为0。而浏览器控制台有个特性:它显示的数组是实时引用,当后续请求完成把数据push进去后,你展开控制台里的数组就能看到最新数据,但length是执行console.log时的数值,不会更新。

问题1:数组顺序与原user_arr不一致

同样是异步请求导致的:每个请求的响应返回时间不同,谁先拿到数据谁就先被push到数组里,自然和原数组顺序对不上。你第一个请求用了async:false(同步),但第二个是异步,这会导致逻辑混乱,而且async:false已经被废弃,强烈不推荐使用。

解决方案:用jQuery的Deferred(类Promise)保证顺序并处理异步

jQuery的$.ajax返回的是Deferred对象,它和Promise类似,能帮我们优雅处理异步操作。下面给你两种实用方案:

方案1:串行请求(严格按原数组顺序,一个请求完成再发下一个)

适合需要严格顺序的场景,缺点是总耗时为所有请求时间之和:

$(document).ready(function(){
  const user_arr = ["ESL_SC2", "OgamingSC2", "cretetion", "freecodecamp", "storbeck", "habathcx", "RobotCaleb", "noobs2ninjas"];
  const resultArr = []; // 存储每个用户的合并数据

  // 递归函数,逐个处理用户
  function processUser(index) {
    if (index >= user_arr.length) {
      // 所有用户处理完成
      console.log("最终结果数组:", resultArr);
      console.log("数组长度:", resultArr.length);
      return;
    }

    const username = user_arr[index];
    const streamUrl = `https://wind-bow.gomix.me/twitch-api/streams/${username}?callback=?`;
    const channelUrl = `https://wind-bow.gomix.me/twitch-api/channels/${username}?callback=?`;

    // 同时获取当前用户的stream和channel数据
    $.when(
      $.getJSON(streamUrl),
      $.getJSON(channelUrl)
    ).done(function(streamData, channelData) {
      // 合并当前用户的两个数据
      resultArr.push({
        username: username,
        stream: streamData[0], // $.getJSON的done回调参数是数组,第一个元素为返回数据
        channel: channelData[0]
      });
      // 处理下一个用户
      processUser(index + 1);
    }).fail(function(err) {
      console.error(`处理用户${username}时出错:`, err);
      processUser(index + 1); // 出错也继续处理下一个用户
    });
  }

  // 开始处理第一个用户
  processUser(0);
});

方案2:并行请求(所有请求同时发送,最后按原顺序整理)

效率更高,总耗时为最慢请求的时间,我们给每个请求标记原数组索引,最后按索引排序:

$(document).ready(function(){
  const user_arr = ["ESL_SC2", "OgamingSC2", "cretetion", "freecodecamp", "storbeck", "habathcx", "RobotCaleb", "noobs2ninjas"];
  const deferreds = [];

  // 为每个用户创建异步任务
  user_arr.forEach((username, index) => {
    const streamUrl = `https://wind-bow.gomix.me/twitch-api/streams/${username}?callback=?`;
    const channelUrl = `https://wind-bow.gomix.me/twitch-api/channels/${username}?callback=?`;

    // 合并当前用户的两个请求
    const userDeferred = $.when(
      $.getJSON(streamUrl),
      $.getJSON(channelUrl)
    ).then(function(streamData, channelData) {
      // 返回带索引的合并数据
      return {
        index: index,
        username: username,
        stream: streamData[0],
        channel: channelData[0]
      };
    }).fail(function(err) {
      console.error(`获取用户${username}数据出错:`, err);
      // 出错时也返回索引,保证顺序
      return {
        index: index,
        username: username,
        error: err
      };
    });

    deferreds.push(userDeferred);
  });

  // 等待所有请求完成
  $.when.apply($, deferreds).done(function() {
    // 按索引排序,还原原数组顺序
    const resultArr = Array.from(arguments).sort((a, b) => a.index - b.index);
    console.log("最终结果数组:", resultArr);
    console.log("数组长度:", resultArr.length);

    // 用map整理成自定义格式,比如只保留关键字段
    const mappedArr = resultArr.map(item => ({
      name: item.username,
      displayName: item.channel?.display_name || item.username,
      isStreaming: item.stream?.stream !== null
    }));
    console.log("map整理后的数组:", mappedArr);
  });
});

关于Promise的简单理解

你可以把Promise(或jQuery的Deferred)看成一个“异步任务容器”:它有等待中、成功、失败三种状态。当异步操作完成时,它会切换到对应状态,并执行预设的回调函数。

上面代码里的$.when()就是把多个异步任务合并成一个,当所有任务都成功时才执行done()里的逻辑;then()则用来处理单个任务的结果,把数据转换成我们需要的格式。这种写法完全替代了过时的async:false,完美解决顺序和异步时序问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 06:48:39