это нормально, чтобы передать асинхронную функцию в качестве Websocket (WS) Listerner?(библиотека node.js и ws) - PullRequest
0 голосов
/ 17 марта 2019

большинство действий, которые должны выполнять мои веб-сокеты, являются асинхронными, поэтому я передаю асинхронную функцию в качестве обратного вызова веб-сокета и вызываю внутри него ожидание вызова, это нормально?если нет, то какая у меня альтернатива?
РЕДАКТИРОВАТЬ: вот мой слушатель сообщения:

ws.on('message', async function (message) {
        if (message instanceof Buffer) {
          if (currentMode == prot.dataMode) {
            await appendData(sessionData,message);
          }
          else {
            console.log("error : unexpected message received");
          }
        }
        // if the message is for defining the mode of communication
        //This message is a configuration message
        else {
          message = JSON.parse(message);
          if (message[prot.modeField] == prot.confMode) {
            console.log("conf mode");
            currentMode = prot.confMode;
            await configure(sessionData,message);
          }
          //The following messages will be data
          else if (message[prot.modeField] == prot.dataMode) {
            console.log("data mode");
            currentMode = prot.dataMode;
          }

          else{
            console.log("unknown message structure : ");
            console.log(message);
          }
        }

      });

1 Ответ

1 голос
/ 17 марта 2019

Если есть вероятность нет отклонения любого из Обещаний, тогда да, с использованием функции async в качестве обработчика все в порядке. Ваш текущий подход будет работать.

Но это нереально. Обработчик обратного вызова не ожидает async функции, и если сгенерированное им обещание отклоняет, вы получите UnhandledPromiseRejectionWarning - отклоненное обещание было создано, которое нигде не обрабатывалось , Это некрасиво - необработанные отказы от Promise устарели, и в будущем они приведут к краху вашего процесса , который вы определенно не захотите.

Если вы используете функцию async, то обязательно try/catch все, что у вас внутри await, потому что в противном случае, если что-то будет ожидаться, будет отклонено, вся функция вернет отклоненное обещание, что приведет к возникновению вышеуказанных проблем. Например:

ws.on('message', async function (message) {
  if (message instanceof Buffer) {
    if (currentMode == prot.dataMode) {
      try {
        await appendData(sessionData,message);
      } catch(e) {
        console.log('Error', e);
      }
    }
    else {
      console.log("error : unexpected message received");
    }
  }
  // if the message is for defining the mode of communication
  //This message is a configuration message
  else {
    message = JSON.parse(message);
    if (message[prot.modeField] == prot.confMode) {
      console.log("conf mode");
      currentMode = prot.confMode;
      try  {
        await configure(sessionData,message);
      } catch(e) {
        console.log('Error', e);
      }
    }
    //The following messages will be data
    else if (message[prot.modeField] == prot.dataMode) {
      console.log("data mode");
      currentMode = prot.dataMode;
    }

    else{
      console.log("unknown message structure : ");
      console.log(message);
    }
  }
});

С учетом всего вышесказанного, хотя приведенный выше код технически удовлетворяет вашим требованиям, это немного странно, потому что вы ждете обещания, но ничего не делаете после его ожидания. await является синтаксическим сахаром для .then, но если у вас нет никакой логики, вам нужно выполнить ее в .then (например, после await или у потребителя функции async здесь) странно иметь await вообще, вы также можете просто .catch Обещания и полностью исключить части async и try, например:

if (currentMode == prot.dataMode) {
  appendData(sessionData,message)
    .catch((e) => {
      console.log('Error', e);
    });

Если вы также хотите убедиться, что appendData будет запускаться только после завершения последнего appendData вызова, используйте очередь Promise, возможно что-то вроде:

const appendDataQueue = [];
function queueAppend(sessionData, message) {
  appendDataQueue.push({ sessionData, message });
  tryRunNext();
}
let active = false;
function tryRunNext() {
  if (active || !appendDataQueue.length) {
    return;
  }
  const { sessionData, message } = appendDataQueue.unshift();
  active = true;
  appendData(sessionData, message)
    .then(() => {
      active = false;
      tryRunNext();
    })
    .catch((err) => {
      // handle errors
      active = false;
      tryRunNext();
    });
}

И затем, в обработчике .on, вызовите queueAppend вместо вызова appendData (и, опять же, нет необходимости в функции async):

if (currentMode == prot.dataMode) {
  queueAppend(sessionData,message);
}
...