Promise.all 比预期更早解决

mar*_*son 1 javascript promise

我正在使用 Promises 编写我的第一段代码,并得到了一些意想不到的结果。我有一些看起来像这样的代码(使用 jQuery):

$('.loading-spinner').show();
$('.elements').replaceWith(function() {
   // Blocking code to generate and return a replacement element
});
$('.newElements').blockingFunction();
$('.loading-spinner').hide();
Run Code Online (Sandbox Code Playgroud)

为了防止页面在运行此代码时被阻塞,我尝试使用 setTimeout 和 Promises 使其异步,如下所示:

$('.loading-spinner').show();
var promises = [];
var promises2 = [];
$('.elements').each(function(i, el){
    promises[i] = new Promise(function(resolve, reject) {
        setTimeout(function() {
            $(el).replaceWith(function() {
                // Code to generate and return a replacement element
            });
            resolve(true);
        }, 100);
    });
});
Promise.all(promises).then(function(values) {
    $('.newElements').each(function(i, el) {
        promises2[i] = new Promise(function(resolve, reject) {
            setTimeout(function() {
                $(el).blockingFunction();
                resolve(true);
            }, 100);
        });
    });
});
Promise.all(promises2).then(function(values) {
    $('.loading-spinner').hide();
});
Run Code Online (Sandbox Code Playgroud)

我想要实现的是,一旦promises解决了 Promises,就会promises2实例化Promises 。解决这些问题后,加载微调器将被隐藏。

我得到的效果是,虽然页面没有被阻塞很长时间,但一旦所有 Promise 设置好,微调器就会消失,而不是等到它们被解决。

我可以看到promises2Promises 在所有内容都解决之前promises不会解决,所以我不明白为什么会发生这种情况。我想这归结于我没有正确理解 Promises,或者没有低估使代码异步。

Ben*_*aum 6

你叫Promise.all上promises2你填充它之前,其实当你调用它,它包含一个空的阵列,它调用Promise.all一个空的阵列上,从而立即解决,而无需等待中的承诺promises。


快速解决:

function delay(ms){ // quick promisified delay function
    return new Promise(function(r){ setTimeout(r,ms);});
}

var promises = $('.elements').map(function(i, el){
    return delay(100).then(function(){
        $(el).replaceWith(function() {
            // Code to generate and return a replacement element
        });
});
Promises.all(promises).then(function(els){
    var ps = $('.newElements').map(function(i, el) {
        return delay(100).then(function(){ 
            $(el).blockingFunction();
        });
    });
    return Promise.all(ps);
}).then(function(){
    $('.loading-spinner').hide();
});
Run Code Online (Sandbox Code Playgroud)

不过我们可以做得更好,没有理由n为n元素触发超时:

delay(100).then(function(){
    $(".elements").each(function(i,el){ 
        $(el).replaceWith(function(){ /* code to generate element */});
    });
}).
then(function(){ return delay(100); }).
then(function(){
    $('.newElements').each(function(i, el) { $(el).blockingFunction(); });
}).then(function(){
    $('.loading-spinner').hide();
}).catch(function(err){
   throw err;
});
Run Code Online (Sandbox Code Playgroud)