Почему при использовании цикла while не отображается прокрутка страницы, хотя она присутствует?

Привет!
У меня есть страница, на которой происходит "калибровка" после загрузки. В таблицу вставляются блоки до того момента, пока у страницы не появится скролл. Вот код:
```javascript
var max_tickets = 0;
function calibration() {
    var calibration_cancel = false;
    while(calibration_cancel !== true) {
        var block = document.getElementById('block');
        var isVerticalScroll= block.scrollHeight > block.clientHeight;

        if(isVerticalScroll !== true) {
            $(function(){
                var newElems = $('<tr>')
                .append('<td>0</td>')
                .append('<td>0</td>')
                $('.tables table:first-child').append(newElems);
            });
            max_tickets = max_tickets + 1;
        } else {
            calibration_cancel = true;
        }
    }
    console.log(max_tickets);
}
```
Однако переменная "isVerticalScroll" всегда показывает false. Но если посмотреть значение переменной после выполнения функции (например, если вызвать console.log при нажатии на кнопку), то значение уже будет true.

Что вызывает такое поведение и как его можно исправить?
  • 20 декабря 2023 г. 23:47
Ответы на вопрос 2
Проблема возникает из-за блокировки потока выполнения кода в цикле `while`. В JavaScript однопоточная модель исполнения кода, поэтому когда цикл `while` выполняется, он занимает весь поток выполнения и не позволяет браузеру обновлять пользовательский интерфейс (включая прокрутку страницы).

Решение проблемы заключается в том, чтобы использовать асинхронные функции или методы, чтобы освободить поток выполнения. В данном случае можно использовать метод `setTimeout`, чтобы задержать каждую итерацию цикла и дать браузеру возможность обновить интерфейс перед продолжением выполнения кода.

Вот пример решения:

```javascript
var max_tickets = 0;

function calibration() {
    var calibration_cancel = false;

    function insertBlock() {
        var newElems = $('<tr>')
            .append('<td>0</td>')
            .append('<td>0</td>');
        $('.tables table:first-child').append(newElems);

        max_tickets = max_tickets + 1;
    }

    function checkScroll() {
        var block = document.getElementById('block');
        var isVerticalScroll = block.scrollHeight > block.clientHeight;

        if (isVerticalScroll !== true) {
            insertBlock();
        } else {
            calibration_cancel = true;
            console.log(max_tickets);
        }

        if (!calibration_cancel) {
            setTimeout(checkScroll, 0);
        }
    }
    
    setTimeout(checkScroll, 0);
}
```

В этом примере `checkScroll` вызывается с использованием `setTimeout(checkScroll, 0)`, что позволяет освободить поток выполнения после каждой итерации цикла. Это позволит браузеру обновлять интерфейс, включая прокрутку страницы. Когда условие `isVerticalScroll !== true` становится ложным, вызывается `insertBlock`, а затем, если `calibration_cancel` все еще равно `false`, `checkScroll` вызывается снова через `setTimeout`.
Потому что ваш цикл while блочит поток выполнения. 
Можно воспользоваться функцией setInterval – каждый новый запуск будет выполнятся в новой итерации цикла событий ( event loop ), давая браузеру время на выполнение других необходимых задач. Например пересчитать и перерисовать объекты на странице.

Похожие вопросы