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

FCC Twitch API项目:for循环内的if-else无法遍历所有情况

解决Twitch主播信息展示项目的异步作用域问题

你遇到的两个问题都是异步回调中的变量作用域陷阱导致的——简单来说,var声明的变量是函数级作用域,当异步请求的回调执行时,循环已经结束,所有回调共用同一个变量值,自然会出现错位的情况。

问题原因拆解

  1. 所有状态显示为Offline:
    你用var声明了streamURL,它是函数级作用域的变量,每次循环都会覆盖这个变量的值。当异步的$.getJSON回调执行时,streamURL已经变成了最后一个频道的请求地址,所以所有流状态请求都是针对最后一个频道的——如果这个频道刚好是离线状态,所有主播的状态就都会显示Offline。

  2. 除第一个logo外边框样式无变化:
    同样,var i是函数级作用域,循环结束后i的值等于channels.length(也就是5)。当回调执行时,你用$("#img"+i)选择元素,实际上找的是不存在的#img5,根本无法给正确的logo添加样式。第一个logo偶尔生效只是因为回调刚好在循环还没结束时执行,属于偶然情况,完全不可靠。

解决方案

下面提供三种可行的解决方式,推荐优先使用前两种(ES6+语法,更简洁清晰):

方案1:使用let替换var(最简单的ES6+方案)

let是块级作用域变量,每次循环都会创建新的变量绑定,确保每个异步回调拿到的都是当前循环的变量值:

$(document).ready(function() {
  const channels = ["freecodecamp", "wudijo", "ThijsHS", "HSdogdog", "Sjow"];
  // 用let声明循环变量i,确保每次循环的i独立
  for (let i = 0; i < channels.length; i++) {
    // 用const/let声明url,避免变量覆盖
    const channelURL = `https://wind-bow.gomix.me/twitch-api/channels/${channels[i]}?callback=?`;
    const streamURL = `https://wind-bow.gomix.me/twitch-api/streams/${channels[i]}?callback=?`;
    
    $.getJSON(channelURL, function(data1) {
      const logo = data1.logo;
      const name = data1.display_name;
      const twitchLink = data1.url;
      let status;
      
      $.getJSON(streamURL, function(data2) {
        status = data2.stream === null ? "Offline" : data2.stream.channel.status;
        
        // 先创建元素,再操作,避免全局查找id
        const $row = $(`<div class="row">
          <div class="col-md-4">
            <a href="${twitchLink}" target="_blank">
              <img id="img${i}" src="${logo}">
            </a>
          </div>
          <div class="col-md-4"><p>${name}</p></div>
          <div class="col-md-4"><p id="status${i}">${status}</p></div>
        </div>`);
        
        $("#followerInfo").append($row);
        
        // 直接从刚创建的row里找img,更高效可靠
        const $img = $row.find(`#img${i}`);
        $img.addClass(data2.stream === null ? 'img-offline' : 'img-online');
      });
    });
  }
});

这里还优化了两个细节:

  • 使用模板字符串拼接HTML和URL,可读性更强
  • 直接从创建的$row元素里查找logo,不用全局通过id查找,性能更好

方案2:使用forEach遍历数组(逻辑更清晰)

forEach的回调函数每次都会创建新的作用域,天然避免变量共享问题:

$(document).ready(function() {
  const channels = ["freecodecamp", "wudijo", "ThijsHS", "HSdogdog", "Sjow"];
  
  channels.forEach((channel, index) => {
    const channelURL = `https://wind-bow.gomix.me/twitch-api/channels/${channel}?callback=?`;
    const streamURL = `https://wind-bow.gomix.me/twitch-api/streams/${channel}?callback=?`;
    
    $.getJSON(channelURL, function(data1) {
      const logo = data1.logo;
      const name = data1.display_name;
      const twitchLink = data1.url;
      let status;
      
      $.getJSON(streamURL, function(data2) {
        status = data2.stream === null ? "Offline" : data2.stream.channel.status;
        
        const $row = $(`<div class="row">
          <div class="col-md-4">
            <a href="${twitchLink}" target="_blank">
              <img id="img${index}" src="${logo}">
            </a>
          </div>
          <div class="col-md-4"><p>${name}</p></div>
          <div class="col-md-4"><p id="status${index}">${status}</p></div>
        </div>`);
        
        $("#followerInfo").append($row);
        
        const $img = $row.find(`#img${index}`);
        $img.addClass(data2.stream === null ? 'img-offline' : 'img-online');
      });
    });
  });
});

方案3:立即执行函数表达式(IIFE,兼容旧环境)

如果需要兼容不支持ES6的浏览器,可以用IIFE把每次循环的变量封装起来,形成独立的闭包:

$(document).ready(function() {
  var channels = ["freecodecamp", "wudijo", "ThijsHS", "HSdogdog", "Sjow"];
  for (var i = 0; i < channels.length; i++) {
    // 用IIFE保存当前循环的i和channel值
    (function(currentIndex, currentChannel) {
      var channelURL = "https://wind-bow.gomix.me/twitch-api/channels/" + currentChannel + "?callback=?";
      var streamURL = "https://wind-bow.gomix.me/twitch-api/streams/" + currentChannel + "?callback=?";
      
      $.getJSON(channelURL, function(data1) {
        var logo = data1.logo;
        var name = data1.display_name;
        var twitchLink = data1.url;
        var status;
        
        $.getJSON(streamURL, function(data2) {
          status = data2.stream === null ? "Offline" : data2.stream.channel.status;
          
          var $row = $("<div class='row'><div class='col-md-4'><a href='" + twitchLink + "' target='_blank'><img id='img" + currentIndex + "' src='" + logo + "'></a></div><div class='col-md-4'><p>" + name + "</p></div><div class='col-md-4'><p id='status" + currentIndex + "'>" + status + "</p></div></div>");
          
          $("#followerInfo").append($row);
          
          var $img = $row.find("#img" + currentIndex + "");
          $img.addClass(data2.stream === null ? 'img-offline' : 'img-online');
        });
      });
    })(i, channels[i]);
  }
});

最后提个小细节:target='blank'应该写成target="_blank",这是HTML的标准写法,避免浏览器解析异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 07:21:45