【问题标题】:Promise.all resolving earlier than expectedPromise.all 早于预期解决
【发布时间】:2019-03-11 14:59:54
【问题描述】:

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

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

为防止页面在运行此代码时被阻塞,我尝试使用 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();
});

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

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

我可以看到promises2 Promises 直到promises 中的所有内容都解决后才会解决,所以我不明白为什么会这样。我想这是因为我没有正确理解 Promises,或者没有低估使代码异步的原因。

【问题讨论】:

    标签: javascript promise


    【解决方案1】:

    您在填充它之前在promises2 上调用Promise.all,实际上,当您调用它时,它包含一个空数组,因此它在一个空数组上调用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();
    });
    

    我们可以做得更好,没有理由为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;
    });
    

    【讨论】:

    • 谢谢,您的解释清楚地说明了为什么它没有按预期工作。但是,我无法让您的任何一个示例起作用。在解决第一组承诺后,第一个仍然使微调器消失,而第二个似乎根本不起作用。对 n 个元素执行 n 次超时似乎可以分散负载并帮助保持页面响应。
    • @marxjohnson 是的,你是对的,我有一个错误,正在修复。我忘了返回承诺等待第二次。现已修复。
    • 太好了,您的“快速修复”解决方案完美地完成了这项工作,谢谢。
    猜你喜欢
    • 2021-12-20
    • 2016-01-09
    • 2015-08-25
    • 2020-04-06
    • 1970-01-01
    • 2021-10-22
    • 2015-02-10
    • 2020-06-23
    相关资源
    最近更新 更多