@leha_trushin

Вывод результатов цепочки промисов работает странно, почему?

Всем привет!
Есть более глобальная задача, но реализовал ее на простом тесте, где результат идентичен. Простой пример. Считаем суммы арифметической прогрессии в цепочке последовательных промисов. В реальности вместо прогрессии считается довольно длительный (несколько секунд) процесс, поэтому в арифметическую прогрессию вставлен псевдо-delay для эмуляции данной ситуации. Выводим результат на страницу. Код:
$(document).ready(function() 
{
    TestFunc();
});
//Арифметическая прогрессия
function arithmeticProgression(n)
{
    delay(100);
    return (n !== 0) ? n + arithmeticProgression(n-1) : 0;
}
//Эмуляция задержки
function delay(ms) 
{
    var date = Date.now();
    var curDate = null;
    do 
    {
        curDate = Date.now();
    } while (curDate-date < ms);
}
//Тестовая функция
function TestFunc()
{
    const counter = 10;
    
    $('body').html('');
    
    for (var i = 0; i < counter; i++) 
    {
        $('body').append($("<div id='" + i + "'>i=" + i  + "<span> Новый</span></div>"));
    }
    
    //Начало цепочки промисов
    let chain = Promise.resolve();
    var results = [];
    
    for(let i=0; i<counter; i++)
    {
        chain = chain.then(function()
        {
            $('#' + i + ' span').text(' В процессе');
            return TestPromise(i, 0);
        })
        .then(function(result) 
        {
            $("#" + i + " span").text(' ' + result);
            results.push(result);
        });
    }    
    
    chain.then(function()
    {
        console.log('All done!');
    });
}
//Промис расчета арифметической прогрессии
function TestPromise(n, delay)
{
    delay = delay || 0;
    return new Promise(function(resolve) 
    {
        /*setTimeout(function() 
        {
            resolve("arithmetic progression(1, " + n + ")=" + arithmeticProgression(n));
        }, delay);*/
        resolve("arithmetic progression(1, " + n + ")=" + arithmeticProgression(n));
    });
}

Если оставить в таком виде (закоменчен SetTimeout в промисе арифметической прогрессии), то поведение следующее: при загрузке страницы все виснет (в отладчике js даже не подгружается) до тех пор, пока все не отработает. То есть такое ощущение, что цепочка промисов блокирует основной поток выполнения. Хотя промисы же сами по себе асинхронны. А вот, если включить таймауты (даже с 0 задержкой), то все начинает работать, как надо: прогрессии считаются одна за одной асинхронно - основной поток не виснет.
Уже наизусть практически выучил эту статью. Но все равно такое ощущение, что я в корне чего-то не понимаю в промисах.
Цепочка промисов составлена на основании решения этой задачи + поиск в просторах интернета.
P.S. Сделал сразу образец для просмотра в песочнице:
1 вариант (когда все висит и результат выдается разом)
2 вариант (когда работает так, как нужно)
P.P.S. Хотя даже во втором варианте наблюдается некая нелинейность выполнения (некоторые результаты выдаются с задержкой, некоторые быстрее). Явно тут дело не в разности "сложности" вычисления арифметической прогрессии от 0 до 1 и от 0 до 10.
  • Вопрос задан
  • 347 просмотров
Решения вопроса 1
0xD34F
@0xD34F Куратор тега JavaScript
промисы же сами по себе асинхронны

Это ваша принципиальная ошибка. Не асинхронны они. Promise исполняет переданную ему функцию немедленно. Вот внутри переданной функции можно делать что-то асинхронное.

А можно не делать - как у вас в первом случае. Получается так - промис создаётся, тут же происходит resolve, дальше в цикле создаётся следующий промис, который в свою очередь тоже немедленно резолвится и так далее. В результате у браузера нет возможности обновить DOM, так как поток выполнения занят. Обновление происходит только после того, как цикл завершится.

Во втором же случае вызовы setTimeout прерывают исполнение вашего кода, давая браузеру возможность обновить DOM. "Даже с 0 задержкой" - тоже ничего удивительного, так как нулевая задержка означает не "вот прям сейчас", а "как только поток выполнения освободится".
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы
16 мая 2024, в 23:36
200000 руб./за проект
16 мая 2024, в 23:10
12000 руб./за проект