【问题标题】:How to abort async function when 'stop' event has been emitted发出“停止”事件时如何中止异步功能
【发布时间】:2019-11-23 01:24:07
【问题描述】:

我试图让 puppeteer.js 机器人能够暂停和恢复其工作。 一般来说,我有一个类,其中包含十几个异步方法、事件发射器和一个名为“状态”的属性,使用 setter 来更改它。当我有事件“停止”时,我希望中止一些异步函数。我怎样才能做到这一点?

我认为我需要观察this.state 何时变为“停止”,然后运行return; 但没有找到任何解决方案。 然后我决定尝试为将状态更改为“停止”的事件设置处理程序,但我无法在停止事件的处理程序中中止异步函数。

 constructor() {
    this.state = 'none';
    this.emiter = new events.EventEmitter();
    this.setHandler('stop', () => this.stop());
    this.setHandler('resume', () => this.resume());
    this.setHandler('onLoginPage', () => this.passAuth());
    // ...
    // And dozen of other states with its handlers
 }
 stop= () => this.setState('stoped', true);
 resume = () => this.setState(this.getPreviousState());
 getPreviousState = () => ...

 // Just an example of a state handler. It has async calls as well
 // I want to abort this function when event 'stop' is emitted
 @errorCatcher()
  async passAuth() {
    const { credentials } = Setup.Instance;
    await this.page.waitForSelector(LOGIN);
    await typeToInput(this.page, EMAIL_INPUT, credentials.login);
    await typeToInput(this.page, PWD_INPUT, credentials.pass);
    await Promise.all([
      await this.page.click(LOGIN),
      this.page.waitForNavigation({ timeout: 600000 }),
    ]);
    await this.page.waitFor(500);
    await DomMutations.setDomMutationObserver(this.page, this.socketEmitter);

 // ...
 // And dozen of handlers on corresponding state



 setState(nextState, resume) {
    // Avoiding to change state if we on pause.
    // But resume() can force setstate with argument resume = true;
    if (this.state === 'stoped' && !resume) return false;
    console.log(`\nEmmited FSM#${nextState}`);
    this.emiter.emit(`FSM#${nextState}`);
 }

 setHandler(state, handler) {
    this.emiter.on(`FSM#${state}`, async () => {
      this.state = state;
      console.log(`State has been changed: ${this.getPreviousState()} ==> ${this.state}. Runnig handler.\n`);
      // 
      // On the next line, we run a corresponding handler func,
      // like passAuth() for state 'onLoginPage'. It has has to be aborted
      // if emiter gets 'FSM#stoped' event.
      //
      await handler();
    });
  }

}```

I expect the async functions to be aborted when event emitter emits 'stop';

【问题讨论】:

    标签: node.js error-handling async-await puppeteer dom-events


    【解决方案1】:

    本机是不可能做到的。

    另外,还有其他两种方法可以做到这一点。

    1. 在拨打await 后检查您的状态,例如:
    class Stated {
      async run() {
        await foo()
        if(this.stopped) return
        await bar()
        if(this.stopped) return
        await done()
      }
    }
    
    const s = new Stated()
    s.run()
    
    1. 将generator 与自定义包装器一起使用,而不是async/await。
    // the wrapper
    function co(gen, isStopped = () => false) {
      return new Promise((resolve, reject) => {
        if (!gen || typeof gen.next !== 'function') return resolve(gen)
        onFulfilled()
    
        function onFulfilled(res) {
          let ret
          try {
            ret = gen.next(res)
          } catch (e) {
            return reject(e)
          }
          next(ret)
        }
    
        function onRejected(err) {
          let ret
          try {
            ret = gen.throw(err)
          } catch (e) {
            return reject(e)
          }
          next(ret)
        }
    
        function next(ret) {
          if (ret.done || isStopped()) return resolve(ret.value)
          Promise.resolve(ret.value).then(onFulfilled, onRejected)
        }
      });
    }
    
    // the following is your code:
    class Stated {
      * run() {
        yield foo()
        yield bar()
        yield done()
      }
    }
    
    const s = new Stated()
    co(s.run(), () => s.stopped)
    

    【讨论】:

      猜你喜欢
      • 2021-10-07
      • 1970-01-01
      • 2023-04-11
      • 1970-01-01
      • 1970-01-01
      • 2012-08-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多