如何取消JavaScript睡眠?

时间:2020-05-22 01:47:59

标签: javascript asynchronous promise

此功能用于等待毫秒数。

function delay(millis: number) {
    return new Promise((resolve, reject) => {

        setTimeout(() => {
            resolve();
        }, millis);
    });

然后我的目标是使此函数超时吗?

const timeout = await delay(20000);

在其他地方单击时,用户无聊的等待中

clearTimeout(timeout)

4 个答案:

答案 0 :(得分:2)

只需扩展您将发送的Promise对象:

function delay( millis ) {
  let timeout_id;
  let rejector;
  const prom = new Promise((resolve, reject) => {
    rejector = reject;
    setTimeout(() => {
        resolve();
    }, millis);
  });
  prom.abort = () => {
    clearTimeout( timeout_id );
    rejector( 'aborted' );
  };
  return prom;
}

const will_abort = delay( 2000 );
const will_not_abort = delay( 2000 );

will_abort
  .then( () => console.log( 'will_abort ended' ) )
  .catch( console.error );

will_not_abort
  .then( () => console.log( 'will_not_abort ended' ) )
  .catch( console.error );

setTimeout( () => will_abort.abort(), 1000 );

答案 1 :(得分:1)

您可以返回解决/拒绝以及承诺

function delay(millis) {
    let reolver;
    return [new Promise((resolve, reject) => {
        resolver = resolve
        x = setTimeout(() => {
            resolve();
        }, millis);
    }), resolver];
}  

const [sleep1, wake1] = delay(2000)
sleep1.then((x) => console.log(x || 'wakeup 1')) // Auto wake after 2 seconds

const [sleep2, wake2] = delay(2000)
sleep2.then((x) => console.log(x || 'wakeup 2'))
wake2('Custom Wakeup') // sleep2 cancelled will wake from wake2 call 
    

答案 2 :(得分:0)

您可以返回一个函数,该函数从cancelTimer函数调用中以数组的形式取消计时器(Promisedelay对象。

然后根据需要使用cancelTimer清除它,这也会拒绝Promise

function delay(millis) {
  let cancelTimer;
  const promise = new Promise((resolve, reject) => {
    const timeoutID = setTimeout(() => {
      resolve("done");
    }, millis);
    cancelTimer = () => {
      clearTimeout(timeoutID);
      reject("Promise cancelled");
    };
  });
  return [promise, cancelTimer];
}

//DEMO
let [promiseCancelled, cancelTimer] = delay(20000);
(async() => {
  try {
    console.log("Promise result never printed", await promiseCancelled);
  } catch (error) {
    console.error("Promise is rejected", error);
  }
})();
cancelTimer();

const [promise, _] = delay(2000);
(async() => {
  console.log("Promise result printed", await promise);
})();

答案 3 :(得分:0)

我建议您不要通过在其上附加.abort方法来修改诺言。而是从您的延迟函数中返回两个

  1. 延迟值
  2. 可以用来取消超时的函数

重要的是,我们看不到"x"已登录到控制台,因为它已被取消-

function useDelay (x = null, ms = 1000)
{ let t
  return [
    new Promise(r => t = setTimeout(r, ms, x)), // 1
    _ => clearTimeout(t)                        // 2
  ]
}

const [x, abortX] =
  useDelay("x", 5000)
  
const [y, abortY] =
  useDelay("y canceled x", 2000)
  
x.then(console.log, console.error)

y.then(console.log, console.error).finally(_ => abortX())

console.log("loading...")

// loading...
// y canceled x


交互式演示

这是一个交互式示例,允许您等待延迟值或中止它-

function useDelay (x = null, ms = 1000)
{ let t
  return [
    new Promise(r => t = setTimeout(r, ms, x)), // 1
    _ => clearTimeout(t)                        // 2
  ]
}

const [ input, output ] =
  document.querySelectorAll("input")
  
const [go, abort] =
  document.querySelectorAll("button")
  
let loading = false

function reset ()
{ loading = false
  input.value = ""
  go.disabled = false
  abort.disabled = true
}

function load ()
{ loading = true
  go.disabled = true
  abort.disabled = false
}

go.onclick = e => {
  if (loading) return
  load()
    
  const [delayedValue, abortValue] =
    useDelay(input.value, 3000)
    
  abort.onclick = _ => {
    abortValue()
    reset()
  }
  
  delayedValue
    .then(v => output.value = v)
    .catch(e => output.value = e.message)
    .finally(_ => reset())
}
code { color: dodgerblue; }
<input placeholder="enter a value..." />
<button>GO</button>
<button disabled>ABORT</button>
<input disabled placeholder="waiting for output..." />

<p>Click <code>GO</code> and the value will be transferred to the output in 5 seconds.</p>
<p>If you click <code>ABORT</code> the transfer will be canceled.</p>