Альтернатива отправке большого количества запросов на сторону сервера

#javascript #node.js #angular #typescript #performance

Вопрос:

У меня есть товары для корзины на моем сайте электронной коммерции,который я создал с помощью Angular, NodeJS,MongoDB. Когда мой клиент хочет добавить количество или уменьшить количество продукта, например, с 4 до 2, он отправит 2 запроса на исправление для обновления количества (первый с 4 до 3 и второй с 3 до 2), Я хочу, чтобы он улучшил алгоритм, который будет выполняться в 1 запросе (например, в конце сеанса, когда пользователь покидает веб-сайт и т. Д.). Я пробовал использовать Navigator.sendBeacon, и он иногда работает, а иногда нет (что я не могу использовать, мне нужно что-то, что работает все время..) Я не хочу показывать пользователю какое-либо сообщение до того, как он уйдет, которое, как я знаю, исправит эту проблему, и оно будет работать с navigator.sendBeacon Вот что я сделал с navigator.sendBeacon :

Сторона клиента:

   @HostListener('window:beforeunload', ['$event'])
  onBeforeUnload(): void {
    const data = new FormData();
    data.append('cartProducts', JSON.stringify(this.cartProducts));
    navigator.sendBeacon("http://localhost:3000/api/shopping-online/get-beacon", data)
  }

  public cartProducts: CartItem[] = [];
 

Корзина товаров получает массив объектов из базы данных.

На стороне Сервера:

     router.post("/get-beacon", async (request, response) => {
  try {
    console.log("hi");
  }
  catch (err) {
    console.log("bye");
  }
})
 

Иногда я получаю сообщение «привет» на терминале NodeJS, и иногда оно приходит с задержкой в несколько секунд, а иногда не приходит вообще.

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

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

1. Вы можете установить некоторое время, например, за 2 секунды до отправки любого вычисленного запроса на исправление. Поэтому, если в течение 2 секунд пользователь нажмет 3 раза, просто откажитесь от него и сделайте -3 в конце один патч.

2. Либо отмените, либо попросите человека действительно нажать кнопку, чтобы сохранить изменения.

Ответ №1:

Вы пробовали слушать visibilitychange вместо того, чтобы использовать onBeforeUnload ?

 document.addEventListener('visibilitychange', () => {
  if (document.visibilityState === 'hidden') {
    const data = new FormData();
    data.append('cartProducts', JSON.stringify(this.cartProducts));
    navigator.sendBeacon("http://localhost:3000/api/shopping-online/get-beacon", data);
  }
});
 

Документы MDN

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

1. Отличный совет, я использовал изменение видимости на хост-слушателе, и это сработало лучше. добавлено несколько исправлений, и это работает как заклинание ! Я добавил свой ответ со всеми подробностями.

2. @Даниэль рад помочь. Если этот или любой другой ответ решил вашу проблему, пожалуйста, отметьте его как принятый.

Ответ №2:

Благодаря замечательному совету Алана я добрался именно до того, чего хотел, вот решение. Кстати, там нет упоминания о том, как получить именно sendBeacon на NodeJS, поэтому я добавлю все здесь.

Сторона клиента (Угловая):

   @HostListener('document:visibilitychange', ['$event'])
  visibilitychange() {
    if (this.cartProducts amp;amp; this.isCartProductsChanged) {
      const blob = new Blob([JSON.stringify(this.cartProducts)], { type: 'application/json' });
      navigator.sendBeacon("http://localhost:3000/api/shopping-online/get-beacon", blob)
      this.isCartProductsChanged = false;
    }
  }

  public cartProducts: CartItem[] = [];
  public isCartProductsChanged: boolean = false;
 

Он отправит маяк только в том случае, если в корзине есть товары, только если в корзину внесены какие-либо изменения (добавлено количество или товар).

Сторона сервера (NodeJS):

На контроллере:

 router.post("/get-beacon", async (request, response) => {
  try {
    console.log(request.body);
  }
  catch (err) {
    console.log("bye");
  }
})
 

На app.js

 const shoppingController = require("./controllers/shopping-controller");
const express = require("express");
const server = express();
const cors = require("cors");
server.use(function (req, res, next) {
  res.header("Access-Control-Allow-Credentials", "true");
  res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content- 
    Type, Accept");
  next();
});
 server.use(express.text());
 let port = process.env.PORT || 3000;
 server.use("/api/shopping-online", shoppingController);
 server.listen(port, () => console.log(`Listening on 
    http://localhost:${port}`));
 

Использование вместо синтаксического анализатора тела с экспресс-версии 4.16.0 для его работы является

 server.use(express.text());
 

До экспресс-версии 4.16.0 вам необходимо установить анализатор тела

  npm i body-parser
 

И добавьте в app.js:

 const bodyParser = require("body-parser");
server.use(bodyParser.text());