首页 > 解决方案 > JS中这个异步循环有更好的实现吗?

问题描述

所以我正在编写一个 node.js 脚本,它使用 Playwright 在浏览器中以设定的时间间隔发送不同的消息。我遇到了脚本异步部分的问题。

我最初是这样设置的

async start() {
  this.interval = setInterval(async () => {
    await sendMessages(this.messages);
  }, 1000);
}

我很确定await关键字在这里什么都不做,只是在 1000 毫秒后执行下一次迭代,无论是否sendMessages完成执行。这导致消息在达到再次发送的间隔要求时被双重发送。

此代码有效,并且是我的问题的主题:

async start() {
  while (!this.stopFlag) {
    await sendMessages(this.messages);
    await timeout(1000);
  }
}

timeout是一个简单的函数,它在调用后解析一个 Promise setTimeout。但是,这似乎有点老套,我不太喜欢这种实现方式。有没有人有更聪明的方法来执行这样的事情?

以下是更多代码细节:

Messenger.js

import Message from './Message.js'
import { timeout } from './Timeout.js'
export default class Messenger {
  constructor(messages, page) {
    this.page = page;
    this.messages = messages.map((msg) => new Message(msg));
    this.stopFlag = false;
  }

  async start() {
    while (!this.stopFlag) {
      await this.sendMessages();
      await timeout(1000);
    }
  }

  async sendMessages() {
    for (const message of this.messages) {
      if (message.shouldSend()) {
        await message.send(this.page);
      }
    }
  }

  stop() {
    this.stopFlag = true;
  }
}

消息.js

export default class Message {
  constructor(message) {
    this.text = message.text;
    this.timing = message.timing;
    this.lastSent = null;
  }

  async send(page) {
    logMessage(`Sending message "${this.text}" in channel.`);
    await playwrightFunctionToSendMessage();
    this.lastSent = new Date();
  }

  shouldSend() {
    // returns a boolean based on this.timing and this.lastSent 
  }
}

标签: javascript

解决方案


而不是stop方法 reassigning this.stopFlag,让它清除间隔或超时。

async start() {
    if (this.timeoutId) return; // timeout is already running - don't start another
    const startTimeout = () => {
        this.timeoutId = setTimeout(() => {
            this.sendMessages()
                .then(() => {
                    if (this.timeoutId) startTimeout();
                })
                .catch(handleErrors); // don't forget this part
        }, 1000); // 1 second between finish of last sendMessages and start of next
    };
    startTimeout();
}
stop() {
    clearTimeout(this.timeoutId);
    this.timeoutId = null;
}

推荐阅读