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

promise按顺序运行嵌套promise,并在第一次拒绝时解决

贺飞
2023-03-14

我正在努力在以下任务中发送多个AJAX调用。API返回有两个参数:userIdoffsetValue,并返回指定用户的最后10条消息,从指定的偏移量开始。如果偏移量大于用户的消息总数,API将返回空字符串。

我编写了一个函数,返回一个单独的promise,为指定的userIdoffsetValue获取10条消息。

function getMessages(userId, offsetValue) {
    return new Promise(function (resolve, reject) {
        $.ajax(
        {
            url: 'https://example.com/api.php',
            type: 'POST',
            data: {
                action: 'get_messages',
                offset: offsetValue,
                user: userId
            },
            success: function (response) {
                if (response != '') {
                    resolve(response);
                } else {
                    reject(response);
                }
            },
            error: function (response) {
                reject(response);
            }
        });
    });
}

我需要使用.all()为多个用户ID运行并行任务,但是我无法为每个用户ID运行并行子任务(每次将偏移值增加10),因为我事先不知道每个用户有多少条消息,因此,当第一个单独的promise被拒绝时(即offsetValue大于消息总数),执行应该停止。大概是这样的:

var messages = '';

getMessages('Alex', 0)
    .then(function(result) {
        messages += result;

        getMessages('Alex', 10);
            .then(function(result) {
                messages += result;

                getMessages('Alex', 20)
                ....
            });
    });

那么,有没有办法一个接一个地运行带有迭代参数的顺序promise,并在第一次拒绝时解决整体级联结果?


共有1个答案

唐兴思
2023-03-14

首先,您希望避免promise反模式,即当$.ajax()已经返回一个您可以直接使用的promise时,不必要地将代码包装在新的promise中。要解决此问题,请更改为:

// retrieves block of messages starting with offsetValue
// resolved response will be empty if there are no more messages
function getMessages(userId, offsetValue) {
    return $.ajax({
        url: 'https://example.com/api.php',
        type: 'POST',
        data: {
            action: 'get_messages',
            offset: offsetValue,
            user: userId
        }
    });
}

现在,回答你的主要问题。如果您希望在收到拒绝或空响应时停止请求新项目,并且您不知道将提前有多少个请求,那么您几乎必须连续请求,并在收到空响应或错误时停止请求下一个项目。这样做的关键是通过从.then()处理程序返回一个新的promise,将顺序promise链接在一起。

您可以这样做:

function getAllMessagesForUser(userId) {
    var offsetValue = 0;
    var results = [];

    function next() {
        return getMessages(userId, offsetValue).then(function(response) {
            // if response not empty, continue getting more messages
            if (response !== '') {
                // assumes API is returning 10 results at a time
                offsetValue += 10;
                results.push(response);
                // chain next request promise onto prior promise
                return next();
            } else {
                // empty response means we're done retrieving messages
                // so just return results accumulated so far
                return results.join("");
            }
        });
    }
    return next();
}

这将创建一个内部函数,该函数返回一个promise,并且每次它收到一些消息时,它都会将一个新promise链接到原始promise上。因此,getAllMessagesForUser()返回一个单独的promise,该promise使用它检索到的所有消息进行解析,或使用错误拒绝所有消息。

您可以这样使用它:

getAllMessagesForUser('Bob').then(function(messages) {
    // got all messages here
}, function(err) {
    // error here
});

您可以将多个用户并行化(只要您确定没有使服务器过载或遇到速率限制问题),如下所示:

$.when.apply($, ['Bob', 'Alice', 'Ted'].map(function(item) {
    return getAllMessagesForUser(item);
})).then(function() {
    // get results into a normal array
    var results = Array.prototype.slice.call(arguments);
});

另外,Promise.all()使用起来比$好得多。when()(因为它需要一个数组并解析为一个数组),但是因为这里已经涉及到jQuerypromise,而且我不知道您的浏览器兼容性要求,所以我坚持使用jQuerypromise管理,而不是ES6标准promise。

 类似资料:
  • 我在想什么时候我该拒绝一个promise。我发现了几个关于这个话题的问题,但找不到合适的答案。我什么时候应该拒绝promise? 本文http://howtonode.org/6666a4b74d7434144cff717c828be2c3953d46e7/promises 说: 解析:一个成功的promise是“已解析”的,它调用正在等待的成功侦听器,并记住为附加的未来成功侦听器解析的值。分辨率

  • 考虑以下以串行/顺序方式读取文件数组的代码。返回一个promise,该promise仅在按顺序读取所有文件后才解析。 上面的代码可以工作,但我不喜欢必须为事情按顺序发生而做递归。有没有更简单的方法可以重写这段代码,使我不必使用我怪异的函数? 最初,我尝试使用,但这导致所有调用并发发生,这不是我想要的:

  • 我正在使用Firebase云消息服务辅助角色处理后台推送通知。 当通知(其中包含一些数据的URL)被点击,我想要么: 焦点窗口,如果它已经在所需的URL 导航到URL并聚焦它,如果已经有一个活动的选项卡打开 如果上述条件都不满足,则打开URL的新窗口 点1和3与下面的SW代码一起工作。 出于某种原因,第2点不起作用。promise被拒绝,原因是: 我认为这可能是由于缺少https,但从我的阅读来看

  • 我正在尝试编写一个jasmine测试,它有一个间谍, 是一个许诺列表。前几次承诺是拒绝,最后一次是成功。虽然测试顺利通过,但Node抱怨如下: 我的代码非常直接:我创建一个间谍,将它注入到我的代码中,调用我的代码,这将循环调用我的间谍直到它不拒绝,然后监视它被调用了5次。间谍是这样的: 被测试的代码在它的链中最后一个空的 来验证我没有引起那里的问题。AFICT,问题是Node看到我在执行 ,并认为

  • 当我的角度前端发送请求时 我的nodejs服务器接收它 我添加了setTimeout,因为如果没有它,我就会得到错误:状态代码400请求失败。 因此,我可以发布订单到,但得到promise拒绝。 (节点:9220)UnhandledPromiseRejtionWarning:未处理的promise拒绝。这个错误要么是由于抛出一个没有捕获块的异步函数,要么是由于拒绝了一个没有用. cat()处理的p

  • 我不熟悉promise和使用NodeJS中的请求和promise编写网络代码。 我想删除这些嵌套的promise,并将它们链接起来,但我不确定该如何做/这是否是正确的方式。 这是请求代码: 如有任何见解,将不胜感激。