JavaScript链接承诺来自for循环中的LocalForage

JavaScript chaining promises from LocalForage in for loop

本文关键字:循环 LocalForage for 链接 承诺 JavaScript      更新时间:2023-09-26

我正试图从LocalForage库中链接多个getItem承诺,密钥是从数组中读取的。

问题:在所有LocalForage承诺完成后,我需要Resolve或Reject回调来触发。

两个方法都没有正确的调用堆栈。有什么想法吗?

代码1:

function load(keyHandlerPairs, correct, incorrect) {
    var result = {
                    resolved: 0,
                    rejects: 0,
                },
                p = new Promise(function (resolve, reject) {
                    //Retrieve objects from localstorage;
                    if ($.isArray(keyHandlerPairs)) {
                        for (var i = 0; i < keyHandlerPairs.length; i++) {
                            var kv = keyHandlerPairs[i];
                            lf.getItem(kv.key, kv.handler).then(
                                //Resolved
                                function () { console.log('resolved'); result.resolved++; }
                            );
                        }
                    } else {
                        var kv = keyHandlerPairs;
                        lf.getItem(kv.key, kv.handler);
                    }

                    if ((result.resolved + result.rejects) == keyHandlerPairs.length) {
                        console.log(result.resolved, result.rejects, keyHandlerPairs.length);
                        resolve(result);
                    } else {
                        console.log(result.resolved, result.rejects, keyHandlerPairs.length);
                        reject(result);
                    }
                }).then(correct, incorrect);
}

代码alt:

if ($.isArray(keyHandlerPairs)) {
                        var promises = [];
                        for (var i = 0; i < keyHandlerPairs.length; i++) {
                            var kv = keyHandlerPairs[i];
                            promises.push(lf.getItem(kv.key, kv.handler));
                        }
                        Promise
                            .all(promises)
                            .then(function (value) { console.log(value); result.resolved++; })
                            .catch(function (error) { console.log(error); result.rejects++; });
                    } else {
                        var kv = keyHandlerPairs;
                        lf.getItem(kv.key, kv.handler);
                    }

在所有LocalForage承诺完成后,我需要Resolve或Reject回调来触发。

是的。lf.getItem是异步的,但在激发所有调用之后,您正在测试(result.resolved + result.rejects) == keyHandlerPairs.length.resolved.rejects仍然是0(请注意,无论如何都不会增加拒绝次数)。

首先,除了为还不支持promise的单个异步API构造promise之外,不应该使用Promise构造函数。不应该有任何逻辑,只是一个简单的呼吁。假设您希望使用Promise.all来等待所有并发运行的promise,并从中获得组合结果作为数组的promise。你的代码应该是这样的:

if (!$.isArray(keyHandlerPairs))
    keyHandlerPairs = [keyHandlerPairs];
var promises = keyHandlerPairs.map(function(kv) {
    return lf.getItem(kv.key, kv.handler);
});
return Promise.all(promises);

好吧,现在假设你实际上不关心结果和是否所有承诺都成功了,而只关心兑现承诺与拒绝承诺的数量。好吧,没有本地的组合子函数,所以我们需要编写自己的(并使用Promise构造函数)。但是,此功能应该是泛型,与键值处理程序对无关。

Promise.countResolutions = function(promises) {
    var result = {fulfillments:0, rejections:0},
        len = 0;
    return new Promise(function(resolve, reject) {
        function addResult(type) {
            result[type]++;
            if (result.fulfillments+result.rejections == len)
                resolve(result);
            return true;
        }
        try {
            let i = 0;
            for (let promise of promises) {
                let called = false;
                i++;
                promise.then(function onfulfilled() {
                    if (!called) called = addResult("fulfillments");
                }, function onrejected() {
                    if (!called) called = addResult("rejections");
                });
            }
            len = i;
            if (result.fulfillments+result.rejections == len)
                resolve(result);
        } catch (e) {
            reject(e);
        }
    });
};

是的,它并不像一开始看起来那么琐碎(好吧,也许上面的版本有点太详细了)。但一旦您有了这个,您可以简单地用.countResolutions()替换第一个代码段中的.all(),就可以得到预期的结果。