我正在努力在以下任务中发送多个AJAX调用。API返回有两个参数:userId
和offsetValue
,并返回指定用户的最后10条消息,从指定的偏移量开始。如果偏移量大于用户的消息总数,API将返回空字符串。
我编写了一个函数,返回一个单独的promise,为指定的userId
和offsetValue
获取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,并在第一次拒绝时解决整体级联结果?
首先,您希望避免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,并将它们链接起来,但我不确定该如何做/这是否是正确的方式。 这是请求代码: 如有任何见解,将不胜感激。