Параллельные запросы с фильтром данных ajaxSetup

#javascript #jquery #ajax #async-await #promise

Вопрос:

Я должен подключиться к существующему ajax-запросу (который я не могу изменить, он находится внутри нашей CMS) и добавить некоторые дополнительные данные. Если быть более точным, это медиатека, загружающая данные изображений (json), и я добавляю еще несколько изображений из внешнего источника.

 var promise_waiting = [];  jQuery.ajaxSetup({  beforeSend: function() {   // starting external library request, so they can run in parallel  promise_waiting = new Promise( function(resolve, reject) {  jQuery.get(external_library_url, {}, function(data) {  if(data) {  console.log('external library request done');  resolve(data);  }  });  });   return true;  },  dataFilter: async function (data) {  console.log('original request done');   // waiting for that external library request to resolve  ext_data = await promise_waiting;   console.log('both requests done');  return data.concat(ext_data);  } })  

Оба запроса заканчиваются так, как я хочу, так что все работает нормально. Проблема в том, что dataFilter не может быть асинхронной функцией, нет ошибок или предупреждений, но код, который будет выполнен после запроса (отображение предварительного просмотра изображения), никогда не запускается.

В настоящее время моей единственной альтернативой является использование неасинхронного ajax-запроса dataFilter , что не является оптимальным, поскольку оба запроса по отдельности занимают довольно много времени.

Я ищу альтернативы этой настройке, заранее благодарю вас

Ответ №1:

Без возможности изменить $.ajax() вызовы и с beforeSend amp; dataFilter , не допускающим асинхронности, вам нужно будет выполнять асинхронность beforeSend вручную, и я не думаю, что вы сможете избежать необходимости «перехватывать» jQuery.fn.ajax .

Что-то вроде этого, может быть:-

 function myBeforeSend(data) {  return $.get(external_library_url, {})  .then(ext_data =gt; data.concat(ext_data || [])); }  (function($, beforeSend) { // i.i.f.e.  // make an alias for $.fn.ajax  let $.fn.originalAjax = $.fn.ajax;   // now hijack $.fn.ajax (in a good way)  $.fn.ajax = function(...args) {  // allow for $.ajax's flexible args .... $.ajax(url, [settings]) or $.ajax([settings])  let settings = Object.assign({}, args[1] || {});  if (typeof args[0] === "string") {  settings.url = args[0]; // standardise settings to include url.  }  return beforeSend(settings.data || [])  .then(filteredData =gt; $.originalAjax(Object.assign(settings, { 'data':filteredData })));  }; })(jQuery, myBeforeSend);  

В составе довольно много безопасности args , но, пожалуйста, не забудьте тщательно протестировать.

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

1. Я понимаю, что вы пытаетесь здесь сделать, но мне нужен результат исходного запроса ajax для слияния с моими данными ext_data. Кроме того, угон ajax сломал некоторые другие вещи, к сожалению

2. @devssc, «нужен результат исходного запроса ajax для слияния с моими данными ext_data» … за исключением ошибки с моей стороны, это именно то, как он должен себя вести. beforeSend() делает первоначальный запрос и возвращает обещание, которое доставляет объединенные данные, которые, в свою очередь, передаются второму запросу ajax.

3. Упс, одна крошечная ошибка, args[2] должна быть args[1] (отредактирована).

4. Проблема с другими нарушениями может быть связана с settings.data || [] выражением, которое по умолчанию имеет значение пустой массив. Возможно, было бы лучше по умолчанию использовать пустой простой объект {} , хотя для этого потребуется beforeSend() различать массив и простой объект.