L
L
leha_trushin2017-08-08 09:41:07
JavaScript
leha_trushin, 2017-08-08 09:41:07

The output of the results of the chain of promises works strangely, why?

Hello!
There is a more global task, but I implemented it on a simple test, where the result is identical. A simple example. We consider the sums of an arithmetic progression in a chain of successive promises. In reality, instead of a progression, a rather long (several seconds) process is considered, so a pseudo-delay is inserted into the arithmetic progression to emulate this situation. We display the result on the page. The code:

$(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));
    });
}

If left in this form (SetTimeout is commented out in the arithmetic progression promise), then the behavior is as follows: when the page loads, everything hangs (it doesn’t even load in the js debugger) until everything works out. That is, it feels like the chain of promises is blocking the main thread of execution. Although promises themselves are asynchronous. But if you turn on timeouts (even with 0 delay), then everything starts working as it should: progressions are counted one by one asynchronously - the main thread does not hang.
I almost learned this article by heart. But all the same, it feels like I don’t understand something fundamentally in promises.
The chain of promises is based on the solution of this problem + search in the Internet.
PS I immediately made a sample for viewing in the sandbox: option
1 (when everything hangs and the result is issued at once) option
2 (when it works as it should)
PPS Although even in the second option there is some non-linearity of execution (some results are issued with a delay, some are faster) . Obviously, the point here is not the difference in the "complexity" of calculating an arithmetic progression from 0 to 1 and from 0 to 10.

Answer the question

In order to leave comments, you need to log in

1 answer(s)
0
0xD34F, 2017-08-08
@leha_trushin

Promises themselves are asynchronous

This is your fundamental mistake. They are not asynchronous. Promise executes the function passed to it immediately. Here, inside the passed function, you can do something asynchronous.
And you can not do it - as you did in the first case. It turns out like this - a promise is created, resolve occurs immediately, then the next promise is created in the loop, which in turn is also immediately resolved, and so on. As a result, the browser has no way to update the DOM because the thread is busy. The update only happens after the loop has completed.
In the second case, setTimeout calls interrupt your code execution, giving the browser a chance to update the DOM. "Even with 0 delay" is also not surprising, since zero delay does not mean "right now", but "as soon as the execution thread is freed".

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question