// Relevant code:
const searchBtn = document.getElementById("search-btn");
const input = document.getElementById("input");
const leftTable = document.querySelector("#left-table");
let url = "https://api.github.com/search/repositories?q=?";
let tagsUrl;
let dataArr;
let names = [];
let language = [];
let latestTag = [];
let tableDataArr = [names, language, latestTag];
// Fetch first 2 items for repos containing user query
function search(newURL) {
fetch(newURL, {
headers: {
"Authorization": "xxxx"
}
})
.then(resp => {
return resp.json();
})
.then(data => {
dataArr = data.items.slice(0, 2);
return extractData();
});
input.value = "";
}
// Extract necessary values from returned object (language, name, latest tag) and push to corresponding arrays
function extractData() {
dataArr.forEach(i => {
names.push(i.full_name);
language.push(i.language);
fetch(i.tags_url)
.then(resp => {
return resp.json();
})
.then(resp => {
if (resp[0]) {
latestTag.push(resp[0].name);
} else {
latestTag.push(" ");
}
return console.log(tableDataArr);
});
// getLatestTag(i.tags_url);
});
renderData();
}
// Render array data to HTML table
function renderData() {
tableDataArr[0].forEach((i, j) => {
let newRow = document.createElement("tr");
newRow.className = "row";
newRow.innerHTML = `<td class='cell'>${i}</td>
<td class='cell'>${tableDataArr[1][j]}</td>
<td class='cell'>${tableDataArr[2][j]}</td>
<td class='cell'><button class='add-btn'>Add</button></td>`;
leftTable.appendChild(newRow);
});
}
// User input event listeners
searchBtn.addEventListener("click", () => {
search(url + input.value);
});
input.addEventListener("keyup", e => {
if (e.keyCode === 13) {
search(url + input.value);
}
});
我需要tableDataArr中每个数组的内容在事件监听器触发后呈现给HTML表。 tableDataArr [0]和tableDataArr [1]中的内容每次都会呈现,没有任何问题。
但是,tableDataArr [2]中的内容在第一次调用时呈现未定义,然后在下一次调用时正确呈现,然后是未定义的,依此类推,在undefined和数据之间使用这种交替模式。这里发生了什么?
Fetch和链接的thens将返回一个Promise对象。你可以把所有这些都推到一个数组中,并在调用renderData()之前使用Promise.all()检查你的所有提取和文件是否完整
此示例代码将指导您...
// Extract necessary values from returned object (language, name, latest tag) and push to corresponding arrays
function extractData() {
let psArr = [];
dataArr.forEach(i => {
names.push(i.full_name);
language.push(i.language);
let ps = fetch(i.tags_url)
.then(resp => {
return resp.json();
})
.then(resp => {
if (resp[0]) {
latestTag.push(resp[0].name);
} else {
latestTag.push(" ");
}
return resp;
});
psArr.push(ps);
// getLatestTag(i.tags_url);
});
Promise.all(psArr).then(()=>{
renderData();
});
}
重要的是要注意当then
s链接到一个承诺时,分配给变量的承诺是最后一个链式then
的承诺。
此外,由于这是异步的,因此顺序可以根据提取的完成而改变,这可能导致不可预测的行为。
你在renderData
完成之前调用fetch
所以它还没有完成提取。尝试将它移动到then
内部,看看我的意思。
fetch
是异步的 - 它必须等待网络响应 - 你在then
中编写的代码等待它完成,但是在将该项目推入阵列之前,renderData
正在被立即调用。
看起来即使使用此更改,如果您正在进行多次提取并以这种方式推送到阵列,您的代码也可能容易出错 - 可能会导致tags
无法正常运行,并且无法与您预期的names
匹配。