Как сделать точную функцию сна в Javascript, возможно, используя обещания? - PullRequest
1 голос
/ 02 мая 2020

Я пытаюсь сделать функцию сна в Javascript.

Функция drawLinesToHtmlCanvas() предназначена для рисования случайных линий на холсте HTML, а пользователь должен видеть Линии рисуются в реальном времени.

Для этого примера я использую задержку в 500 мс, но хотел бы иметь возможность от go до 1 мс (или даже в будущем разрешение менее 1 мс)

Первоначально я следовал за ответом из этого поста: Что такое JavaScript версия sleep ()?

    function sleep(ms) {
      return new Promise(resolve => setTimeout(resolve, ms));
    }

    async function drawLinesToHtmlCanvas() {

        // Get canvas and context here...

        var drawSpeed = 500; // ms.

        for (i=0; i<lines; i++) {

            // Draw lines to canvas...

            await sleep(drawSpeed);
        }
    }

И это сработало очень хорошо (см. Выше). Это было эффективно, совсем не замедляло работу браузера и позволяло мне контролировать время.

Проблема заключалась в том, что setTimeout() не может показывать go с точностью до 1 мс, и это то, что я требуется для этой функции.

Поэтому вместо этого я попробовал свой собственный подход следующим образом:

    function sleep(ms) {
        ms = parseInt(ms);
        var now = new Date();
        nowMs = now.valueOf();

        var endMs = nowMs + ms;

        while (endMs > nowMs) {
            nowMs = new Date().valueOf();
        }

        return true;
    }

    function drawLinesToHtmlCanvas() {

        // Get canvas and context here...

        var drawSpeed = 500; // ms.

        for (i=0; i<lines; i++) {

            // Draw lines to canvas...

            while (!sleep(drawSpeed));
        }
    }

Этот метод очень медленный, в то время как l oop, ожидающий нужного времени, израсходует все ресурсы браузера, это совершенно непригодно для использования. Кроме того, во время работы функции drawLinesToHtmlCanvas() строки не обновляются до элемента canvas.

Решение с обещанием setTimeout() было fantasti c, оно просто недостаточно точно для моего требования.

Могу ли я дать обещание, которое работает аналогично первому примеру? Но вместо использования setTimeout() он использует алгоритм, аналогичный моему Date(), теперь по сравнению с окончанием мс сравнения, так как это было бы гораздо более точным?

Линии должны быть в состоянии быть сокращены до 1 мс пока у вас есть обновления в реальном времени, пользователь должен видеть линии, нарисованные на холсте.

1 Ответ

1 голос
/ 02 мая 2020

Даже если бы setTimeout работал на таких очень маленьких временных интервалах, это, вероятно, не сработало бы. Когда вы используете обратные вызовы и / или обещания, вы полагаетесь на JS событие времени выполнения l oop. Это событие l oop только выполняет ваш обратный вызов так быстро, как может. Архитектура будет налагать лаги, которые станут видны, когда вы go ниже 1 мс. Обратный вызов в setTimeout точно не выполняется после того, как пройдет N мс. По прошествии N мс он становится приемлемым только для исполнения. И, наконец, он вызывается только тогда, когда на его ход приходит другое событие l oop tick.

Что касается вашего второго подхода, он не совсем "использует ресурсы". Дело в том, что вы больше не используете событие l oop. Но вы должны помнить, что JS является однопоточным. И из-за этого, когда JS -код выполняется без остановок, он вообще не позволит пользователю взаимодействовать с пользовательским интерфейсом. Пользователь может сделать что-то только между выполнениями обратного вызова события. Поэтому никогда не используйте долгое время в браузере JS в браузере, если вы не хотите испортить пользовательский опыт. Возможно, если вы не используете веб-работников, потому что они позволят вам создавать новые потоки, но тогда вы не сможете ничего оттуда нарисовать.

В целом ваш подход к анимации как «рисовать что-то и спать» довольно наивно. Производительные и плавные анимации - это то, для чего созданы видеокарты, хотя записать их в браузере для эффективного использования видеокарты может быть непросто. Если вы хотите сделать анимацию в браузере, вы должны найти определенные c вызовы функций браузера, сделанные специально для анимации на Canvas или WebGL. Может быть, начать здесь: https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Basic_animations

Также подумайте, если вам действительно нужно, может быть кадров в секунду. Более 1000 кадров в секунду? Может ли монитор сделать это? Как насчет влияния на производительность?

...