Javascript 中止嵌套函数的执行
Javascript abort execution of a nested function
我有一个从程序的多个点调用的函数“main”。 “main”调用另一个函数“child”函数。如果调用主函数,我想中止执行“子”函数。
async function main() {
await child()
}
async child function (){
// doing something. periodically waiting for user's input.
// if 'main' function is called in meantime. abort current excution.
}
从以上评论...
"It sounds like the OP is in need of an abstraction which wraps functions that have to be time and/or condition based and repeatedly invoked into cyclically running (or better clocked) functions which e.g. can get actively terminated. One answer to How does one terminate a counter process which runs in timed intervals? provides both the implementation and a lot of running example code."
''Let's suppose invoking child
triggers an interval of a child related process. Now the OP states ... "I would like to abort [the] execution of [the] child [interval] if main
function is called". Let's suppose this can be achieved from within the main
function. Wouldn't invoking child
(as implemented with the current main
function) not immediately trigger a new child related interval again?''
示例代码...
function childProcess(text) {
console.log(text);
}
const clockedChildProcess = childProcess.clocked(1000);
function main(text) {
clockedChildProcess.terminate();
clockedChildProcess(text);
}
function init() {
document
.forms[0]
.addEventListener('reset', evt => {
clockedChildProcess.terminate();
console.clear();
});
document
.forms[0]
.addEventListener('submit', evt => {
evt.preventDefault();
main(evt
.currentTarget
.elements[1]
.value
);
});
}
init();
body { margin: 0; }
fieldset { margin: 0; padding: 0 3px 4px 3px; }
fieldset [type="text"] { width: 50%; }
.as-console-wrapper { min-height: 75%; top: auto; }
<script>
(function (global, Reflect, Math, Number, Array, Function) {
'use strict';
const DEFAULT_INTERVAL = 200;
const { isFinite, parseInt } = Number;
const { setInterval, clearInterval } = global;
function isFunction(value) {
return (
typeof value === 'function' &&
typeof value.call === 'function' &&
typeof value.apply === 'function'
);
}
function getSanitizedTarget(value) {
return value ?? null;
}
function getSanitizedInteger(value) {
value = parseInt(value, 10);
return isFinite(value) ? value : 0;
}
function getSanitizedPositiveInteger(value) {
return Math.max(getSanitizedInteger(value), 0);
}
function createClockedFunction(interval, target, controller) {
const proceed = this;
let thisArg;
let argsArr;
let clockCount = null;
let clockStart = null;
let timerId = null;
target = getSanitizedTarget(target);
interval = getSanitizedPositiveInteger(interval) || DEFAULT_INTERVAL;
function triggerController() {
controller({
clock: {
interval,
startTime: clockStart,
timestamp: Date.now(),
count: ++clockCount,
},
target: thisArg,
args: [...argsArr],
proceed,
terminate,
});
}
function triggerProceed() {
proceed.apply(thisArg, argsArr);
}
function terminate() {
clearInterval(timerId);
timerId = null;
clockStart = null;
clockCount = null;
}
function isActive() {
return (timerId !== null);
}
function clocked(...argumentsArray) {
thisArg = getSanitizedTarget(this) ?? target;
argsArr = argumentsArray;
if (isActive()) {
terminate();
}
clockCount = 0;
clockStart = Date.now();
const trigger = isFunction(controller)
? triggerController
: triggerProceed;
timerId = setInterval(trigger, interval);
}
clocked.terminate = terminate;
clocked.isActive = isActive;
return (isFunction(proceed) && clocked) || proceed;
}
createClockedFunction.toString = () => 'clocked() { [native code] }';
Reflect.defineProperty(Function.prototype, 'clocked', {
configurable: true,
writable: true,
value: createClockedFunction,
});
}((window || global || this), Reflect, Math, Number, Array, Function));
</script>
<form>
<fieldset>
<legend>log update</legend>
<input type="text" value="Hallo World!" />
<button type="submit">log</button>
<button type="reset">terminate / reset</button>
</fieldset>
</form>
我有一个从程序的多个点调用的函数“main”。 “main”调用另一个函数“child”函数。如果调用主函数,我想中止执行“子”函数。
async function main() {
await child()
}
async child function (){
// doing something. periodically waiting for user's input.
// if 'main' function is called in meantime. abort current excution.
}
从以上评论...
"It sounds like the OP is in need of an abstraction which wraps functions that have to be time and/or condition based and repeatedly invoked into cyclically running (or better clocked) functions which e.g. can get actively terminated. One answer to How does one terminate a counter process which runs in timed intervals? provides both the implementation and a lot of running example code."
''Let's suppose invoking
child
triggers an interval of a child related process. Now the OP states ... "I would like to abort [the] execution of [the] child [interval] ifmain
function is called". Let's suppose this can be achieved from within themain
function. Wouldn't invokingchild
(as implemented with the currentmain
function) not immediately trigger a new child related interval again?''
示例代码...
function childProcess(text) {
console.log(text);
}
const clockedChildProcess = childProcess.clocked(1000);
function main(text) {
clockedChildProcess.terminate();
clockedChildProcess(text);
}
function init() {
document
.forms[0]
.addEventListener('reset', evt => {
clockedChildProcess.terminate();
console.clear();
});
document
.forms[0]
.addEventListener('submit', evt => {
evt.preventDefault();
main(evt
.currentTarget
.elements[1]
.value
);
});
}
init();
body { margin: 0; }
fieldset { margin: 0; padding: 0 3px 4px 3px; }
fieldset [type="text"] { width: 50%; }
.as-console-wrapper { min-height: 75%; top: auto; }
<script>
(function (global, Reflect, Math, Number, Array, Function) {
'use strict';
const DEFAULT_INTERVAL = 200;
const { isFinite, parseInt } = Number;
const { setInterval, clearInterval } = global;
function isFunction(value) {
return (
typeof value === 'function' &&
typeof value.call === 'function' &&
typeof value.apply === 'function'
);
}
function getSanitizedTarget(value) {
return value ?? null;
}
function getSanitizedInteger(value) {
value = parseInt(value, 10);
return isFinite(value) ? value : 0;
}
function getSanitizedPositiveInteger(value) {
return Math.max(getSanitizedInteger(value), 0);
}
function createClockedFunction(interval, target, controller) {
const proceed = this;
let thisArg;
let argsArr;
let clockCount = null;
let clockStart = null;
let timerId = null;
target = getSanitizedTarget(target);
interval = getSanitizedPositiveInteger(interval) || DEFAULT_INTERVAL;
function triggerController() {
controller({
clock: {
interval,
startTime: clockStart,
timestamp: Date.now(),
count: ++clockCount,
},
target: thisArg,
args: [...argsArr],
proceed,
terminate,
});
}
function triggerProceed() {
proceed.apply(thisArg, argsArr);
}
function terminate() {
clearInterval(timerId);
timerId = null;
clockStart = null;
clockCount = null;
}
function isActive() {
return (timerId !== null);
}
function clocked(...argumentsArray) {
thisArg = getSanitizedTarget(this) ?? target;
argsArr = argumentsArray;
if (isActive()) {
terminate();
}
clockCount = 0;
clockStart = Date.now();
const trigger = isFunction(controller)
? triggerController
: triggerProceed;
timerId = setInterval(trigger, interval);
}
clocked.terminate = terminate;
clocked.isActive = isActive;
return (isFunction(proceed) && clocked) || proceed;
}
createClockedFunction.toString = () => 'clocked() { [native code] }';
Reflect.defineProperty(Function.prototype, 'clocked', {
configurable: true,
writable: true,
value: createClockedFunction,
});
}((window || global || this), Reflect, Math, Number, Array, Function));
</script>
<form>
<fieldset>
<legend>log update</legend>
<input type="text" value="Hallo World!" />
<button type="submit">log</button>
<button type="reset">terminate / reset</button>
</fieldset>
</form>