Как правильно оптимизировать длинный цикл for, который каждый раз объединяет длинную строку? - PullRequest
0 голосов
/ 05 февраля 2019

Я занимаюсь небольшим учебным проектом, он берет список монет из API, а затем создает страницу, полную загрузочной карты для длины массива, полученного из API.Во время разработки я использовал только 100 первых монет, чтобы избежать длительного ожидания, но теперь, когда я закончил, когда я пробую все 3900+ монет, это занимает непрактично много времени.

Я почти уверен, как ядобавленная строка является источником проблемы, я добавлю свой код, и я уверен, что все это будет иметь больше смысла.

Я попытался построить всю строку, а затем добавить ее - ничего хорошего все еще медленно.Я пытался изменить его innerHTML каждый раз, а затем добавлять его (добавить внутри цикла for), но он просто перезаписывает все старые монеты и добавляет только последнюю.

То, что я хочу сделать, это на самом деле добавитькаждый блок отдельно и делайте это за разумное количество времени, сейчас для его завершения требуется более 30 минут, что явно нехорошо.

Текущая версия кода, которую я добавил, - это та, которая занимает много времени, нов конце концов делает все правильно (хотя его всего 50 итераций в цикле for, поэтому он не застревает, если вы попробуете прямо сейчас, это должно быть более 3900 итераций)

function homeStart(coins: any[]): void {

  var divcreate = document.createElement("div");

  for (var i = 0; i < 50; i++) {
    // console.log(coins[i]);
    // ******This is where the string addup starts
    divcreate.innerHTML += `
            <div class="card text-dark bg-dark m-auto makeinline" 
            id="${coins[i].id}${i}" style="max-width: 18rem;">
            <div class="card-header">
                <div class="flexalign">
                    <span class="coinsymbol" 
            id="${coins[i].symbol.toUpperCase() + 
            "a1"}">${coins[i].symbol.toUpperCase()} 
           </span>
                    <label class="switch">
                        <input type="checkbox" 
         id="${coins[i].id}${coins[i].symbol}" 
        onchange="selectedCoinUpdate(this,'${coins[i].symbol}')"> 
                        <span class="slider round"></span>
                    </label>
                </div>
            </div>
            <div class="card-body">
                <div class="">
                    <h5 class="card-title coinname">${coins[i].name}</h5>
                    <button type="button" class="btn btn-secondary" data- 
       toggle="collapse" href="#collapseIdentity${i}" role="button"
                          aria-expanded="false" aria- 
       controls="collapseIdentity${i}" 
       onclick="moreInfo('${coins[i].id}')">More info</button>
                </div>
                    <div class="collapse" id="collapseIdentity${i}">
                        <div class="card-body" id="${coins[i].id}">

                        </div>
                    </div>
                </div>
            </div>`;

  }
  // ******This is where the string addup ends
  $("#pagecont").append(divcreate);

}

Ответы [ 2 ]

0 голосов
/ 05 февраля 2019

Как сказал Кит, вы можете преобразовать свою уникальную операцию синхронизации в несколько задач и запускать эти задачи асинхронным способом (в его примере setTimeout).

Выполнение этого способа вместо одной большой операции улучшает производительность пользовательского интерфейса, но это не так здорово, потому что вы касаетесь DOM.

Касание DOM происходит медленно, поскольку браузер может выполнять множество операций,делать (рисовать, перекомпоновывать и т. д.).Поэтому лучше попросить браузер выполнить ваши задачи, когда для него самое подходящее время обратиться к DOM и к его работе в DOM.

Для этого в браузере есть в основном два метода, которые вы можете использовать:

  • requestAnimationFrame : обычно используется для выполнения анимации, но это лучший момент, чтобы попросить браузер выполнить операцию DOM.
  • requestIdleCallback : для выполнения фоновой и низкоприоритетной работы

Итак, вот пример, объединяющий оба метода: https://codesandbox.io/s/7jz3yjow0q

Itоснована на этой статье для разработчиков Google .

А вот несколько полезных ресурсов, которые можно прочитать о производительности в Интернете:

0 голосов
/ 05 февраля 2019

Для быстрой загрузки элементов DOM, вы можете увидеть эту ссылку -> Утечка памяти в javascript, функции внутри цикла

После того, как все получится настолько быстро, насколько возможно, это все равно может быть слишкоммедленный и потенциально может вызвать зависание / сбой браузера.

Длительная операция синхронизации в JS заблокирует пользовательский интерфейс.

Чтобы предотвратить это, вы можете сделать длительную операцию sync вasync операция, это дает преимущества, дающие UI некоторое передышку.Затем вы можете создать индикатор загрузки и т. Д.

Ниже приведен очень простой пример, я выполняю операцию синхронизации, которая занимает около 100 мс, и делаю это 100 раз.Затем это в сумме составило бы 10 секунд, если вы сделали это без использования async, это было бы не очень приятным опытом для пользователя.

Чтобы доказать, что пользовательский интерфейс не заблокирован, я 'м, затем просто мигает розовый индикатор загрузки, конечно, вы можете сделать вращающийся круг и т. д. После того, как он закончил, он также записывает консоль all done, ..

Надеюсь, этот небольшой пример поможет с длительным запуском sync операции.

ps: я всегда считал, что async/await должен был сделать следующий тик, хотя выполнение цикла без sleep(0) все равно приводило бы к блокировке пользовательского интерфейса на 10 секунд.

const loaddiv = document.querySelector(".loading");

var i = setInterval(() => {
  loaddiv.classList.toggle("loading");  
}, 300);

const sleep = (time) => new Promise((resolve) => setTimeout(resolve, time));

async function blockUI() {
  let now = new Date().getTime();
  const desiredTime = now + 100;
  while (now < desiredTime) {
    now = new Date().getTime(); 
  }
  await sleep(0); //give the UI some breathing space
}

async function longLoop() {
  for (let l = 0; l < 100; l += 1) 
    await blockUI();
  clearInterval(i);  
  console.log("all done");
}

longLoop();
.loading {
  background-color: pink;
}
<div class="loading">
  Loading.
</div>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...