Created
May 14, 2026 21:17
-
-
Save eladkarako/e765b86fb448300a18aabd6042715ed5 to your computer and use it in GitHub Desktop.
sleep - promise wrap around setTimeout, can be cancelled
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* sleep | |
| * promise wrap around setTimeout. | |
| * - can be cancelled (stops the timer and rejects the promise immediately). | |
| * - can be set to execute method, with arguments, within a scope. | |
| * | |
| * ---------------------------------------------------------- simple case. | |
| * (async ()=>{ | |
| * foo(); | |
| * await sleep(50 * 1000); //halts the code-block for 50 seconds. | |
| * bar(); | |
| * })(); | |
| * ---------------------------------------------------------- a button that stops the timer and reject the promise right away (even when the async block is halted due to "wait sleep"). you can re-assign the promise, so the button will be able to cancel whatever sleep you set. this is also a very nice way to reject any promise... | |
| * let promise = undefined; | |
| * const button = document.createElement("button"); | |
| * const click_handler = (ev)=>{ | |
| * if("function" === typeof promise && "function" === typeof promise.cancel_immediately){ //might not be available yet. | |
| * promise.cancel_immediately(); | |
| } | |
| * }; | |
| * button.addEventListener("click", click_handler, {capture:false, passive:true, once:false}); | |
| * document.querySelector("body").appendChild(button); | |
| * | |
| * (async ()=>{ | |
| * promise = sleep(50 * 1000); //returns a promise right away. and populate a variable that is used by the button click. | |
| * await promise(); //halts the async block. but if the user will click the button, it will immediately clear the timeout and reject it. | |
| * })(); | |
| * ---------------------------------------------------------- | |
| */ | |
| const sleep = async (milliseconds, optional_fn, optional_arguments, optional_scope)=>{ "use strict"; | |
| milliseconds = milliseconds || 0; | |
| let is_settled = false; | |
| let timer_id = undefined; //exposed from within the promise. | |
| let promise_reject = undefined; //exposed from within the promise. | |
| const promise = new Promise((resolve, reject)=>{ | |
| promise_reject = reject; //expose, to be able to use it when canceling the timer. which itself is exposed as piggyback on top of the returned promise. | |
| timer_id = setTimeout(()=>{ | |
| if(true === is_settled){ return; } //prevent double-settlement. regardless if resolved or rejected. | |
| is_settled = true; | |
| optional_arguments = optional_arguments || []; | |
| optional_scope = optional_scope || this; | |
| let result = undefined; | |
| if("function" === typeof optional_fn){ | |
| result = optional_fn.apply(optional_scope, optional_arguments); | |
| } | |
| resolve(result); //even if the potential function was not returning a result. | |
| }, milliseconds); | |
| }); | |
| promise.cancel_immediately = ()=>{ //cancel timer and reject promise without waiting for the rest of the time. it does not execute any optional method. | |
| is_settled = true; | |
| clearTimeout(timer_id); | |
| timer_id = null; | |
| const error = "undefined" !== typeof DOMException ? new DOMException("sleep cancelled.","AbortError") : (()=>{ const e = new Error("sleep cancelled."); e.name = "AbortError"; return e; })(); | |
| if("function" === typeof promise_reject){ | |
| promise_reject(error); | |
| } | |
| }; | |
| return promise; | |
| }; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment