当前位置: 首页 > 知识库问答 >
问题:

JavaScript解析已按顺序填充的promise数组中的第一个元素

曾涵育
2023-03-14

我对不同的API(由delayedPromise函数模拟)执行多个请求,每个请求都需要一定的时间才能完成。如果其中一个满足,我返回它解析的值,就这样。我现在一个接一个地做这些,因为第一个请求是最准确的,而第二个则不太准确,等等。因此,如果第一个请求失败,第二个满足,我将返回第二个请求

为了加快速度,我考虑将这些请求并行化。为了实现这一点,我正在创建一个数组,它持有promise,它等待第一个元素的结果,如果失败,它等待第二个元素的结果等...

这是代码:

function promiseTest() {
    return new Promise(function (resolve, reject) {
        let promises = []
        new Promise(async function (resolve, reject) {
            promises.push(delayedPromise(true, 10000, "1")) //If true resolves after 10000 ms; false = reject
            promises.push(delayedPromise(false, 1000, "2"))
            promises.push(delayedPromise(false, 1000, "3"))
            let answer;
            let answer2
            let answer3;
            answer = await promises[0].catch(async err => {
                answer2 = await promises[1].catch(async err => {
                    answer3 = await promises[2].catch(err => { reject(err) })
                })
            })
            if (answer != undefined) {
                resolve(answer)
            }
            else if (answer2 != undefined) {
                resolve(answer2)
            }
            else if (answer3 != undefined) {
                resolve(answer3)
            }

        }).then(res => resolve(res)).catch(err => {reject(err)})

    })
}

function delayedPromise(bool, time,string ="") {
    return new Promise(function (resolve, reject) {
        if (bool) {
            setTimeout(resolve(string), time)
        }
        else {
            setTimeout(reject(), time)
        }
    })
}

问题是,虽然这种方法有效

答:很可能不是最好的解决方案,也很难扩展

B:上面的代码创建了一堆未捕获的异常错误。我相信这是当我收到答案1的结果时,我不会处理其他函数返回的任何拒绝。

有没有更好的方法来解决上述问题?如果有任何想法或改进,我将不胜感激!非常感谢

附言:如果你能更好地表达我的标题,请让我知道我正在努力用一句话来表达我的问题

共有3个答案

太叔昊苍
2023-03-14

我认为,在仍然并行运行promise的同时(为了获得最佳的端到端时间),对结果进行加权以支持promise需要构建一个特殊的循环。我想你可以这样做:

const errResult = Symbol('errResult');

// fns is an array of functions to call
// args is a array of arguments to pass to each function (same args to each)
async function getResult(fns, args) {
    // start all the async operations to run in parallel
    const promises = fns.map(fn => {
        // Rejections will resolve with a sentinel value so we can detect them
        // This helps us avoid ever getting an unhandled rejection error
        // on promises that reject after we've already found our desired value
        return fn(...args).catch(err => {
            return errResult;
        });
    });
    // now await them in order so you can find the first
    // one that completes (in order)
    // Promises that rejected have been converted into an errResult
    // resolve to help in avoiding unhandled rejections
    // after we return with our good first result
    for (let p of promises) {
        let result = await p;
        if (result !== errResult) {
            return result;
        }
    }
    throw new Error('no results');
}


// sample usage:
getResult([fn1, fn2, fn3, fn4], [argA,argB]).then(result => {
    console.log(result);
}).catch(err => {
    console.log("no results found");
});

如果您希望每个函数都有不同的参数,那么只需将其构建到fn1、fn2等中...这样他们就可以用所需的参数调用根函数,然后让args数组成为一个空数组。

蔺弘
2023-03-14

问题中的代码简化为:

function promiseTest() {
    let promises = [
        delayedPromise(true, 10000, '1'),
        delayedPromise(false, 1000, '2'),
        delayedPromise(false, 1000, '3')
    ];
    return promises[0]
    .catch(() => promises[1])
    .catch(() => promises[2]);
}

