【问题标题】:Recursive sync function with "isResolved" termination condition具有“isResolved”终止条件的递归同步函数
【发布时间】:2021-03-22 01:01:23
【问题描述】:

目前,我定义了两个函数如下:

function getLock() {
  let promise, isPending;
  if (Math.random() > 0.5) {
    promise = new Promise((resolve, reject) => setTimeout(resolve, 1000));
    isPending = true;
  } else {
    promise = Promise.resolve();
    isPending = false;
  }
  return [promise, isPending];
};

function waitForLock() {
  const lockAndIsPending = getLock();
  const lock = lockAndIsPending[0];
  const isPending = lockAndIsPending[1];

  if (!isPending) {
    return lock;
  } else {
    return lock.then(waitForLock);
  }
}

waitForLock().then(() => console.log("done"));

这当然只是为了演示。作为现实世界应用程序的必需品,getLock 总是需要返回一个 Promise。 另外,锁被释放一次后,必须检查它是否仍然被释放(lock.then(waitForLock)),因为实际的释放条件(这里由Math.random()建模)可能同时由于异步而发生变化。这引入了递归。

我当前的代码工作正常:waitForLock() 最终会返回,因为它会在某个时候发生getLock 返回isPending=false,满足终止条件。

但我的目标是摆脱 isPending 作为额外的返回变量。将来,getLock 应该只返回一个承诺。不幸的是,无法检查给定的承诺是否已经解决(参见here),因此我无法在waitForLock 中“计算”isPending。那么如何相应地更改waitForLock

编辑

目标是能够为getLock 使用任何Promise-returning 函数,而对返回或解析值没有特殊限制。所以,如果可能的话,逻辑应该都在waitForLock,而不是getLock

【问题讨论】:

  • 你为什么不直接await getLock()
  • 这不会改变递归问题,对吗?我仍然需要决定是否第二次拨打waitForLock
  • 我不这么认为,请看下面我的回答
  • waitForLock 不是您正在寻找的函数,它返回一个关于何时释放锁的承诺?
  • 是的,当前的实现工作,但它依赖于我想摆脱的“附加信息”(即isPending 变量)。

标签: javascript asynchronous recursion promise


【解决方案1】:

如果我正确理解您要做什么,您只需要一个函数,它以任何一种方式返回一个 Promise,然后等待它:

function getLock() {
  let promise;

  if (Math.random() > 0.5) {
    console.log("Waiting to unlock...")
    promise = new Promise((resolve, reject) => setTimeout(() => resolve("Unlocked!"), 1000));
  } else {
    console.log("Unlocking immediately.")
    promise = Promise.resolve("Unlocked!");
  }
  return promise;
};

// Testing the above function
(async() => {
  for (let i in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) {
    console.log(await getLock())
  }
  console.log("All done")
})()

您甚至可以并行等待所有这些:

function getLock() {
  let promise;

  if (Math.random() > 0.5) {
    console.log("Waiting to unlock...")
    promise = new Promise((resolve, reject) => setTimeout(() => resolve("Unlocked!"), 1000));
  } else {
    console.log("Unlocking immediately.")
    promise = Promise.resolve("Unlocked!");
  }
  return promise;
};

// Testing the above function
(async() => {
  await Promise.all([1,2,3,4,5,6,7,8,9,10].map(getLock))
  console.log("All done")
})()

【讨论】:

  • 问题是锁被解锁一次后,由于等待过程中出现了新的锁定条件,可能会再次重新锁定,所以在“等待”的情况下,我必须重新检查它.我承认,不幸的是,在我的玩具示例中很难看到这一点,但要以其他方式呈现并不容易。
  • 哈,越来越复杂了。我猜你需要一个 Lock 类,具有this.locked 状态,每次这个状态被某些东西改变时,一个解锁过程会自动开始(this.startUnlocking()),最终会以this.locked=false;结束。
  • 好主意,我真的必须重新考虑这种方法。到目前为止,谢谢。
【解决方案2】:

我认为你可以这样做

function getLock() {
  if (Math.random() > 0.5) {
    return new Promise((resolve, reject) => setTimeout(resolve, 1000));
  }

  return Promise.resolve('pending');
};

function waitForLock() {
  const lock = getLock();

  return lock.then((result) => {
    if (result === 'pending') {
      return waitForLock();
    }

    return result;
  })
}

waitForLock().then(() => console.log("done"));

【讨论】:

  • 基本上有两种解决方案,一如既往:带有.then()回调的“承诺风格”,或“等待风格”。
  • @JeremyThille 完全是 ;)
  • 好的,谢谢,这样的事情可能会奏效,但这有点作弊,因为getLock 仍然需要返回isPending 状态(尽管以另一种方式)。目标是为getLock 使用any 承诺返回函数,无需特殊考虑。很抱歉没有说得足够清楚,我会相应地更新问题。
猜你喜欢
  • 1970-01-01
  • 2015-08-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-24
  • 1970-01-01
相关资源
最近更新 更多