@effection/core
Advanced tools
Comparing version 2.0.0-preview.2-ed0bed9 to 2.0.0-preview.3-2febf01
# @effection/core | ||
## 2.0.0-preview.3 | ||
### Patch Changes | ||
- bdedf68: Simplify sleep method | ||
- 2bf5ef4: Make iterator controllers reentrant so they can e.g. halt themselves | ||
## 2.0.0-preview.2 | ||
@@ -4,0 +11,0 @@ |
@@ -6,2 +6,3 @@ import { Controller } from './controller'; | ||
import { Trapper } from '../trapper'; | ||
declare type Continuation = () => IteratorResult<Operation<unknown>>; | ||
export declare class IteratorController<TOut> implements Controller<TOut>, Trapper { | ||
@@ -11,8 +12,12 @@ private controls; | ||
private didHalt; | ||
private didEnter; | ||
private subTask?; | ||
private continuations; | ||
constructor(controls: Controls<TOut>, iterator: OperationIterator<TOut>); | ||
start(): Promise<void>; | ||
resume(iter: () => IteratorResult<Operation<unknown>>): void; | ||
resume(iter: Continuation): void; | ||
step(iter: Continuation): void; | ||
trap(child: Task): void; | ||
halt(): void; | ||
} | ||
export {}; |
@@ -228,2 +228,4 @@ 'use strict'; | ||
this.didHalt = false; | ||
this.didEnter = false; | ||
this.continuations = []; | ||
} // make this an async function to delay the first iteration until the next event loop tick | ||
@@ -246,5 +248,27 @@ | ||
} | ||
} // the purpose of this method is solely to make `step` reentrant, that is we | ||
// should be able to handle a `halt` which occurs while we are already in a | ||
// generator. This is a rare case and should only happen under some edge | ||
// cases, for example a task halting itself, or a task causing one of its | ||
// siblings to fail. | ||
; | ||
_proto.resume = function resume(iter) { | ||
this.continuations.push(iter); // only enter this loop if we aren't already running it | ||
if (!this.didEnter) { | ||
this.didEnter = true; // acquire lock | ||
// use while loop since collection can be modified during iteration | ||
var continuation; | ||
while (continuation = this.continuations.shift()) { | ||
this.step(continuation); | ||
} | ||
this.didEnter = false; // release lock | ||
} | ||
}; | ||
_proto.resume = function resume(iter) { | ||
_proto.step = function step(iter) { | ||
var next; | ||
@@ -694,2 +718,9 @@ | ||
} | ||
}, | ||
halt: function halt() { | ||
try { | ||
return Promise.resolve(Effection.root.halt()).then(function () {}); | ||
} catch (e) { | ||
return Promise.reject(e); | ||
} | ||
} | ||
@@ -703,5 +734,3 @@ }; | ||
task.ensure(function () { | ||
if (timeoutId) { | ||
clearTimeout(timeoutId); | ||
} | ||
return clearTimeout(timeoutId); | ||
}); | ||
@@ -708,0 +737,0 @@ }; |
@@ -1,2 +0,2 @@ | ||
"use strict";var t=require("events");function r(t,r){for(var e=0;e<r.length;e++){var n=r[e];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}function e(t,e,n){return e&&r(t.prototype,e),n&&r(t,n),t}function n(t,r){t.prototype=Object.create(r.prototype),t.prototype.constructor=t,o(t,r)}function i(t){return(i=Object.setPrototypeOf?Object.getPrototypeOf:function(t){return t.__proto__||Object.getPrototypeOf(t)})(t)}function o(t,r){return(o=Object.setPrototypeOf||function(t,r){return t.__proto__=r,t})(t,r)}function s(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],(function(){}))),!0}catch(t){return!1}}function c(t,r,e){return(c=s()?Reflect.construct:function(t,r,e){var n=[null];n.push.apply(n,r);var i=new(Function.bind.apply(t,n));return e&&o(i,e.prototype),i}).apply(null,arguments)}function a(t){var r="function"==typeof Map?new Map:void 0;return(a=function(t){if(null===t||-1===Function.toString.call(t).indexOf("[native code]"))return t;if("function"!=typeof t)throw new TypeError("Super expression must either be null or a function");if(void 0!==r){if(r.has(t))return r.get(t);r.set(t,e)}function e(){return c(t,arguments,i(this).constructor)}return e.prototype=Object.create(t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),o(e,t)})(t)}var u=function(){function t(t){this.controls=t}var r=t.prototype;return r.start=function(){},r.halt=function(){this.controls.halted()},t}();function h(){var t=function(){},r=function(){},e=new Promise((function(e,n){t=e,r=n}));return{resolve:t,reject:r,promise:e}}var l=Symbol("halt"),f=function(){function t(t,r){this.controls=t,this.promise=r,this.haltSignal=h()}var r=t.prototype;return r.start=function(){var t=this;Promise.race([this.promise,this.haltSignal.promise]).then((function(r){r===l?t.controls.halted():t.controls.resolve(r)}),(function(r){t.controls.reject(r)}))},r.halt=function(){this.haltSignal.resolve(l)},t}();function p(t){return t&&"function"==typeof t.then}var d=function(t){function r(){return t.call(this,"halted")||this}return n(r,t),e(r,[{key:"__isEffectionHaltError",get:function(){return!0}}]),r}(a(Error));function v(t){var r;if(!(r=t)||!r.__isEffectionHaltError)throw t}var m=function(){function t(t,r){this.controls=t,this.iterator=r,this.didHalt=!1}var r=t.prototype;return r.start=function(){try{var t=this;return t.resume((function(){return t.iterator.next()})),Promise.resolve()}catch(t){return Promise.reject(t)}},r.resume=function(t){var r;try{r=t()}catch(t){return void this.controls.reject(t)}r.done?this.didHalt?this.controls.halted():this.controls.resolve(r.value):(this.subTask=new E(r.value),this.subTask.addTrapper(this),this.subTask.start())},r.trap=function(t){var r=this;"completed"===t.state&&this.resume((function(){return r.iterator.next(t.result)})),"errored"===t.state&&this.resume((function(){return r.iterator.throw(t.error)})),"halted"===t.state&&this.resume((function(){return r.iterator.throw(new d)}))},r.halt=function(){var t=this;this.didHalt||(this.didHalt=!0,this.subTask&&(this.subTask.removeTrapper(this),this.subTask.halt()),this.resume((function(){return t.iterator.return(void 0)})))},t}(),g=function(){function t(t,r){this.controls=t,this.resolution=r}var r=t.prototype;return r.start=function(){try{this.resolution(this.controls.resolve,this.controls.reject)}catch(t){this.controls.reject(t)}},r.halt=function(){this.controls.halted()},t}(),y=function(){function t(t,r){this.controls=t,this.operation=r}var r=t.prototype;return r.start=function(t){var r,e;try{r=this.operation(t)}catch(t){return void this.controls.reject(t)}e=p(r)?new f(this.controls,r):"function"==typeof r?new g(this.controls,r):new m(this.controls,r),this.controller=e,e.start()},r.halt=function(){try{if(!this.controller)throw new Error("INTERNAL ERROR: halt called before start, this should never happen");return this.controller.halt(),Promise.resolve()}catch(t){return Promise.reject(t)}},t}();function w(t){return JSON.stringify(t)}var b=function(){function t(t){this.emitter=t,this.current="pending"}var r=t.prototype;return r.transition=function(t,r){var e=this.current,n=r[e];if(!n){var i=Object.keys(r).map(w).join(", ");throw new Error("INTERNAL ERROR: state transition "+w(t)+" is not valid in current state "+w(e)+", should be one of "+i)}this.current=n,this.emitter.emit("state",{from:e,to:n})},r.start=function(){this.transition("start",{pending:"running"})},r.resolve=function(){this.transition("resolve",{running:"completing",completing:"completing",erroring:"erroring",halting:"halting"})},r.reject=function(){this.transition("reject",{running:"erroring",completing:"erroring",halting:"erroring",erroring:"erroring"})},r.halt=function(){this.transition("halt",{running:"halting",completing:"halting",halting:"halting",erroring:"erroring",halted:"halted",completed:"completed",errored:"errored"})},r.finish=function(){this.transition("finish",{completing:"completed",erroring:"errored",halting:"halted"})},e(t,[{key:"isFinishing",get:function(){return["completing","halting","erroring"].includes(this.current)}}]),t}(),j=0,E=function(t){function r(r,e){var n;if(void 0===e&&(e={}),(n=t.call(this)||this).operation=r,n.options=e,n.id=++j,n.children=new Set,n.trappers=new Set,n.ensureHandlers=new Set,n.deferred=h(),n.stateMachine=new b(function(t){if(void 0===t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return t}(n)),n.controls={resolve:function(t){n.stateMachine.resolve(),n.result=t,n.children.forEach((function(t){t.options.blockParent||t.halt()})),n.resume()},reject:function(t){n.stateMachine.reject(),n.result=void 0,n.error=t,n.children.forEach((function(t){return t.halt()})),n.resume()},halted:function(){n.stateMachine.halt(),n.children.forEach((function(t){return t.halt()})),n.resume()}},r)if(p(r))n.controller=new f(n.controls,r);else{if("function"!=typeof r)throw new Error("unkown type of operation: "+r);n.controller=new y(n.controls,r)}else n.controller=new u(n.controls);return n.deferred.promise.catch((function(){})),n}n(r,t);var i=r.prototype;return i.start=function(){this.stateMachine.start(),this.controller.start(this)},i.resume=function(){var t=this;this.stateMachine.isFinishing&&0===this.children.size&&(this.stateMachine.finish(),this.ensureHandlers.forEach((function(t){return t()})),this.trappers.forEach((function(r){return r.trap(t)})),"completed"===this.state?this.deferred.resolve(this.result):"halted"===this.state?this.deferred.reject(new d):"errored"===this.state&&this.deferred.reject(this.error))},i.then=function(t,r){return this.deferred.promise.then(t,r)},i.catch=function(t){return this.deferred.promise.catch(t)},i.catchHalt=function(){return this.deferred.promise.catch(v)},i.finally=function(t){return this.deferred.promise.finally(t)},i.spawn=function(t,e){if("running"!==this.state)throw new Error("cannot spawn a child on a task which is not running");var n=new r(t,e);return this.link(n),n.start(),n},i.link=function(t){this.children.has(t)||(t.addTrapper(this),this.children.add(t),this.emit("link",t))},i.unlink=function(t){this.children.has(t)&&(t.removeTrapper(this),this.children.delete(t),this.emit("unlink",t))},i.trap=function(t){this.children.has(t)&&("errored"!==t.state||this.options.ignoreChildErrors||this.controls.reject(t.error),this.unlink(t)),this.resume()},i.ensure=function(t){this.ensureHandlers.add(t)},i.addTrapper=function(t){this.trappers.add(t)},i.removeTrapper=function(t){this.trappers.delete(t)},i.halt=function(){try{return this.controller.halt(),Promise.resolve(this.catch((function(){}))).then((function(){}))}catch(t){return Promise.reject(t)}},e(r,[{key:"state",get:function(){return this.stateMachine.current}},{key:Symbol.toStringTag,get:function(){return"[Task "+this.id+"]"}}]),r}(t.EventEmitter);function k(){var t=new E(void 0,{ignoreChildErrors:!0});return t.start(),t}var T={root:k(),reset:function(){try{return Promise.resolve(T.root.halt()).then((function(){T.root=k()}))}catch(t){return Promise.reject(t)}}};exports.Deferred=h,exports.Effection=T,exports.Task=E,exports.deprecated=function(t,r){return function(){try{throw new Error("trace")}catch(r){var e=r.stack.split("\n").slice(3,4),n=e[0];console.warn(t,"\n"+n)}for(var i=arguments.length,o=new Array(i),s=0;s<i;s++)o[s]=arguments[s];return r.call.apply(r,[this].concat(o))}},exports.run=function(t,r){return T.root.spawn(t,r)},exports.sleep=function(t){return function(r){return function(e){var n=setTimeout(e,t);r.ensure((function(){n&&clearTimeout(n)}))}}}; | ||
"use strict";var t=require("events");function r(t,r){for(var e=0;e<r.length;e++){var n=r[e];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}function e(t,e,n){return e&&r(t.prototype,e),n&&r(t,n),t}function n(t,r){t.prototype=Object.create(r.prototype),t.prototype.constructor=t,o(t,r)}function i(t){return(i=Object.setPrototypeOf?Object.getPrototypeOf:function(t){return t.__proto__||Object.getPrototypeOf(t)})(t)}function o(t,r){return(o=Object.setPrototypeOf||function(t,r){return t.__proto__=r,t})(t,r)}function s(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],(function(){}))),!0}catch(t){return!1}}function c(t,r,e){return(c=s()?Reflect.construct:function(t,r,e){var n=[null];n.push.apply(n,r);var i=new(Function.bind.apply(t,n));return e&&o(i,e.prototype),i}).apply(null,arguments)}function a(t){var r="function"==typeof Map?new Map:void 0;return(a=function(t){if(null===t||-1===Function.toString.call(t).indexOf("[native code]"))return t;if("function"!=typeof t)throw new TypeError("Super expression must either be null or a function");if(void 0!==r){if(r.has(t))return r.get(t);r.set(t,e)}function e(){return c(t,arguments,i(this).constructor)}return e.prototype=Object.create(t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),o(e,t)})(t)}var u=function(){function t(t){this.controls=t}var r=t.prototype;return r.start=function(){},r.halt=function(){this.controls.halted()},t}();function h(){var t=function(){},r=function(){},e=new Promise((function(e,n){t=e,r=n}));return{resolve:t,reject:r,promise:e}}var l=Symbol("halt"),f=function(){function t(t,r){this.controls=t,this.promise=r,this.haltSignal=h()}var r=t.prototype;return r.start=function(){var t=this;Promise.race([this.promise,this.haltSignal.promise]).then((function(r){r===l?t.controls.halted():t.controls.resolve(r)}),(function(r){t.controls.reject(r)}))},r.halt=function(){this.haltSignal.resolve(l)},t}();function p(t){return t&&"function"==typeof t.then}var d=function(t){function r(){return t.call(this,"halted")||this}return n(r,t),e(r,[{key:"__isEffectionHaltError",get:function(){return!0}}]),r}(a(Error));function v(t){var r;if(!(r=t)||!r.__isEffectionHaltError)throw t}var m=function(){function t(t,r){this.controls=t,this.iterator=r,this.didHalt=!1,this.didEnter=!1,this.continuations=[]}var r=t.prototype;return r.start=function(){try{var t=this;return t.resume((function(){return t.iterator.next()})),Promise.resolve()}catch(t){return Promise.reject(t)}},r.resume=function(t){if(this.continuations.push(t),!this.didEnter){var r;for(this.didEnter=!0;r=this.continuations.shift();)this.step(r);this.didEnter=!1}},r.step=function(t){var r;try{r=t()}catch(t){return void this.controls.reject(t)}r.done?this.didHalt?this.controls.halted():this.controls.resolve(r.value):(this.subTask=new j(r.value),this.subTask.addTrapper(this),this.subTask.start())},r.trap=function(t){var r=this;"completed"===t.state&&this.resume((function(){return r.iterator.next(t.result)})),"errored"===t.state&&this.resume((function(){return r.iterator.throw(t.error)})),"halted"===t.state&&this.resume((function(){return r.iterator.throw(new d)}))},r.halt=function(){var t=this;this.didHalt||(this.didHalt=!0,this.subTask&&(this.subTask.removeTrapper(this),this.subTask.halt()),this.resume((function(){return t.iterator.return(void 0)})))},t}(),g=function(){function t(t,r){this.controls=t,this.resolution=r}var r=t.prototype;return r.start=function(){try{this.resolution(this.controls.resolve,this.controls.reject)}catch(t){this.controls.reject(t)}},r.halt=function(){this.controls.halted()},t}(),y=function(){function t(t,r){this.controls=t,this.operation=r}var r=t.prototype;return r.start=function(t){var r,e;try{r=this.operation(t)}catch(t){return void this.controls.reject(t)}e=p(r)?new f(this.controls,r):"function"==typeof r?new g(this.controls,r):new m(this.controls,r),this.controller=e,e.start()},r.halt=function(){try{if(!this.controller)throw new Error("INTERNAL ERROR: halt called before start, this should never happen");return this.controller.halt(),Promise.resolve()}catch(t){return Promise.reject(t)}},t}();function w(t){return JSON.stringify(t)}var b=function(){function t(t){this.emitter=t,this.current="pending"}var r=t.prototype;return r.transition=function(t,r){var e=this.current,n=r[e];if(!n){var i=Object.keys(r).map(w).join(", ");throw new Error("INTERNAL ERROR: state transition "+w(t)+" is not valid in current state "+w(e)+", should be one of "+i)}this.current=n,this.emitter.emit("state",{from:e,to:n})},r.start=function(){this.transition("start",{pending:"running"})},r.resolve=function(){this.transition("resolve",{running:"completing",completing:"completing",erroring:"erroring",halting:"halting"})},r.reject=function(){this.transition("reject",{running:"erroring",completing:"erroring",halting:"erroring",erroring:"erroring"})},r.halt=function(){this.transition("halt",{running:"halting",completing:"halting",halting:"halting",erroring:"erroring",halted:"halted",completed:"completed",errored:"errored"})},r.finish=function(){this.transition("finish",{completing:"completed",erroring:"errored",halting:"halted"})},e(t,[{key:"isFinishing",get:function(){return["completing","halting","erroring"].includes(this.current)}}]),t}(),E=0,j=function(t){function r(r,e){var n;if(void 0===e&&(e={}),(n=t.call(this)||this).operation=r,n.options=e,n.id=++E,n.children=new Set,n.trappers=new Set,n.ensureHandlers=new Set,n.deferred=h(),n.stateMachine=new b(function(t){if(void 0===t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return t}(n)),n.controls={resolve:function(t){n.stateMachine.resolve(),n.result=t,n.children.forEach((function(t){t.options.blockParent||t.halt()})),n.resume()},reject:function(t){n.stateMachine.reject(),n.result=void 0,n.error=t,n.children.forEach((function(t){return t.halt()})),n.resume()},halted:function(){n.stateMachine.halt(),n.children.forEach((function(t){return t.halt()})),n.resume()}},r)if(p(r))n.controller=new f(n.controls,r);else{if("function"!=typeof r)throw new Error("unkown type of operation: "+r);n.controller=new y(n.controls,r)}else n.controller=new u(n.controls);return n.deferred.promise.catch((function(){})),n}n(r,t);var i=r.prototype;return i.start=function(){this.stateMachine.start(),this.controller.start(this)},i.resume=function(){var t=this;this.stateMachine.isFinishing&&0===this.children.size&&(this.stateMachine.finish(),this.ensureHandlers.forEach((function(t){return t()})),this.trappers.forEach((function(r){return r.trap(t)})),"completed"===this.state?this.deferred.resolve(this.result):"halted"===this.state?this.deferred.reject(new d):"errored"===this.state&&this.deferred.reject(this.error))},i.then=function(t,r){return this.deferred.promise.then(t,r)},i.catch=function(t){return this.deferred.promise.catch(t)},i.catchHalt=function(){return this.deferred.promise.catch(v)},i.finally=function(t){return this.deferred.promise.finally(t)},i.spawn=function(t,e){if("running"!==this.state)throw new Error("cannot spawn a child on a task which is not running");var n=new r(t,e);return this.link(n),n.start(),n},i.link=function(t){this.children.has(t)||(t.addTrapper(this),this.children.add(t),this.emit("link",t))},i.unlink=function(t){this.children.has(t)&&(t.removeTrapper(this),this.children.delete(t),this.emit("unlink",t))},i.trap=function(t){this.children.has(t)&&("errored"!==t.state||this.options.ignoreChildErrors||this.controls.reject(t.error),this.unlink(t)),this.resume()},i.ensure=function(t){this.ensureHandlers.add(t)},i.addTrapper=function(t){this.trappers.add(t)},i.removeTrapper=function(t){this.trappers.delete(t)},i.halt=function(){try{return this.controller.halt(),Promise.resolve(this.catch((function(){}))).then((function(){}))}catch(t){return Promise.reject(t)}},e(r,[{key:"state",get:function(){return this.stateMachine.current}},{key:Symbol.toStringTag,get:function(){return"[Task "+this.id+"]"}}]),r}(t.EventEmitter);function k(){var t=new j(void 0,{ignoreChildErrors:!0});return t.start(),t}var T={root:k(),reset:function(){try{return Promise.resolve(T.root.halt()).then((function(){T.root=k()}))}catch(t){return Promise.reject(t)}},halt:function(){try{return Promise.resolve(T.root.halt()).then((function(){}))}catch(t){return Promise.reject(t)}}};exports.Deferred=h,exports.Effection=T,exports.Task=j,exports.deprecated=function(t,r){return function(){try{throw new Error("trace")}catch(r){var e=r.stack.split("\n").slice(3,4),n=e[0];console.warn(t,"\n"+n)}for(var i=arguments.length,o=new Array(i),s=0;s<i;s++)o[s]=arguments[s];return r.call.apply(r,[this].concat(o))}},exports.run=function(t,r){return T.root.spawn(t,r)},exports.sleep=function(t){return function(r){return function(e){var n=setTimeout(e,t);r.ensure((function(){return clearTimeout(n)}))}}}; | ||
//# sourceMappingURL=core.cjs.production.min.js.map |
@@ -226,2 +226,4 @@ import { EventEmitter } from 'events'; | ||
this.didHalt = false; | ||
this.didEnter = false; | ||
this.continuations = []; | ||
} // make this an async function to delay the first iteration until the next event loop tick | ||
@@ -244,5 +246,27 @@ | ||
} | ||
} // the purpose of this method is solely to make `step` reentrant, that is we | ||
// should be able to handle a `halt` which occurs while we are already in a | ||
// generator. This is a rare case and should only happen under some edge | ||
// cases, for example a task halting itself, or a task causing one of its | ||
// siblings to fail. | ||
; | ||
_proto.resume = function resume(iter) { | ||
this.continuations.push(iter); // only enter this loop if we aren't already running it | ||
if (!this.didEnter) { | ||
this.didEnter = true; // acquire lock | ||
// use while loop since collection can be modified during iteration | ||
var continuation; | ||
while (continuation = this.continuations.shift()) { | ||
this.step(continuation); | ||
} | ||
this.didEnter = false; // release lock | ||
} | ||
}; | ||
_proto.resume = function resume(iter) { | ||
_proto.step = function step(iter) { | ||
var next; | ||
@@ -692,2 +716,9 @@ | ||
} | ||
}, | ||
halt: function halt() { | ||
try { | ||
return Promise.resolve(Effection.root.halt()).then(function () {}); | ||
} catch (e) { | ||
return Promise.reject(e); | ||
} | ||
} | ||
@@ -701,5 +732,3 @@ }; | ||
task.ensure(function () { | ||
if (timeoutId) { | ||
clearTimeout(timeoutId); | ||
} | ||
return clearTimeout(timeoutId); | ||
}); | ||
@@ -706,0 +735,0 @@ }; |
@@ -5,2 +5,3 @@ import { Task } from './task'; | ||
reset(): Promise<void>; | ||
halt(): Promise<void>; | ||
}; |
{ | ||
"name": "@effection/core", | ||
"version": "2.0.0-preview.2-ed0bed9", | ||
"version": "2.0.0-preview.3-2febf01", | ||
"main": "dist/index.js", | ||
@@ -23,3 +23,3 @@ "types": "dist/index.d.ts", | ||
"expect": "^25.3.0", | ||
"mocha": "^7.1.1", | ||
"mocha": "^8.3.1", | ||
"ts-node": "^8.8.2", | ||
@@ -26,0 +26,0 @@ "tsdx": "0.13.2", |
@@ -8,6 +8,11 @@ import { Controller } from './controller'; | ||
type Continuation = () => IteratorResult<Operation<unknown>>; | ||
export class IteratorController<TOut> implements Controller<TOut>, Trapper { | ||
private didHalt = false; | ||
private didEnter = false; | ||
private subTask?: Task; | ||
private continuations: Continuation[] = []; | ||
constructor(private controls: Controls<TOut>, private iterator: OperationIterator<TOut>) { | ||
@@ -21,3 +26,22 @@ } | ||
resume(iter: () => IteratorResult<Operation<unknown>>) { | ||
// the purpose of this method is solely to make `step` reentrant, that is we | ||
// should be able to handle a `halt` which occurs while we are already in a | ||
// generator. This is a rare case and should only happen under some edge | ||
// cases, for example a task halting itself, or a task causing one of its | ||
// siblings to fail. | ||
resume(iter: Continuation) { | ||
this.continuations.push(iter); | ||
// only enter this loop if we aren't already running it | ||
if(!this.didEnter) { | ||
this.didEnter = true; // acquire lock | ||
// use while loop since collection can be modified during iteration | ||
let continuation; | ||
while(continuation = this.continuations.shift()) { | ||
this.step(continuation); | ||
} | ||
this.didEnter = false; // release lock | ||
} | ||
} | ||
step(iter: Continuation) { | ||
let next; | ||
@@ -24,0 +48,0 @@ try { |
@@ -15,3 +15,7 @@ import { Task } from './task'; | ||
Effection.root = createRootTask(); | ||
}, | ||
async halt() { | ||
await Effection.root.halt(); | ||
} | ||
} |
@@ -6,8 +6,4 @@ import { Operation } from './operation'; | ||
let timeoutId = setTimeout(resolve, duration); | ||
task.ensure(() => { | ||
if(timeoutId) { | ||
clearTimeout(timeoutId); | ||
} | ||
}); | ||
task.ensure(() => clearTimeout(timeoutId)); | ||
} | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
155273
1950