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>