#javascript #setinterval
Вопрос:
У меня есть строка содержимого таблицы, которая извлекается из API, в то время как я использую функцию setinterval, она просто повторяет содержимое обновленной строки таблицы.
Например: (Это пример вывода, а не фактический)
Предположим, что у меня есть контент
John price 2000
По истечении временного интервала в 1 секунду он должен обновить новое значение из API, например
John price 2200
Но что я получаю, так это то, что каждый раз, когда он обновляется, он просто добавляет, как
John price 2000
John price 2200
John price 2120 ......
Мой Код:
<table class="table">
<thead class="thead-dark">
<tr>
<th>Coin</th>
<th>Symbol</th>
<th>Currency</th>
<th>Price</th>
</tr>
</thead>
<tbody id="details">
<tbody>
</table>
var data, len, len1, name, symbol, currency, price;
const api_url = "https://api.wazirx.com/api/v2/market-status";
async function get_data_from_api() {
const response = await fetch(api_url);
data = await response.json();
len = Object.keys(data["markets"]).length;
len1 = Object.keys(data["assets"]).length;
for (let i = 0; i < len; i ) {
for (let j = 0; j < len1; j ) {
if (data['markets'][i]['baseMarket'] == data['assets'][j]['type'] amp;amp; data['markets'][i]['quoteMarket'] == "inr") {
name = data['assets'][j]['name'];
symbol = data['assets'][j]['type'];
currency = data['markets'][i]['quoteMarket'];
price = data['markets'][i]['buy'];
document.getElementById('details').innerHTML = "<tr><td>" name "</td><td>" symbol "</td><td>" currency "</td><td>" price "</td></tr>";
}
}
}
}
get_data_from_api();
setInterval(get_data_from_api, 1000);
Комментарии:
1.
=
объединяет2. Просто замените = на = в вашем внутреннем htmlе?
3. попробовал это, но если я удалю =, это означает, что на моем столе ничего не отображается, это просто пустой идентификатор, в чем проблема. но если я использую =, это означает, что вывод отображается правильно.
4. @Браво, я только что ответил на вопрос, это должно сработать.
5. Я думаю, что если вы приведете пример данных, полученных из вашего API. Это поможет людям понять ваш вопрос и легко дать на него ответ.
Ответ №1:
Помимо принятого ответа. Я также рекомендую вам использовать цикл while с wait
функцией ниже вместо setInterval
.
setInterval может вызывать API без необходимости. Например. при первом вызове api api требуется одна секунда для ответа, в то же время вы вызываете api во второй раз, когда он отвечает всего за 100 мс, и на самом деле вы не увидите результат первого раза, потому что второй вызов немедленно обновляет первый вызов.
const api_url = "https://api.wazirx.com/api/v2/market-status";
const wait = ms => new Promise(res => setTimeout(res, ms));
(async function run() {
while (true) {
try {
const response = await fetch(api_url);
const data = await response.json();
//html jobs.....
await wait(1000);
} catch (err) {
console.log(err);
continue;
}
}
})();
Комментарии:
1. почему? Я имею в виду, конечно, это не заблокирует основную нить или что-то в этом роде … но… почему? в чем преимущество
2. @Bravo, setInterval может вызывать API без необходимости. Например. при первом вызове api api требуется одна секунда для ответа, в то же время вы вызываете api во второй раз, когда он отвечает всего за 100 мс, и на самом деле вы не увидите результат первого раза, потому что второй вызов немедленно обновляет первый вызов.
3. Это вполне логично — я задавался вопросом, а не критиковал
4. @Браво, конечно, мы просто обсуждаем.
5. хотя… вы могли бы сделать то же самое с
setTimeout
Ответ №2:
Вы просто добавляете содержимое в узел с помощью
document.getElementById('details').innerHTML = "<tr><td>" name "</td><td>" symbol "</td><td>" currency "</td><td>" price "</td></tr>";
Перед добавлением этого вы должны установить содержимое пустым вне цикла, если у вас есть несколько узлов, удовлетворяющих условию.
document.getElementById('details').innerHTML = "";
Если есть только один узел, удовлетворяющий условию, просто назначьте значение с
document.getElementById('details').innerHTML = "<tr><td>" name "</td><td>" symbol "</td><td>" currency "</td><td>" price "</td></tr>";
Рабочее решение будет примерно таким.
var data, len, len1, name, symbol, currency, price;
const api_url = "https://api.wazirx.com/api/v2/market-status";
async function get_data_from_api() {
const response = await fetch(api_url);
document.getElementById('details').innerHTML = '';
data = await response.json();
len = Object.keys(data["markets"]).length;
len1 = Object.keys(data["assets"]).length;
for (let i = 0; i < len; i ) {
for (let j = 0; j < len1; j ) {
if (data['markets'][i]['baseMarket'] == data['assets'][j]['type'] amp;amp; data['markets'][i]['quoteMarket'] == "inr") {
name = data['assets'][j]['name'];
symbol = data['assets'][j]['type'];
currency = data['markets'][i]['quoteMarket'];
price = data['markets'][i]['buy'];
document.getElementById('details').innerHTML = "<tr><td>" name "</td><td>" symbol "</td><td>" currency "</td><td>" price "</td></tr>";
}
}
}
}
get_data_from_api();
setInterval(get_data_from_api, 1000);
Комментарии:
1. @Nitheesh да, но у меня есть несколько данных, поступающих из моего API с помощью forloop, поэтому я не могу поставить ‘=’
2. Браво, я не проверил твой ответ, он был удален b4, я в него вхожу
3. есть ли какая-либо возможность обратиться только к деталям цены? В настоящее время все это освежает. Есть идеи ?
Ответ №3:
Причина, по которой ваш код продолжает добавляться в таблицу, заключается в том, что вы только сделали это
document.getElementById('details').innerHTML = " ..... "
Так что, конечно, это только добавляет
Наивное решение состоит в том, чтобы добавить код ПЕРЕД циклами, который очищает innerHTML
document.getElementById('details').innerHTML = ""
Гораздо лучшим решением было бы инициализировать строковую переменную перед циклами, добавить в строку внутри циклов, а затем обновить innerHTML один раз после циклов
const api_url = "https://api.wazirx.com/api/v2/market-status";
async function get_data_from_api() {
const response = await fetch(api_url);
const data = await response.json();
const len = Object.keys(data["markets"]).length;
const len1 = Object.keys(data["assets"]).length;
// this will hold the new HTML
let html = "";
for (let i = 0; i < len; i ) {
for (let j = 0; j < len1; j ) {
if (data['markets'][i]['baseMarket'] == data['assets'][j]['type'] amp;amp; data['markets'][i]['quoteMarket'] == "inr") {
const name = data['assets'][j]['name'];
const symbol = data['assets'][j]['type'];
const currency = data['markets'][i]['quoteMarket'];
const price = data['markets'][i]['buy'];
html = "<tr><td>" name "</td><td>" symbol "</td><td>" currency "</td><td>" price "</td></tr>";
}
}
}
// we have the new HTML - update the DOM only once per API call
document.getElementById('details').innerHTML = html;
}
(Я взял на себя смелость объявить переменные там, где они необходимы, а не глобально)
Теперь: Вот альтернатива, которая очищает циклы for с помощью методов массива, таких как flatMap, фильтр, карта
const api_url = "https://api.wazirx.com/api/v2/market-status";
async function get_data_from_api() {
try {
const response = await fetch(api_url);
const data = await response.json();
document.getElementById('details').innerHTML = Object.values(data.markets)
.flatMap((market) =>
Object.values(data.assets)
// your if condition
.filter((asset) => market.baseMarket == asset.type amp;amp; market.quoteMarket == 'inr')
.map((asset) => {
const { name, type: symbol } = asset;
const { quoteMarket: currency, buy: price } = market;
return `<tr><td>${name}</td><td>${symbol}</td><td>${currency}</td><td>${price}</td></tr>`;
})
).join('');
} catch(error) {
// handle error
}
setTimeout(get_data_from_api, 1000);
}
get_data_from_api();
Не уверен, но этот код может обновить только цену
const api_url = "https://api.wazirx.com/api/v2/market-status";
async function get_data_from_api() {
try {
const target = document.getElementById('details');
const response = await fetch(api_url);
const data = await response.json();
const addedHtml = Object.values(data.markets)
.flatMap((market) =>
Object.values(data.assets)
// your if condition
.filter((asset) => market.baseMarket == asset.type amp;amp; market.quoteMarket == 'inr')
.map((asset) => {
const { name, type: symbol } = asset;
const { quoteMarket: currency, buy: price } = market;
return { id, name, symbol, currency, price };
})
)
.map(({ name, symbol, currency, price }) => {
const id = `${name}${symbol}${currency}`;
let el = target.querySelector(`#${id}`);
if (el) {
el.textContent = price;
return '';
} else {
return `<tr><td>${name}</td><td>${symbol}</td><td>${currency}</td><td id="${id}">${price}</td></tr>`;
}
});
if (addedHTML.length) {
target.insertAdjacentHTML('beforeend', addedHtml.join(''));
}
} catch(error) {
// handle error
}
setTimeout(get_data_from_api, 1000);
}
get_data_from_api();
Комментарии:
1. Ошибка произошла в моей консоли, которая «Не поймана (в обещании)». Ошибка типа: Объект.значения(…).flatmap не является функцией в get_data_from_api»
2. @harish — должен был быть
flatMap
… моя вина3. Вопрос был «проблема с кодом», и одобренный ответ был «Как написать лучший код».
4. @harish, пожалуйста, взгляните на мой ответ. Это также помогло бы вам.
5. @Браво, Это было действительно забавно. Вопрос заключался в логической ошибке, которую он допустил в своем коде. Он спросил, почему его записи добавляются к существующим, а не удаляются из существующих и создаются новые. Но этот ответ был похож на то, как этот код можно улучшить до более эффективного уровня.