一旦遇到成功的promise,链将停止捕获,成功的结果将一路下降,以传递(proverd-wrp)给promise测试的调用方。

捕获链也可以写如下。。。

Promise.reject()
.catch(() => promises[0])
.catch(() => promises[1])
.catch(() => promises[2]);

... 这有助于为任意长度的数组制定过程化版本,如下所示:

function promiseTest() {
    let promises = [...]; // array of Promises (any length)
    return promises.reduce((p_, p) => p_.catch(() => p), Promise.reject());
}

假设在制定promise数组时没有采取措施避免未经处理的拒绝,您可以在减少中这样做(使用一系列“分支捕获”)。。。

function promiseTest() {
    let promises = [...]; // array of Promises (any length).
    return promises.reduce((p_, p) => {
        p.catch(() => null); // avoid unhandled rejections.
        return p_.catch(() => p);
    }, Promise.reject());
}
景国兴
2023-03-14

Promise.anyPromise.all解决非常相似,但并不完全符合您的要求。你必须自己建造它。这就是我要做的:

async function first(iterable) {
    const promises = [];
    for (const thenable of iterable) {
        const promise = Promise.resolve(thenable);
        promises.push(promise);
        promise.catch(() => {}); // ignore rejections, we'll handle them later
    }
    const errors = [];
    for (const promise of promises) {
        try {
            return await promise;
        } catch(error) {
            errors.push(error);
        }
    }
    throw new AggregateError(errors);
}
 类似资料:
  • 考虑以下以串行/顺序方式读取文件数组的代码。返回一个promise,该promise仅在按顺序读取所有文件后才解析。 上面的代码可以工作,但我不喜欢必须为事情按顺序发生而做递归。有没有更简单的方法可以重写这段代码,使我不必使用我怪异的函数? 最初,我尝试使用,但这导致所有调用并发发生,这不是我想要的:

  • 将oneArr 按照 twoArr 的顺序进行排序,而且两个数组可能一样长,也可能不一样长, twoArr 是基于oneArr选中的数据,oneArr 是接口返回的数据,

  • 本文向大家介绍Java程序来填充int数组中的元素,包括了Java程序来填充int数组中的元素的使用技巧和注意事项,需要的朋友参考一下 可以使用java.util.Arrays.fill()方法将元素填充到int数组中。此方法将所需的int值分配给Java中的int数组。所需的两个参数是数组名称和要存储在数组元素中的值。 演示此的程序如下所示- 示例 输出结果 现在让我们了解上面的程序。 首先定义

  • 我这里的问题是,获取promise在当前文本之前创建了几个字符,然后在最后创建的promise之后解析。我需要解决的最后一个promise的最新或取消以前的promise时,我改变了文本。 我希望结果总是最新的。 我查找了一些搜索栏示例,但什么也没找到。 我很确定解决方案是保存以前的promise,如果在你创建一个新promise时它仍然悬而未决,就取消它,但是我不知道如何取消promise。 谢

  • 本文向大家介绍JavaScript数组中的第一个元素和最后一个元素?,包括了JavaScript数组中的第一个元素和最后一个元素?的使用技巧和注意事项,需要的朋友参考一下 数组是一组元素。每个元素都有其自己的 索引值。我们可以使用这些索引访问任何元素。但是,对于最后一个元素,直到知道数组中存在的元素数量,我们才知道索引。在这种情况下,我们必须使用逻辑。让我们简要地讨论这些细节。 访问第一个元素 因

  • 本文向大家介绍Java程序来填充字节数组中的元素,包括了Java程序来填充字节数组中的元素的使用技巧和注意事项,需要的朋友参考一下 可以使用java.util.Arrays.fill()方法将元素填充到字节数组中。此方法将所需的字节值分配给Java中的字节数组。所需的两个参数是数组名称和要存储在数组元素中的值。 演示此的程序如下所示- 示例 输出结果 现在让我们了解上面的程序。 首先定义字节数组b