Очередь AJAX запросов от пользовательских событий в Javascript - PullRequest
1 голос
/ 17 июня 2020

Я создаю страницу Javascript, которая запрашивает данные о пользовательских событиях

Для каждого события необходимо получить много данных, поэтому я получаю небольшой объем данных с помощью одного запроса AJAX так что я могу показывать обновления. Обратный вызов рекурсивно запрашивает дополнительные данные через AJAX, пока данных для получения не останется. В этой «цепочке» все идет хорошо.

Проблемы, однако, возникают, когда пользователь запускает больше событий, когда уже запущена другая цепочка. Обе цепочки используют один и тот же объект данных, поэтому данные теряются. Как правильно поставить эти пользовательские события в очередь, чтобы они не запускались одновременно? Я добавил мьютекс (https://github.com/kirill-konshin/mutex-promise), но он не принимает во внимание запрос AJAX.

Общая структура кода:

function userEvent(){
    exclusiveGetData()
}

var dataCache = [];

var getDataMutex = new MutexPromise('ThisIsAnUniqueEnoughKey');

function exclusiveGetData(){
    return getDataMutex.promise()
        .then(function(){
            getDataMutex.lock();
            getData();
        })
        .then(function(res){
            getDataMutex.unlock();
            return res;
        })
        .catch(function(e){
            getDataMutex.unlock();
            throw e;
        });
}


function getData(){
    $.get("url", function(data){
        dataCache.handleData();
        if(thereIsMoreData)
            getData();
    })
}

Это, конечно, не работает, потому что мы не ждем, пока $ .get () завершит sh, прежде чем снять блокировку. Я почти уверен, что мне нужны обещания, но я возился с ними около 4 часов, и у меня все еще не получилось. Есть совет?

Ответы [ 2 ]

2 голосов
/ 17 июня 2020

Когда событие запускается, добавьте запрос, который должен быть сделан, в список и проверьте, можете ли вы сделать запрос, проверив, истинна ли переменная логического флага, которая изначально имеет значение true. Если вы можете сделать запрос, установите для переменной логического флага значение false и go впереди с запросом, иначе никаких действий не требуется.

После завершения запроса проверьте, есть ли какие-либо ожидающие запросы в списке , если есть, то отправляйте эти запросы один за другим. Если нет ожидающих запросов, установите для переменной логического флага значение true, указывающее, что все ожидающие запросы были выполнены.

Пример:

См. Следующий пример, который извлекает случайные шутки из шуток Чака-Норриса api. При первом нажатии кнопки извлечения первый запрос выполняется через 2 секунды. Если вы нажмете кнопку несколько раз до того, как будет сделан первый запрос, все эти запросы будут добавлены в массив pendingRequests, а после завершения первого запроса будут выполняться следующие запросы, если есть какие-либо ожидающие запросы.

PS setTimeout добавлено только для того, чтобы показать, что при многократном нажатии кнопки запросы добавляются в массив pendingRequests. Вы можете удалить это в своем коде, если последуете этому примеру.

const btn = document.querySelector('button');
const baseURL = 'https://api.chucknorris.io/jokes/random';
const pendingRequests = [];
let canMakeRequest = true;

btn.addEventListener('click', getData);

function getData() {
  pendingRequests.push(baseURL);
  
  if (canMakeRequest) {
    canMakeRequest = false;
    setTimeout(() => {
       makeRequest(pendingRequests.shift());
    }, 2000);
  }
}

function makeRequest(url) {
  fetch(url)
    .then(res => res.json())
    .then(data => {
       displayData([data]);
    
       const nextURL = pendingRequests.shift();
    
       if (nextURL) {
         makeRequest(nextURL);
       }
       else {
         canMakeRequest = true;
       }
    })
    .catch(error => console.log(error));
}

function displayData(data) {
  const div = document.querySelector('div');
  let html = '';
  data.forEach(d => html += `<span>${d.value}</span>`);
  div.innerHTML += html;
}
div {
  display: flex;
  flex-direction: column;
  align-items: center;
}

span {
  background: #f8f8f8;
  box-shadow: 0 0 2px rgba(0, 0, 0, 0.2);
  padding: 15px;
  margin: 5px;
  width: 100%;
  text-align: center;
}
<button>Fetch Data</button>
<div id="container"></div>
1 голос
/ 17 июня 2020

вы можете попробовать использовать простую проверку количества раз, пользователь запускает событие, pendingAjaxCount сохранит триггер пользовательского события, на основе завершения каждого триггера, это поможет уменьшить количество и вызвать следующий ajax звоните

var pendingAjaxCount = 0;
var dataCache = [];

var userEvent = () => {
  pendingAjaxCount++;
  if(pendingAjaxCount === 1) {
    getData();
 }
}

var unlockedData = () => {
    if(pendingAjaxCount !== 0) {
      getData();
    }
};
 
var getData = () => {
    $.get("url", function(data){
        dataCache.handleData();
        if(thereIsMoreData) {
            getData();
        }
        else {
            pendingAjaxCount--;
            unlockedData()
        }
    })
}
...