Может ли несколько асинхронных функций JS, считывающих и изменяющих одну и ту же переменную, вызвать состояние гонки/неожиданное значение переменной? Нужен совет

#javascript #asynchronous

Вопрос:

Я хочу, чтобы переменная «остающаяся» была >= 0. Если он достигнет 0, следует прекратить выполнение какой-либо операции вычитания.

Есть 2 асинхронные функции, которые проверят «оставшееся» и выполнят вычитание, если и только если >= 0. Очевидно, что это работает так, как я ожидал, но я действительно понятия не имею, как правильно это решить…

Я прочитал статью https://dev.to/loweisz/how-to-avoid-race-conditions-using-asynchronous-javascript-j30 но я не уверен, что это сработает. Разве та же проблема все еще может возникнуть между «если (!заблокировано) {» и «заблокировано = true;»?

Мне нужна помощь…Ниже приведен мой тестовый код

 let remaining = 1000; // remaining should always be >= 0

const fn1 = async () => {
  console.log('fn1 invoked');

  while(remaining > 0) {
    await new Promise(resolve => {
      setTimeout(() => {
        // This is just a simulation of the delay between "while(remaining > 0) {" and "remaining = remaining - 1;"
        resolve();
      }, 1);
    });
    
    remaining = remaining - 1;
    console.log(`fn1 remaining: ${remaining}`);
  }
};

const fn2 = async () => {
  console.log('fn2 invoked');

  while(remaining > 0) {
    await new Promise(resolve => {
      setTimeout(() => {
        // This is just a simulation of the delay between "while(remaining > 0) {" and "remaining = remaining - 1;"
        resolve();
      }, 1);
    });

    remaining = remaining - 1;
    console.log(`fn2 remaining: ${remaining}`);
  }
};

/**
 * run async functions
 */
fn1();
fn2();
 

Комментарии:

1. Да, если у вас есть await разница между проверкой ( while условием) и фактической мутацией переменной ( remaining = … ), у вас есть условие гонки. Если вы действительно удалите эту искусственную задержку, это сработает — синхронные последовательности операторов выполняются синхронно, без параллелизма.

2. Простейший случай, чтобы показать, как это не работает: for (let i=0; i<2000; i ) fn1();

3. Так что на самом деле искусственная задержка является единственной причиной состояния гонки?

4. В конце концов, в JS нет «одновременного выполнения 2 функций», я правильно понял?

5. Причина в том, что две асинхронные функции / обещания выполняются одновременно