Цель проста в управлении, быстрые и одновременные вызовы API, когда подписки не нужны и накладные расходы.

Вот код и объяснение:

клиент:

class DataStreamPromisifier {
  constructor() {
    this.pending = {}
  }

  getPromise(id) {
    return new Promise((resolve, reject) => {
      this.pending[id] = data => data.error ? reject(data.error) : resolve(data.responses)
    })
  }

  pushData(id, data) {
    if (typeof this.pending[id] !== "function") {
      console.log("nothing to do for " + id)
      return
    }
    this.pending[id](data)
    delete this.pending[id]
  }
}

const dataStreamPromisifier = new DataStreamPromisifier()
const uuidv4Regex = //unimportant
//primus is our WebSocket connector
primus.on("data", data => {
  if (!uuidv4Regex.test(data.requestId)) return
  dataStreamPromisifier.pushData(data.requestId, data)
});
//the parameter schema of this function can be domain specific
const getRemoteData = async (type, payload) => {
  let requestId = uuidv4()
  let dataPromise = dataStreamPromisifier.getPromise(requestId)
  primus.write({
    requestId: requestId,
    type: type,
    payload: payload
  });
  return await dataPromise
}

сервер:

const primus = Primus.createServer(function connection(spark) {
  spark.on("data", async data => {
    if (data.requestId === undefined) return
    if (data.type === "datarequest") {
      const response = await processPayload(data.payload)
      spark.write({requestId: requestId, responses: response})
    } else {
      spark.write({requestId: requestId, error: {code: 500, message: "an error occurred"}})
    }
  })
}, {port: 18080, transformer: 'engine.io'});

Таким образом, получается асинхронная функция getRemoteData (), которая получает данные с помощью async-await, в то время как все вызовы этой функции проходят через один и тот же веб-сокет.

Это быстрее, потому что он использует веб-сокеты и не требует накладных расходов, связанных с полным HTTP-запросом для каждого вызова.

А когда нет необходимости в настройке подписки, например, когда данные необходимы только по запросу, это позволяет избежать подписок, а код более читабелен (он течет).

Итак, что здесь происходит?

Мы хотим вызвать функцию и вернуть ее, когда получит ответ от сервера.

Сначала нам нужно получить await ответ от сервера. Для этого у нас есть class DataStreamPromisifier(), у которого есть getPromise()метод, который дает resolve() обещания, когда данные, идентифицированные requestId , возвращаются с сервера. Если у вас есть Promise, вы можете await это.

DataStreamPromisifier получает все данные прямо из веб-сокета.

Итак, наша функция так же проста, как 1, 2, 3:

  1. Создать requestId
  2. Получите обещание для этого requestId от Promisifier потока данных
  3. Отправить полезную нагрузку с requestId в поток данных веб-сокета
  4. упс, забыл про этот, верните обещание к данным.

На сервере речь идет только о том, чтобы мы ответили прикрепленным requestId.

return Promise.resolve («Конец»)

Сноска: Promisifier можно улучшить, включив в запрос максимальное значение TTL, используя Promise.race () с обещанием тайм-аута.

Спасибо за прочтение!