JS safety when accessing variables outside of the async function

I have an async function here, since the messageQueue is changed outside, I want to know if it's safe to be written like this.

this.messageQueue.push(message1);
onChatMessage();
... // some other code
this.messageQueue.push(message2);
onChatMessage();
... // some other code
this.messageQueue.push(message3);
onChatMessage();
...

onChatMessage: async function () {
    if (this.isProcessMsgQ) { return; }
    this.isProcessMsgQ = true;
    for (let i = 0; i < this.messageQueue.length; i++) {
        const msg = this.messageQueue[i];
        try {
            await this.processMessage(msg);
        } catch (err) {
        }
    }
    this.messageQueue = [];
    this.isProcessMsgQ = false;
},

my worry is that, for thread1, right after this.messageQueue = []; and before this.isProcessMsgQ = false;, could thread2 finish the process from adding message2 to the queue, going into onChatMessage, checking this.isProcessMsgQ, and return? if yes, then there's the case that messsage2 will not be processed, any idea to deal with it?

Thanks!

1 answer

  • answered 2020-11-24 23:07 richytong

    It's possible to lose messages between the start of your for loop and when you set this.messageQueue = []. Any messages that are added in that time frame will be lost when you reassign this.messageQueue. To prevent this, use a Promise to track the completion of the message executions, refreshing the queue at the very begining before any of the executions have begun.

    onChatMessage: function () {
        if (this.isProcessMsgQ) { return; }
        this.isProcessMsgQ = true;
        const tmp = this.messageQueue
        this.messageQueue = []
        this.executingAll = Promise.all(
          tmp.map(msg => this.processMessage(msg).catch(() => {}))
        ).then(() => {
          this.isProcessMsgQ = false
        })
    },