我正在编写一个脚本,该脚本从Twitch.tv API中为数组中指定的多个通道提取数据,然后使用通道名称和流式传输来填充表格。这里是JS代码后跟HTML:
var channels = ["ESL_SC2", "freecodecamp", "OgamingSC2", "noobs2ninjas"];
$(document).ready(function() {
$( window ).on("load", function() {
for (var i = 0; i < channels.length; i++) {
$.getJSON("https://wind-bow.gomix.me/twitch-api/streams/" + channels[i] + "?callback=?", function(json) {
var json = JSON.stringify(json);
var obj = JSON.parse(json);
var streamStatus = obj.stream;
if (streamStatus === null) {
streamStatus = "Offline";
}
else {
streamStatus = "Streaming " + obj.stream.channel.status;
}
var para = document.createElement("div");
var node = document.createTextNode(streamStatus);
para.appendChild(node);
var element = document.getElementById("status");
element.appendChild(para);
});
}
for (var i = 0; i < channels.length; i++) {
var para = document.createElement("div");
var node = document.createTextNode(channels[i]);
para.appendChild(node);
var element = document.getElementById("title");
element.appendChild(para);
}
});
});
&#13;
<head>
<script src="http://code.jquery.com/jquery-latest.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
</head>
<div class="row">
<div class="col-sm-3"></div>
<div class="col-sm-6 center-column">
<h3>Twitch.tv Viewer</h3>
<div class="row">
<div class="col-sm-2" id="title"></div>
<a href="" id="link" target="_blank" style="text-decoration:none;"><div id="status"></div></a>
</div>
</div>
<div class="col-sm-3"></div>
</div>
&#13;
这是我的问题:每次加载页面时,第二列中的项目顺序(&#39;状态&#39; div,让您知道&#39; 39; s流式传输)以不同的顺序结束,这意味着它们不再与第一列中的频道(&#39; title&#39; div)正确对齐。
我怀疑它与API调用有关,而for循环是asynchronic,如建议here。但我无法弄清楚如何实施所提出的解决方案。任何建议将不胜感激!
答案 0 :(得分:1)
嗯,是的,你是对的 - 你面临的问题是每次你在for循环中进行API调用需要花费不同的时间来处理,所以一些回调可能会更早发生另一个打破你的 for循环顺序。
使用的最佳做法是使用Promise,如下所述:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
在您当前的代码中,您可以等待所有回调完成,然后才将数据呈现给DOM(但这不是最佳做法):
var channels = ["ESL_SC2", "freecodecamp", "OgamingSC2", "noobs2ninjas"];
$(document).ready(function() {
$( window ).on("load", function() {
var getData = function(i){
$.getJSON("https://wind-bow.gomix.me/twitch-api/streams/" + channels[i] + "?callback=?", function(json) {
var json = JSON.stringify(json);
var obj = JSON.parse(json);
var streamStatus = obj.stream;
if (streamStatus === null) {
streamStatus = "Offline";
}
else {
streamStatus = "Streaming " + obj.stream.channel.status;
}
channels[i].streamStatus = streamStatus;
var para = document.createElement("div");
var node = document.createTextNode(streamStatus);
para.appendChild(node);
var element = document.getElementById("status");
element.appendChild(para);
if(i == channels.length -1){
getData(++i);
}
});
}
getData(0);
for (var i = 0; i < channels.length; i++) {
var para = document.createElement("div");
var node = document.createTextNode(channels[i]);
para.appendChild(node);
var element = document.getElementById("title");
element.appendChild(para);
}
});
});
&#13;
在此示例中,脚本使用循环函数,只有在前一个迭代完成时才加载下一个迭代。
请注意,这会影响性能 - 因为它实际上会破坏异步API调用的完美性;这种方式仍然可以更容易地实现和管理它。
答案 1 :(得分:0)
只需在getJSON回调结束时接收下一部分数据:
function updateNextStream(){
if (i>=channels.length)return;
$.getJSON("https://wind-bow.gomix.me/twitch-api/streams/" + channels[i] + "? callback=?", function(json) {
var json = JSON.stringify(json);
var obj = JSON.parse(json);
var streamStatus = obj.stream;
if (streamStatus === null) {
streamStatus = "Offline";
}
else {
streamStatus = "Streaming " + obj.stream.channel.status;
}
var para = document.createElement("div");
var node = document.createTextNode(streamStatus);
para.appendChild(node);
var element = document.getElementById("status");
element.appendChild(para);
i++;
updateNextStream();
});
}
答案 2 :(得分:0)
您可以解决此问题的一种方法是创建递归函数。这允许你等待&#34;对于每个AJAX请求,当处理请求时,它将转到获取下一个通道。
var channels = ["ESL_SC2", "freecodecamp", "OgamingSC2", "noobs2ninjas"];
var ci = 0; // Channel index
(function getChannels(){
if(ci >= channels.length)
return; // Stop the recursion if we've iterated all channels
$.getJSON("https://wind-bow.gomix.me/twitch-api/streams/" + channels[ci] + "?callback=?", function(json) {
var json = JSON.stringify(json);
var obj = JSON.parse(json);
var streamStatus = obj.stream;
if (streamStatus === null) {
streamStatus = "Offline";
}
else {
streamStatus = "Streaming " + obj.stream.channel.status;
}
var para = document.createElement("div");
var node = document.createTextNode(streamStatus);
para.appendChild(node);
var element = document.getElementById("status");
element.appendChild(para);
ci++;
getChannels();
});
var para = document.createElement("div");
var node = document.createTextNode(channels[ci]);
para.appendChild(node);
var element = document.getElementById("title");
element.appendChild(para);
})();
答案 3 :(得分:0)
那是因为你正在创建&#34;标题&#34;元素独立于&#34;状态&#34;元素,在API回调中创建。 API请求的完成顺序各不相同。
只需同时创建它们就不会出现这个问题。
var channels = ["ESL_SC2", "freecodecamp", "OgamingSC2", "noobs2ninjas"];
$(document).ready(function() {
for (var i = 0; i < channels.length; i++) {
$.getJSON("https://wind-bow.gomix.me/twitch-api/streams/" + channels[i] + "?callback=?", dataCallback(channels[i]));
}
function dataCallback(channel) {
return function(data) {
var streamStatus = data.stream;
if (streamStatus === null) {
streamStatus = "Offline";
} else {
streamStatus = "Streaming " + data.stream.channel.status;
}
var para = document.createElement("div");
var node = document.createTextNode(streamStatus);
para.appendChild(node);
var element = document.getElementById("status");
element.appendChild(para);
var para = document.createElement("div");
var node = document.createTextNode(channel);
para.appendChild(node);
var element = document.getElementById("title");
element.appendChild(para);
}
}
});
&#13;
<head>
<script src="http://code.jquery.com/jquery-latest.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
</head>
<div class="row">
<div class="col-sm-3"></div>
<div class="col-sm-6 center-column">
<h3>Twitch.tv Viewer</h3>
<div class="row">
<div class="col-sm-2" id="title"></div>
<a href="" id="link" target="_blank" style="text-decoration:none;">
<div id="status"></div>
</a>
</div>
</div>
<div class="col-sm-3"></div>
</div>
&#13;
答案 4 :(得分:0)
正如其他人所说,问题是结果是异步返回的,但是你的逻辑依赖于它们以与调用它们相同的顺序返回。
这是一个示例解决方案,它使用返回的JSON中的ID将返回的状态与相关元素进行匹配。
状态元素与标题元素一起创建,并显示“待定”状态,直到从API返回实际状态。
var channels = ["ESL_SC2", "freecodecamp", "OgamingSC2", "noobs2ninjas"];
$(document).ready(function() {
$(window).on("load", function() {
for (var i = 0; i < channels.length; i++) {
$.getJSON("https://wind-bow.gomix.me/twitch-api/streams/" + channels[i] + "?callback=?", function(json) {
var json = JSON.stringify(json);
var obj = JSON.parse(json);
var streamStatus = obj.stream;
if (streamStatus === null) {
streamStatus = "Offline";
} else {
streamStatus = "Streaming " + obj.stream.channel.status;
}
//Update status
var channelId = '';
if (obj._links && obj._links.channel) {
const parts = obj._links.channel.split('/');
if (parts.length >= 6) {
channelId = parts[5];
}
}
var statusEl = document.getElementById("channel_"+channelId);
if (statusEl) {
statusEl.innerHTML = streamStatus;
}
});
}
//cache relevant elements
var titleEl = document.getElementById("title");
var statusEl = document.getElementById("status");
for (var i = 0; i < channels.length; i++) {
var para = document.createElement("div");
var node = document.createTextNode(channels[i]);
para.appendChild(node);
titleEl.appendChild(para);
//create status elements
para = document.createElement("div");
para.id = "channel_"+channels[i];
node = document.createTextNode('pending...');
para.appendChild(node);
statusEl.appendChild(para);
}
});
});
<head>
<script src="http://code.jquery.com/jquery-latest.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
</head>
<div class="row">
<div class="col-sm-3"></div>
<div class="col-sm-6 center-column">
<h3>Twitch.tv Viewer</h3>
<div class="row">
<div class="col-sm-2" id="title"></div>
<a href="" id="link" target="_blank" style="text-decoration:none;">
<div id="status"></div>
</a>
</div>
</div>
<div class="col-sm-3"></div>
</div>