caf
Version:
Cancelable Async Flows: a wrapper to treat generators as cancelable async functions
5 lines • 3.25 kB
JavaScript
/*! CAF: shared.mjs
v15.0.1 (c) 2022 Kyle Simpson
MIT License: http://getify.mit-license.org
*/
const CLEANUP_FN=Symbol("Cleanup Function"),TIMEOUT_TOKEN=Symbol("Timeout Token"),REASON=Symbol("Signal Reason"),UNSET=Symbol("Unset"),[SIGNAL_HAS_REASON_DEFINED,MISSING_REASON_EXCEPTION]=function featureDetect(){var n=new AbortController,e=!!Object.getOwnPropertyDescriptor(Object.getPrototypeOf(n.signal),"reason");try{n.abort()}catch(n){}return[e,isNativeAbortException(n.signal.reason)]}();class cancelToken{constructor(n=new AbortController){var e;this.controller=n,this.signal=n.signal,this.signal[REASON]=UNSET;var initPromise=(n,t)=>{var doRej=()=>{if(t&&this.signal){let n=getSignalReason(this.signal);this._trackSignalReason(n),t(n!==UNSET?n:void 0)}t=null};this.signal.addEventListener("abort",doRej,!1),e=()=>{this.signal&&(this.signal.removeEventListener("abort",doRej,!1),this.signal.pr&&(this.signal.pr[CLEANUP_FN]=null)),doRej=null}};this.signal.pr=new Promise(initPromise),this.signal.pr[CLEANUP_FN]=e,this.signal.pr.catch(e),initPromise=e=null}abort(...n){var e=n.length>0?n[0]:UNSET;this._trackSignalReason(e),this.controller&&(SIGNAL_HAS_REASON_DEFINED&&e!==UNSET?this.controller.abort(e):this.controller.abort())}discard(){this.signal&&(this.signal.pr&&(this.signal.pr[CLEANUP_FN]&&this.signal.pr[CLEANUP_FN](),this.signal.pr=null),delete this.signal[REASON],SIGNAL_HAS_REASON_DEFINED||(this.signal.reason=null),this.signal=null),this.controller=null}_trackSignalReason(n){this.signal&&n!==UNSET&&(SIGNAL_HAS_REASON_DEFINED||"reason"in this.signal||(this.signal.reason=n),this.signal[REASON]===UNSET&&(this.signal[REASON]=n))}}export default{CLEANUP_FN:CLEANUP_FN,TIMEOUT_TOKEN:TIMEOUT_TOKEN,UNSET:UNSET,getSignalReason:getSignalReason,cancelToken:cancelToken,signalPromise:signalPromise,processTokenOrSignal:processTokenOrSignal,deferred:deferred,isFunction:isFunction,isPromise:isPromise,invokeAbort:invokeAbort};export{CLEANUP_FN};export{TIMEOUT_TOKEN};export{UNSET};export{getSignalReason};export{cancelToken};export{signalPromise};export{processTokenOrSignal};export{deferred};export{isFunction};export{isPromise};export{invokeAbort};function getSignalReason(n){return n&&n.aborted?SIGNAL_HAS_REASON_DEFINED&&MISSING_REASON_EXCEPTION?isNativeAbortException(n.reason)?UNSET:n.reason:REASON in n?n[REASON]:UNSET:UNSET}function signalPromise(n){if(n.pr)return n.pr;var e,t=new Promise((function c(t,i){e=()=>{if(i&&n){let e=getSignalReason(n);i(e!==UNSET?e:void 0)}i=null},n.addEventListener("abort",e,!1)}));return t[CLEANUP_FN]=function cleanup(){n&&(n.removeEventListener("abort",e,!1),n=null),t&&(t=t[CLEANUP_FN]=e=null)},t.catch(t[CLEANUP_FN]),t}function processTokenOrSignal(n){n instanceof AbortController&&(n=new cancelToken(n));var e=n&&n instanceof cancelToken?n.signal:n;return{tokenOrSignal:n,signal:e,signalPr:signalPromise(e)}}function deferred(){var n;return{pr:new Promise((e=>n=e)),resolve:n}}function isFunction(n){return"function"==typeof n}function isPromise(n){return n&&"object"==typeof n&&"function"==typeof n.then}function isNativeAbortException(n){return"object"==typeof n&&n instanceof Error&&"AbortError"==n.name}function invokeAbort(n,e){isNativeAbortException(e)||e===UNSET?n.abort():n.abort(e)}