Как заставить мою функцию ждать, прежде чем она возвратит другой вызов - PullRequest
0 голосов
/ 05 июля 2019

У меня есть служба, которая возвращает несколько переводов. Он выполняет вызов apex, который по своей природе является асинхронным, и возвращает переводы. Каждый раз, когда я получаю набор результатов, я сохраняю переводы в хранилище сеансов, и в следующий раз, когда поступает вызов, я сначала проверяю его внутри кэшированных переводов, и, если он доступен, я возвращаюсь. Проблема возникает, когда пользователь отправляет несколько запросов на перевод для одного и того же набора значений. Для этого я отслеживаю уже запущенный вызов Apex. Однако я не уверен, как заставить мой запрос дождаться завершения предыдущего вызова Apex и вернуть результаты.

Вот код услуги.

let labelQueue = [];
let labelMap;
let requestCustomLabels = function(labelsArr, language) {
  return new Promise(function(resolve, reject) {
    let labelsArray = [...labelsArr];
    let returnedLabels = {};
    let cachedLabels = JSON.parse(sessionStorage.getItem("customLabels")) || {};
    labelMap = { ...cachedLabels };
    if (Object.keys(labelMap).length > 0) {
      labelsArray.forEach(item => {
        if (Object.keys(labelMap).indexOf(item) > -1) {
          labelsArray = labelsArray.filter(label => label !== item);
          //push the available lables inside returnedLabels
          returnedLabels[item] = labelMap[item];
        }
      });
    }
    if (Object.keys(returnedLabels).length === labelsArr.length) {
      resolve(returnedLabels);
    }
    if (labelQueue.length && labelsArray.length) {
      labelsArray.forEach(item => {
        if (labelQueue.indexOf(item) > -1) {
          labelsArray = labelsArray.filter(label => label !== item);
        }
      });
    }
    if (labelsArray.length) {
      // store labels to the queue
      labelsArray.forEach(label => {
        labelQueue.push(label);
      });
      // then make call to apex for the result and store it inside returnedLabels & localmap and remove them from labelsQueue
      fetchLabels(labelsArray, returnedLabels, language).then(
        labelsReturned => {
          returnedLabels = { ...returnedLabels, ...labelsReturned };
          resolve(returnedLabels);
        }
      );
    } else {
      // wait for apex to return the call;
    }
  });
};

let fetchLabels = function(labelsArray, returnedLabels, language) {
  return new Promise(function(resolve, reject) {
    getUserProfile().then(function(userData) {
      language = language || userData.language;
      getCustomLabel(labelsArray, language)
        .then(res => {
          let labels = JSON.parse(res).data;
          for (const key in labels) {
            if (key !== "language" && key !== "totalSize") {
              //when the apex call returns remove the labels from the label Queue.
              labelQueue = labelQueue.filter(label => label !== key);
              returnedLabels[key] = labels[key];
              labelMap[key] = labels[key];
            }
          }
          // store localsMap to the storage
          sessionStorage.setItem("customLabels", JSON.stringify(labelMap));
          resolve(returnedLabels);
        })
        .catch(function(error) {
          console.error("error : ", error);
          reject(error);
        });
    });
  });
};

1 Ответ

0 голосов
/ 05 июля 2019

Я на самом деле написал это, в основном для выборки языковых файлов, которые вызываются из нескольких элементов на странице в приложении теневого домена.

Вам необходимо:

  1. Проверьте, сохранено ли обещание.
  2. Сохранить обещание ajax как переменную.
  3. Сохранить переменную, если она не сохранена.
  4. Получить обещание или вернуть сохраненное обещание.
  5. Удалить обещание.

    var ajaxQueue = {};
    
    /**
    * @description Avoids unnecessary calls to server
    * @param {String} url The api call
    * @param {String} method 'GET', 'POST', 'PUT', 'DELETE'
    * @param {String} data If sending data through POST/PUT
    */
    function queueAJAXCalls(url, method, data) {
      var property = FXAjaxBehavior.getQueueProperty(url, method);
    
      if (firstTimeRequesting(property)) {        // 1
        var ajaxPromise = someGeneralCodeForFetchingAjaxData(url, method, data)  // 2
        .then(function(serverData) {
          removeFromAJAXQueue(property);          // 5
          return serverData;
        }).catch(function(error) {
          removeFromAJAXQueue(property);          // 5
          console.warn(error);
    
          return false;
        });
    
        storeInAJAXQueue(property, ajaxPromise);  // 3
      }
    
      return getAJAXFromQueue(property);          // 4
    }
    
    function getQueueProperty(url, method) {
      return encodeURIComponent(method + url);
    }
    
    function firstTimeRequesting(property) {
      return !ajaxQueue[property];
    }
    
    function removeFromAJAXQueue(property) {
      delete ajaxQueue[property];
    }
    
    function storeInAJAXQueue(property, ajaxPromise) {
      ajaxQueue[property] = ajaxPromise;
    }
    
    function getAJAXFromQueue(property) {
      return ajaxQueue[property];
    }
    

Пример:

queueAJAXCalls('http://somedomain.com/api/fetchstuff', 'GET')
.then(function(serverResponse) {
  // do stuff, like using JSON.parse(serverResponse)
})

Осознайте опасность разбора jsondata в одном месте, а именно в someGeneralCodeForFetchingAjaxData, и возврата массивов и объектов, потому что это означает, что изменение массива / объекта в одном месте изменит его во всех местах.

Вместо реализации этого, я думаю, вы могли бы также использовать Service Worker .

...