Reject a promise and stop timeout on socket-io event

删除回忆录丶 提交于 2021-01-29 07:18:40

问题


I'm currently using the following function to simulate awaiting (sleep) in my Node.js server script.

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

and I'm using it like below. When used in this way, executing the code below that line is paused until 20 seconds have been passed.

await sleep(20000)

Now I want to break this sleeping on a socket-io event, but I can't figure a correct way out to do that.

I tried the following code, but it didn't break the sleep.

// This object holds some properties
var meetings = {

}

function sleep(ms) {
  return new Promise(function(resolve,reject) => {
    var t = setTimeout(resolve, ms)
    // add the function as a "meetings" object property value
    meetings[endSleep] = function(){
      clearTimeout(t)
      reject()
    }    
  });
}

// later, using socket-io
socket.on("end_sleep",function(){
  meetings["endSleep"]()
})

How can I get this functionality to work? all helpful suggestions are highly appreciated.


回答1:


In your case 'break' means 'early resolving', not rejecting. If you calling reject the await statement will throw an error and execution of the async function can be stopped (if try catch block is not used). The code might look a little better::

const CPromise= require("c-promise2");
// cancellable sleep
function sleep(ms, signal) {
    return new CPromise((resolve, reject, {onCancel}) => {
        const timer = setTimeout(resolve, ms);
        onCancel(() => clearTimeout(timer));
    }, {signal}).catch(() => {});
}

(async()=>{
    const sleeper= sleep(30000);
    socket.on("end_sleep",function(){
        sleeper.cancel();
    });
    await sleeper;
})();

or

const abortController= new CPromise.AbortController();

(async()=>{
    await sleep(30000, abortController.signal);
})();

socket.on("end_sleep",function(){
    abortController.abort();
});



回答2:


I would be tempted to wrap this in a class which holds the state of both the timerId and the reject of the returned Promise and use them within a cancel method.

The below demonstrates this:

class Sleeper
{
   wait(ms){
     return  new Promise( (resolve, reject) => {
        this.reject = reject;
        this.t = setTimeout(resolve,ms);
     });
   }
   
   cancel(reason){
    clearTimeout(this.t);
    this.reject(reason);
   }
}
var sleep = new Sleeper();

async function test(){
  
  try{
    await sleep.wait(5000);
    console.log("finished");
  }catch(e){
    console.log("cancelled:", e);
  }
}

document.querySelector("#cancel").addEventListener("click", () => {
   sleep.cancel("cancel button pressed");
});

test();
<button id="cancel">Cancel</button>

I've added the ability to pass a cancel reason, might be useful.


In your code that would look like:

var sleeper = new Sleeper();

socket.on("end_sleep",function(){
  sleeper.cancel(); // pass a reason if you wanted.
})

// your code
await sleeper.wait(20000);



回答3:


I'm not really sure why this works, but I thought to note down what made it work.

Everything was solved when I used resolve instead of reject as follows.

function sleep(ms) {
  return new Promise(function(resolve,reject) => {
    var t = setTimeout(resolve, ms)
    // add the function as a "meetings" object property value
    meetings[endSleep] = function(){
      clearTimeout(t)
      resolve()
    }    
  });
}

If someone can explain why it works this way, please feel free to edit this answer.



来源:https://stackoverflow.com/questions/64152960/reject-a-promise-and-stop-timeout-on-socket-io-event

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!