如何实现重复的Promise呼叫链?

时间:2019-08-14 19:23:53

标签: javascript es6-promise

请知道我不是在寻找减少模式,该模式假定我已经需要事先知道执行次数。递归也太过分了。

我需要执行一个连续返回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循环也不会这样做,因为dofor都是同步的。

简而言之,我如何才能继续调用同样会返回N次诺言的相同函数,直到我发现出问题了?

2 个答案:

答案 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对象。

  • 第一个分配了一个promise函数,该函数将在返回的string包含"fin"时解析。
  • 第二个对象被分配了一个Promise函数,该函数将在返回的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}`));