在 JavaScript / node.js 中具有 A+ 承诺的 While 循环
While loop with A+ promises in JavaScript / node.js
我需要一直调用远程 API 直到得到我需要的响应,我想使用 node.js 中的官方 A+ 承诺。同步伪代码:
params = { remote api call params }
while (true) {
result = callRemoteApi(params)
if isGood(result) {
onSuccess(result)
break
}
params = modify(params)
}
我正在为请求使用 request-promise 库,所以结果可能是这样的:
new Promise(function (resolve, reject) {
var task = request({params})
.then(function (result) {
if (isGood(result)) {
resolve(result);
} else {
task = request({new params}).then(this_function);
}
});
P.S。这与 非常相似,但我想要一个非基于 q 的实现。
像这样的东西应该运作良好:
var remoteApiCall = function(num){
// fake function to resolve promise if random number in range
return new Promise(function(resolve, reject){
return ((Math.random()*10) < num)
? resolve(true)
: reject(false);
})
}
function getUntil(num){
return remoteApiCall(num).then(function(result){
if (result) {
return result
} else {
// call again until you get valid response
return getUntil(num)
}
})
}
getUntil(num).then(...)
以下解决方案解决了一些具体问题:
- 如何打破(否则无休止的)循环
- 如何访问先前失败尝试的结果
- 如何合并你的
params = modify(params)
问题可以分为两部分:
- a repeater/promise 运行ner(它本身 returns 一个 promise 所以我们可以挂钩
onSuccess
它)
- 承诺提供者 - 为转发器创建承诺的函数
转发器看起来像这样:
function repeatUntilSuccess(promiseProvider) {
return new Promise(function (resolve, reject) {
var counter = 0;
function run(failedResult) {
var p = promiseProvider(failedResult, counter++);
if (p instanceof Promise) {
p.then(resolve).catch(run);
} else {
reject(p);
}
}
run();
});
}
"loop" 出现在这一行:p.then(resolve).catch(run);
。转发器一直调用承诺提供者,直到它 returns 解决承诺(在这种情况下转发器解决) 或 直到它不再提供承诺(在这种情况下转发器拒绝).
承诺提供者可以是任何function(previousResult, counter)
returns 承诺(或者不是,如果你想停止循环)。
var params = {/* ... */};
function nextRequest(previousResult, counter) {
if (counter >= 10) return "too many attempts";
if (previousResult) params = modify(params);
return apiRequest(params);
}
(此设置假定 apiRequest()
returns 一个承诺)
现在你可以这样做了:
repeatUntilSuccess(nextRequest).then(onSuccess).catch(onError);
由于您的问题包括将 HTTP 请求包装在 promise 中的附带任务:
function apiRequest(params) {
return new Promise(function (resolve, reject) {
return request(params).then(function (result) {
if (isGood(result)) {
resolve(result);
} else {
reject(result);
}
});
});
}
打开浏览器控制台并运行以下代码段以查看其实际效果。
function repeatUntilSuccess(promiseProvider) {
return new Promise(function (resolve, reject) {
var counter = 0;
function run(failedResult) {
var p = promiseProvider(failedResult, counter++);
if (p instanceof Promise) {
p.then(resolve).catch(run);
} else {
reject(p);
}
}
run();
});
}
// mockup promise that resoves or rejects randomly after a timeout
function randomPromise(num){
return new Promise(function(resolve, reject){
setTimeout(function () {
var randomNum = Math.floor(Math.random() * num * 10);
if (randomNum < num) {
resolve(randomNum);
} else {
reject(randomNum);
}
}, 300);
});
}
// promise provider
function nextPromise(prev, i) {
if (prev) console.info("failed attempt #" + i + ": " + prev);
if (i >= 5) return "too many attempts:" + i;
return randomPromise(100);
}
// run it!
repeatUntilSuccess(nextPromise).then(function (result) {
console.log("success", result);
}).catch(function (result) {
console.log("failed", result);
});
我需要一直调用远程 API 直到得到我需要的响应,我想使用 node.js 中的官方 A+ 承诺。同步伪代码:
params = { remote api call params }
while (true) {
result = callRemoteApi(params)
if isGood(result) {
onSuccess(result)
break
}
params = modify(params)
}
我正在为请求使用 request-promise 库,所以结果可能是这样的:
new Promise(function (resolve, reject) {
var task = request({params})
.then(function (result) {
if (isGood(result)) {
resolve(result);
} else {
task = request({new params}).then(this_function);
}
});
P.S。这与 非常相似,但我想要一个非基于 q 的实现。
像这样的东西应该运作良好:
var remoteApiCall = function(num){
// fake function to resolve promise if random number in range
return new Promise(function(resolve, reject){
return ((Math.random()*10) < num)
? resolve(true)
: reject(false);
})
}
function getUntil(num){
return remoteApiCall(num).then(function(result){
if (result) {
return result
} else {
// call again until you get valid response
return getUntil(num)
}
})
}
getUntil(num).then(...)
以下解决方案解决了一些具体问题:
- 如何打破(否则无休止的)循环
- 如何访问先前失败尝试的结果
- 如何合并你的
params = modify(params)
问题可以分为两部分:
- a repeater/promise 运行ner(它本身 returns 一个 promise 所以我们可以挂钩
onSuccess
它) - 承诺提供者 - 为转发器创建承诺的函数
转发器看起来像这样:
function repeatUntilSuccess(promiseProvider) {
return new Promise(function (resolve, reject) {
var counter = 0;
function run(failedResult) {
var p = promiseProvider(failedResult, counter++);
if (p instanceof Promise) {
p.then(resolve).catch(run);
} else {
reject(p);
}
}
run();
});
}
"loop" 出现在这一行:p.then(resolve).catch(run);
。转发器一直调用承诺提供者,直到它 returns 解决承诺(在这种情况下转发器解决) 或 直到它不再提供承诺(在这种情况下转发器拒绝).
承诺提供者可以是任何function(previousResult, counter)
returns 承诺(或者不是,如果你想停止循环)。
var params = {/* ... */};
function nextRequest(previousResult, counter) {
if (counter >= 10) return "too many attempts";
if (previousResult) params = modify(params);
return apiRequest(params);
}
(此设置假定 apiRequest()
returns 一个承诺)
现在你可以这样做了:
repeatUntilSuccess(nextRequest).then(onSuccess).catch(onError);
由于您的问题包括将 HTTP 请求包装在 promise 中的附带任务:
function apiRequest(params) {
return new Promise(function (resolve, reject) {
return request(params).then(function (result) {
if (isGood(result)) {
resolve(result);
} else {
reject(result);
}
});
});
}
打开浏览器控制台并运行以下代码段以查看其实际效果。
function repeatUntilSuccess(promiseProvider) {
return new Promise(function (resolve, reject) {
var counter = 0;
function run(failedResult) {
var p = promiseProvider(failedResult, counter++);
if (p instanceof Promise) {
p.then(resolve).catch(run);
} else {
reject(p);
}
}
run();
});
}
// mockup promise that resoves or rejects randomly after a timeout
function randomPromise(num){
return new Promise(function(resolve, reject){
setTimeout(function () {
var randomNum = Math.floor(Math.random() * num * 10);
if (randomNum < num) {
resolve(randomNum);
} else {
reject(randomNum);
}
}, 300);
});
}
// promise provider
function nextPromise(prev, i) {
if (prev) console.info("failed attempt #" + i + ": " + prev);
if (i >= 5) return "too many attempts:" + i;
return randomPromise(100);
}
// run it!
repeatUntilSuccess(nextPromise).then(function (result) {
console.log("success", result);
}).catch(function (result) {
console.log("failed", result);
});