Цель проста в управлении, быстрые и одновременные вызовы 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:
- Создать
requestId
- Получите обещание для этого
requestId
от Promisifier потока данных - Отправить полезную нагрузку с
requestId
в поток данных веб-сокета - упс, забыл про этот, верните обещание к данным.
На сервере речь идет только о том, чтобы мы ответили прикрепленным requestId
.
return Promise.resolve («Конец»)
Сноска: Promisifier можно улучшить, включив в запрос максимальное значение TTL, используя Promise.race () с обещанием тайм-аута.