Отменить ожидающие запросы AJAX в приложении PHP?

У меня возникают проблемы с отменой моих запросов XHR при навигации между страницами. У меня есть страница, на которой есть 8 запросов, которые увольняются. Я отменяю их при нажатии ссылки за пределами текущей страницы. Страница закрывается, так как она ждет следующего документа для загрузки. Запросы XHR отображаются как отмененные в инструментах разработчика, но новый документ заходит, как будто он ждет их возвращения.

Здесь вы можете увидеть, что страница застопорена, хотя все остальные запросы отменены. Новая страница – единственный ожидающий запрос …

введите описание изображения здесь

И здесь вы можете увидеть, как только страница, наконец, сделала прыжок, TTFB – 52.52. Если я жду, когда вызовы вернутся, прежде чем щелкнуть, переход будет мгновенным.

введите описание изображения здесь

Вот заголовки для новых страниц, когда они наконец загрузятся, если это поможет … введите описание изображения здесь

Я использую следующий код frankenstein для управления запросами XHR. У меня есть функция cancelAll в нижней части, которая прерывает запросы …

XHRManager = { Requests: [], pendingRequests: [], addNextRequest: function (r) { var timeout = 0; if (trace.isDevelopment()) { timeout = 350; } setTimeout(function () { if (r.url == XHRManager.pendingRequests[0].url && r.start == XHRManager.pendingRequests[0].start) { XHRManager.pendingRequests.splice(0, 1); } else { $( XHRManager.pendingRequests).each(function (ii, dd) { if (dd.url == r.url && dd.start == r.start) { XHRManager.pendingRequests.splice(ii, 1); } }); } XHRManager.startNextRequest(); if (trace.findLocalStorage()) { XHRManager.showTrace = true; trace.show(); } }, timeout); }, requests: [], intervals: [], requestsInt: 0, firstRun: true, delay: 500, globalTimeout: 5000, showTrace: false, startNextRequest: function () { $( XHRManager.pendingRequests).each(function (i, d) { if (d.start) { } if (i == 0) { if (trace.domWatcher.constructor == Function) { trace.domWatcher(d.requestNumber); } trace.log("Request #" + d.requestNumber + " started"); d.requestType(d); } }); if ( XHRManager.pendingRequests.length == 0) { if (trace.isDevelopment()) { trace.show(); } } }, AddToPendingRequests: function (url, params, cb, type, errCB) { var rI = XHRManager.requestsInt; XHRManager.requestsInt++; var req = {url: url, params: params, cb: cb, requestNumber: rI, requestType: type}; if (errCB) { req.errCB = errCB; } XHRManager.pendingRequests.push(req); // if(trace.findLocalStorage()){ // trace.show(); // } if (rI == 0 || XHRManager.pendingRequests.length == 1) { XHRManager.startNextRequest(); } }, writeVals: function (url, params, data, start, cb, requestNumber) { if ($("meta[content='development']").length > 0) { try { var response = {}; response.requestNumber = requestNumber; if (data.sql != "" && data.sql != undefined) { response.sql = data.sql; } if (data.debug) { if (data.debug.sql != "" && data.debug.sql != undefined) { response.sql = data.debug.sql; } } if (data.data != "" && data.data != undefined) { response.data = data.data; } else { if (data != "" || data != undefined) { response.data = data; } } if (url != "" && url != undefined) { response.url = url; } if (params != "" && params != undefined) { response.params = params; } if (cb) { response.cb = cb.toString(); } else { response.cb = ""; } response.requestStats = {}; response.requestStats.start = start; response.requestStats.end = Date(); response.requestStats.totalTime = ((new Date(response.requestStats.end)).getTime() - (new Date(start)).getTime()) / 1000 + " sec(s)"; XHRManager.Requests.push(response); } catch (e) { trace.log(e); } } }, _create: function (r) { var xm = XHRManager; var start = Date(); var req = $.get(r.url, r.params, r.cb) .done(function (data) { XHRManager.writeVals(r.url, r.params, data, start, r.cb, r.requestNumber); if (trace.isDevelopment() && trace.isOn()) { XHRManager.addNextRequest(r); } }); xm.requests.push(req); }, _createAjax: function (r) { var xm = XHRManager; var start = Date(); if (r.type == "PUT" || r.type == "DELETE") { var req = $.ajax({ type: r.type, xhrFields: { withCredentials: true }, url: r.url, data: r.params, success: function (data) { XHRManager.writeVals(r.url, r.params, r.data, r.start, r.cb, r.requestNumber); r.cb(data); if (trace.isDevelopment() && trace.isOn()) { XHRManager.addNextRequest(r); } }, error: r.errCB }); xm.requests.push(req); } else { var req = $.ajax({ type: r.type, xhrFields: { withCredentials: true }, dataType: 'json', json: 'json', url: r.url, data: r.params, success: function (data) { XHRManager.writeVals(r.url, r.params, data, start, r.cb, r.requestNumber); r.cb(data); if (trace.isDevelopment() && trace.isOn()) { XHRManager.addNextRequest(r); } }, error: r.errCB }); xm.requests.push(req); } }, _createJSON: function (r) { var start = Date(); var xm = XHRManager; var req = $.getJSON(r.url, r.params, r.cb) .done(function (data) { XHRManager.writeVals(r.url, r.params, data, start, r.cb, r.requestNumber); if (trace.isDevelopment() && trace.isOn()) { XHRManager.addNextRequest(r); } }); xm.requests.push(req); }, create: function (url, params, cb) { if (trace.isDevelopment() && trace.isOn()) { XHRManager.AddToPendingRequests(url, params, cb, XHRManager._create); } else { var r = {}; r.url = url; r.params = params; r.cb = cb; XHRManager._create(r); } }, createAjax: function (url, params, type, cb, errCB) { if (trace.isDevelopment() && trace.isOn()) { XHRManager.AddToPendingRequests(url, params, cb, XHRManager._createAjax, errCB); } else { var r = {}; r.url = url; r.params = params; r.cb = cb; r.type = type; r.errCB = errCB; XHRManager._createAjax(r); } }, createJSON: function (url, params, cb) { if (trace.isDevelopment() && trace.isOn()) { XHRManager.AddToPendingRequests(url, params, cb, XHRManager._createJSON); } else { var r = {}; r.url = url; r.params = params; r.cb = cb; XHRManager._createJSON(r); } }, remove: function (xhr) { var xm = XHRManager; var index = xm.requests.indexOf(xhr); if (index > -1) { xm.requests.splice(index, 1); } index = xm.intervals.indexOf(xhr.interval); if (index > -1) { xm.intervals.splice(index, 1); } }, cancelAll: function () { var xm = XHRManager; $(xm.requests).each(function () { var t = this; t.abort(); }); $(xm.intervals).each(function () { var t = this; clearInterval(t); }); xm.requests = []; xm.intervals = []; } }; 

На сайте используются jQuery, PHP, Zend Framework 2 и SQL, Apache. Что мне не хватает?

Вероятная причинно-следственная цепочка

  1. сервер не понимает, что запросы XHR отменены, поэтому соответствующие процессы PHP продолжают работать
  2. эти процессы PHP используют сеансы и предотвращают одновременный доступ к этому сеансу до тех пор, пока они не прекратятся

Возможные решения

Адресация одной из двух вышеуказанных точек разрывает цепочку и может решить проблему:

  1. (a) ignore_user_abort по умолчанию имеет значение FALSE , но вы можете использовать нестандартную настройку. Измените этот параметр на FALSE в php.ini или вызовите ignore_user_abort(false) в скриптах, которые обрабатывают эти прерываемые запросы.

Недостаток: сценарий просто заканчивается. Любая незавершенная работа отбрасывается, возможно, оставляя систему в грязном состоянии.

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

Недостаток: эти фиктивные данные могут повредить нормальный вывод вашего скрипта. И здесь сценарий может оставить систему в грязном состоянии.

  1. Сеансы PHP хранятся в виде файла на сервере. В session_start() скрипт открывает файл сеанса в режиме записи, фактически приобретая эксклюзивную блокировку. Последующие запросы, которые используют один и тот же сеанс, приостанавливаются до тех пор, пока блокировка не будет отпущена. Это происходит, когда сценарий завершается, если вы не закрываете сеанс явно. Вызовите session_write_close() или session_abort() как можно раньше.

Недостаток: при закрытии сеанс больше не может быть записан (если вы не открываете сеанс , но это несколько неэффективно). Также скрипт продолжает работать, возможно, тратя ресурсы.

Я определенно рекомендую последний вариант.

Вы сохраняете свой запрос Ajax в переменной ?. Если нет, это то, что вам нужно сделать, чтобы полностью отменить запрос

 var xhr = $.ajax({ type: "POST", url: "anyScript.php", data: "data1=0&data2=1", success: function(msg){ //Success Function } }); //here you abort the request xhr.abort() 

Я предполагаю, что вы это сделали, но проверьте все файлы журнала (php и apache).

Также попробуйте следующее:

php.ini

 upload_max_filesize = 256M post_max_size = 256M 

.htaccess

 php_value upload_max_filesize 256M php_value post_max_size 256M 

Еще одна вещь, которая меня беспокоит, – это эта часть.

 $(xm.requests).each(function () { var t = this; t.abort(); }); $(xm.intervals).each(function () { var t = this; clearInterval(t); }); 

Попробуйте передать аргументы для обратного вызова и прервать их. Я видел случаи, когда присвоение this переменной переменной, содержащей цикл $ .each, фактически указывает на другой объект или глобальное окно.

 $(xm.requests).each(function (index, value) { value.abort(); }); $(xm.intervals).each(function (index, value) { clearInterval(value); });