我怎样才能取消javascript等待睡眠?

u4dcyp6a  于 2022-12-21  发布在  Java
关注(0)|答案(2)|浏览(190)

在javascript中,sleep函数最常见的实现是在setTimeout解析后返回Promise:

function sleep(ms) {
  return new Promise((resolve) => {
    setTimeout(resolve, ms);
  });
}

我有一个带await sleep的for循环来防止它执行得太快,比如不要太快地请求xhr。我在其他地方也有一个isBreak标志来告诉我什么时候停止for循环。然而,我遇到的问题是,当我中断for循环时,先前的AWAIT休眠已经执行并且正在阻止FOR循环。有没有更好的方法来打破for循环,同时立即终止等待睡眠?

const items = [];

let isBreak = false; // Somewhere else in the application

for (const item of items) {
  if (isBreak) break;

  // Do something, like xhr request
  await sleep(15000); // 15 seconds sleep

  if (isBreak) break;
}

有没有办法让我提前发信号

pkbketx9

pkbketx91#

在JS中,当await操作开始时,不能再中断;它将等待直到其操作数承诺被确定。
所以,你必须做出承诺,你是await ing以某种方式取消。
不幸的是,您的代码无法得到变量重新分配的通知(当您将isBreak设置为true时),轮询它将是低效的。
您可以使用AbortSignal(它就是为此目的而发明的)来代替标志,并使您的sleep接受一个标志:

function sleep(ms, signal) {
  return new Promise((resolve, reject) => {
    signal.throwIfAborted();
    const timeout = setTimeout(() => {
      resolve();
      signal.removeEventListener('abort', abort);
    }, ms);
    const abort = () => {
      clearTimeout(timeout);
      reject(signal.reason);
    }
    signal.addEventListener('abort', abort);
  });
}

然后,您可以这样使用它:

const items = [];

const isBreak = new AbortController(); // Somewhere else in the application, call `isBreak.abort()`

try{
  for (const item of items) {
    // Do something, like xhr request
    await sleep(15000, isBreak.signal); // 15 seconds sleep
  }
}catch(e){
  if(e.name === 'TimeoutError'){
    //Handle a cancellation
    console.log('Cancelled');
  }else{
    //Not a cancellation, rethrow it
    throw e;
  }
}

一个AbortSignal也可以很好地与fetch一起工作,以防你也必须取消它。

carvr3hs

carvr3hs2#

我在过去的博客中找到的一个答案,我调整了一下。它和FZs的答案很相似。用法也一样。只是给予一个替代方案。

function sleep(ms, abortSignal) {
  return new Promise((resolve, reject) => {
    signal.addEventListener("abort", abort);
    if(abortSignal.aborted){
      abort();
    }
    const timeout = setTimeout(end, ms);

    function abort() {
      clearTimeout(timeout);
      abortSignal.removeEventListener("abort", abort);
      reject(new Error("sleep aborted"));
    }

    function end() {
      abortSignal.removeEventListener("abort", abort);
      resolve();
    }
  });
}

相关问题