请知道我不是在寻找减少模式,该模式假定我已经需要事先知道执行次数。递归也太过分了。
我需要执行一个连续返回Promise(已解决/拒绝)的调用,直到在该Promise的返回数据中找到某个关键字伪代码为止:
let response_that_will_come_from_each_promise = null;
do {
response_that_will_come_from_each_promise = execute_my_call_that_is_a_promise();
} while(!('finished_all_calls' in response_that_will_come_from_each_promise ));
不幸的是,这不适用于promises的异步特性。 for循环也不会这样做,因为do
和for
都是同步的。
简而言之,我如何才能继续调用同样会返回N次诺言的相同函数,直到我发现出问题了?
答案 0 :(得分:4)
while
可以在async function
中异步:
async function pollStuff() {
while(!("keyword" in await somePromise());
}
没有异步/等待递归的是您的朋友:
const pollStuff = () =>
somePromise().then(result => "keyword" in result ? "done" : pollStuff())
答案 1 :(得分:0)
为了可重用性和维护性,您可以创建一个构造函数来为您执行此操作:
function PromiseUntil(promiseFn, conditional) {
let trace = (place) => e => console.log(`trace: ${place} :: ${e}`);
return {
[Symbol.asyncIterator]: async function*() {
let p;
while(p != conditional) { p = await promiseFn().catch(trace("PromiseUntil[Symbol.asyncIterator]")) }
yield p;
},
resolve: async function(cb = i => i, err = trace("PromiseUntil.resolve")) {
this.resolve = false;
try {
for await (let p of this) {
this.resolved = true;
return cb(p);
}
} catch (e) {
err(e);
}
}
}
}
它只接受一个promise函数并重复执行,直到解析的Promise返回的值与条件匹配。在下面,它检查它是否等于"awaited value"
。匹配后,将返回该值,并使用该值调用回调函数(在示例console.log
中)。
function PromiseUntil(promiseFn, conditional) {
let trace = (place) => e => console.log(`trace: ${place} :: ${e}`);
return {
[Symbol.asyncIterator]: async function*() {
let p;
while(p != conditional) { p = await promiseFn().catch(trace("PromiseUntil[Symbol.asyncIterator]")) }
yield p;
},
resolve: async function(cb = i => i, err = trace("PromiseUntil.resolve")) {
this.resolve = false;
try {
for await (let p of this) {
this.resolved = true;
return cb(p);
}
} catch (e) {
err(e);
}
}
}
}
let a = () => new Promise(res => (Math.random() >= 0.5) ? (console.log("no"), res("not awaited value")) : (console.log("yes"), res("awaited value")));
let waiter = PromiseUntil(a, "awaited value");
waiter.resolve(console.log);
考虑完上述答案后,最好能传递一个有条件的函数,而不仅仅是传递要匹配的原始值。这样,您可以检查对象属性或任何您想要的比较,等等。
此调整将参数名称从conditional
更改为conditionalFn
,并将while循环从以下位置调整:
while(p != conditional)
收件人:
while(p == undefined || !conditionalFn(p))
在下面,我们构造了两个PromiseUntil
对象。
string
包含"fin"
时解析。 object
(在这种情况下为用户对象)具有id
的{{1}}属性时解析
1
在上面的代码中,PromiseUntil对象将继续尝试并无限期地解决其Promise函数。如果从不满足条件,则可能导致无限递归。为避免这种情况,您可以设置尝试解决该问题的最大持续时间,也可以设置多次尝试。下面演示了如何做到这一点:
function PromiseUntil(promiseFn, conditionalFn) {
let trace = (place) => e => console.log(`trace: ${place} :: ${e}`);
return {
[Symbol.asyncIterator]: async function*() {
let p;
while(p == undefined || !conditionalFn(p)) {
p = await promiseFn().catch(trace("PromiseUntil[Symbol.asyncIterator]"))
}
yield p;
},
resolve: async function(cb = i => i, err = trace("PromiseUntil.resolve")) {
this.resolve = false;
try {
for await (let p of this) {
this.resolved = true;
return cb(p);
}
} catch (e) {
err(e);
}
}
}
}
let a = () => new Promise(res => (Math.random() >= 0.5) ? (console.log("First Example: no"), res("not awaited value")) : (console.log("First Example: yes"), res("First Example: finished"))),
b = () => new Promise(res => (Math.random() >= 0.5) ? (console.log("Second Example: no"), res({ id: 2 })) : (console.log("Second Example: yes"), res({id: 1, name: "John Smith" })) );
let waiter = PromiseUntil(a, val => val.includes("fin"));
waiter.resolve(console.log);
let waiter_two = PromiseUntil(b, user => user.id == 1);
waiter_two.resolve(user => console.log(`Second Example: Found User: ${user.id} , ${user.name}`));