回调函数传递变量:Twitch流状态查询无法关联流名称求助
解决Twitch API流状态与名称关联的问题
我一眼就看出你的问题所在了——这是异步请求和JavaScript闭包结合时的经典坑!
问题根源
你在for循环里发起异步的$.getJSON请求,而AJAX请求是异步执行的:当回调函数触发时,外层的for循环早就跑完了,变量i的值已经变成了streamsToGet.length(也就是8),这时候streamsToGet[i]就是undefined,而且你也没法把API返回的结果和对应的流名称对应起来。另外,这个Twitch测试API的返回结果里确实不会带回你查询的用户名,所以必须自己把每个请求的用户名和回调绑定起来。
修复方案
有几种简单的方法可以解决这个问题,我推荐最直观的两种:
方法1:使用forEach循环替代for循环
forEach会为每个元素创建独立的作用域,这样每个回调函数都能捕获到当前迭代的流名称:
var twitchApiEndpoint = "https://wind-bow.glitch.me/twitch-api"; var streamsToGet = ["ESL_SC2", "OgamingSC2", "cretetion", "freecodecamp", "storbeck", "habathcx", "RobotCaleb", "noobs2ninjas"]; var streamsStatuses = []; $(document).ready(getEntries); function getEntries() { streamsToGet.forEach(function(streamName) { $.getJSON(twitchApiEndpoint + "/streams/" + streamName, function(json) { var streamStatus = json.stream ? json.stream.game : "offline"; $(".main").append('<div class="row stream-entry"><div class="col stream-title">' + streamName + '</div><div class="col stream-description">' + streamStatus + '</div></div>'); }); }); }
方法2:在for循环里使用let(ES6+)
let会创建块级作用域,每次循环都会生成一个新的i变量,确保回调能拿到当前迭代的索引:
var twitchApiEndpoint = "https://wind-bow.glitch.me/twitch-api"; var streamsToGet = ["ESL_SC2", "OgamingSC2", "cretetion", "freecodecamp", "storbeck", "habathcx", "RobotCaleb", "noobs2ninjas"]; var streamsStatuses = []; $(document).ready(getEntries); function getEntries() { // 这里用let代替var for (let i = 0; i < streamsToGet.length; i++) { const streamName = streamsToGet[i]; $.getJSON(twitchApiEndpoint + "/streams/" + streamName, function(json) { var streamStatus = json.stream ? json.stream.game : "offline"; $(".main").append('<div class="row stream-entry" id="' + i + '"><div class="col stream-title">' + streamName + '</div><div class="col stream-description">' + streamStatus + '</div></div>'); }); } }
额外优化建议
- 可以把HTML字符串模板用模板字符串(
`)来写,可读性更好:$(".main").append(`<div class="row stream-entry"> <div class="col stream-title">${streamName}</div> <div class="col stream-description">${streamStatus}</div> </div>`); - 如果需要保证结果的顺序和
streamsToGet数组一致,可以用Promise.all来等待所有请求完成后再渲染,避免因请求响应速度不同导致顺序混乱。
内容的提问来源于stack exchange,提问作者Daniel Speich
相关产品推荐
相关产品推荐

