You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在事件触发时终止函数进程?现有方案问题分析

如何通过事件触发立即终止异步函数进程?

我需要在事件触发时终止异步函数进程。在函数内部抛出错误(例如在任意步骤的delay中抛错)可以正常终止进程,但如果通过事件监听器来终止进程,在监听器内抛错会导致进程继续运行,且错误会被视为Unhandled Rejection或DOMException——这是因为错误是在监听器上下文而非主函数上下文抛出的,无法影响主进程。

以下是我尝试的几种方案及存在的问题:

  • 在事件监听器内抛错终止进程:进程仍正常运行,错误被标记为Unhandled Rejection或DOMException
(() => {
  class EventEmitter {
    constructor() {
      this.events = {};
    }

    on(event, listener) {
      if (!this.events[event]) {
        this.events[event] = [];
      }

      this.events[event].push(listener);

      // Return a function that can be used to remove this specific listener
      return () => {
        this.off(event, listener);
      };
    }

    emit(event, ...args) {
      if (this.events[event]) {
        this.events[event].forEach(listener => listener(...args));
      }
    }

    removeListeners(event) {
      delete this.events[event];
    }

    off(event, listener) {
      if (this.events[event]) {
        this.events[event] = this.events[event].filter(existingListener => existingListener !== listener);
      }
    }
  }

  const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
  const processEmitter = new EventEmitter();

  async function startProcess(params) {
    try {
      const removeListener = processEmitter.on('stop', async () => {
        removeListener(); 
        throw new Error(`Process stopped due to external event`); 
      });

      await delay(2000);
      console.log('finished step 1');
      await delay(2000);
      console.log('finished step 2');
      await delay(2000);
      console.log('finished step 3');
      await delay(2000);
      console.log('finished step 4');
      await delay(2000);
      console.log('finished step 5');
      await delay(2000);
      console.log('finished step 6');
    } catch (err) {
      console.log('Process terminated:', err.message);
    } finally {
      console.log('done !!')
    }
  }

  startProcess();

  setTimeout(() => {
    processEmitter.emit('stop');
  }, 5000);
})();
  • 用Proxy在值变更时抛错:仍无法终止进程
(() =>  {
  const processEmitter = new EventEmitter();
  async function startProcess(params) {
    try {
      // use proxy as a middleware when the value change
      const abortHandler = new Proxy({ msg: '' }, {
        set(target, key, value) {
          target[key] = value;
          throw new Error(value);
        }
      });

      const removeListener = processEmitter.on('stop', async () => {
        removeListener(); 
        abortHandler.msg = `Process stopped due to external event`; 
      });

      await delay(2000);
      console.log('finished step 1');
      await delay(2000);
      console.log('finished step 2');
      await delay(2000);
      console.log('finished step 3');
      await delay(2000);
      console.log('finished step 4');
      await delay(2000);
      console.log('finished step 5');
      await delay(2000);
      console.log('finished step 6');
    } catch (err) {
      console.log('Process terminated:', err.message);
    } finally {
      console.log('done !!')
    }
  }

  startProcess();

  setTimeout(() => {
    processEmitter.emit('stop');
  }, 5000);
})();
  • 用自定义reject函数抛错:因上下文问题失败
(() =>  {
  const processEmitter = new EventEmitter();
  async function startProcess(params) {
    try {
      // use proxy as a middleware when the value change
      const reject = msg => {
        throw new Error(msg);
      } 

      const removeListener = processEmitter.on('stop', async () => {
        removeListener(); 
        reject(`Process stopped due to external event`); 
      });

      await delay(2000);
      console.log('finished step 1');
      await delay(2000);
      console.log('finished step 2');
      await delay(2000);
      console.log('finished step 3');
      await delay(2000);
      console.log('finished step 4');
      await delay(2000);
      console.log('finished step 5');
      await delay(2000);
      console.log('finished step 6');
    } catch (err) {
      console.log('Process terminated:', err.message);
    } finally {
      console.log('done !!')
    }
  }

  startProcess();

  setTimeout(() => {
    processEmitter.emit('stop');
  }, 5000);
})();
  • 用Promise包裹并调用reject:进程仍继续运行
(() => {
  const processEmitter = new EventEmitter();
  async function startProcess(params) {
    return new Promise(async (_resolve, reject) => {
      try {
        const removeListener = processEmitter.on('stop', async () => {
          removeListener();
          reject(`Process stopped due to external event`);
        });

        await delay(2000);
        console.log('finished step 1');
        await delay(2000);
        console.log('finished step 2');
        await delay(2000);
        console.log('finished step 3');
        await delay(2000);
        console.log('finished step 4');
        await delay(2000);
        console.log('finished step 5');
        await delay(2000);
        console.log('finished step 6');
      } catch (err) {
        console.log('Process terminated:', err.message);
      } finally {
        console.log('done !!')
      }
    })
  }

  startProcess();

  setTimeout(() => {
    processEmitter.emit('stop');
  }, 5000);
})();
  • 使用AbortController或标记变量:存在代码冗余且无法立即终止当前执行步骤
(() =>  {
  const delay = (ms, signal) => {
    if (signal?.aborted) {
      throw new Error(signal?.reason || 'Aborted')
    }

    return new Promise(resolve => setTimeout(resolve, ms))
  };

  const processEmitter = new EventEmitter();
  const controller = new AbortController();
  const { signal } = controller;

  async function startProcess(params) {
    try {
      const removeListener = processEmitter.on('stop', async () => {
        removeListener();
        controller.abort('Process stopped due to external event');
      });

      await delay(2000, signal);
      console.log('finished step 1');
      await delay(2000, signal);
      console.log('finished step 2');
      await delay(2000, signal);
      console.log('finished step 3');
      await delay(2000, signal);
      console.log('finished step 4');
      await delay(2000, signal);
      console.log('finished step 5');
      await delay(2000, signal);
      console.log('finished step 6');
    } catch (err) {
      console.log('Process terminated:', err.message);
    } finally {
      console.log('done !!')
    }
  }

  startProcess();

  setTimeout(() => {
    processEmitter.emit('stop');
  }, 5000);
})();
(() =>  {
  const delay = (ms, err) => {
    if (err) {
      throw err;
    }

    return new Promise(resolve => setTimeout(resolve, ms))
  };

  const processEmitter = new EventEmitter();

  async function startProcess(params) {
    try {
      let err = null;
      const removeListener = processEmitter.on('stop', async () => {
        removeListener();
        err = new Error('Process stopped due to external event');
      });

      await delay(2000, err);
      console.log('finished step 1');
      await delay(2000, err);
      console.log('finished step 2');
      await delay(2000, err);
      console.log('finished step 3');
      await delay(2000, err);
      console.log('finished step 4');
      await delay(2000, err);
      console.log('finished step 5');
      await delay(2000, err);
      console.log('finished step 6');
    } catch (err) {
      console.log('Process terminated:', err.message);
    } finally {
      console.log('done !!')
    }
  }

  startProcess();

  setTimeout(() => {
    processEmitter.emit('stop');
  }, 5000);
})();

我希望找到一种无需冗余代码、能立即终止进程的解决方案。


内容来源于Stack Exchange,提问作者Mahmoud Y3c

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 01:14:54