У меня возникают проблемы с отменой моих запросов 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. Что мне не хватает?
Адресация одной из двух вышеуказанных точек разрывает цепочку и может решить проблему:
ignore_user_abort
по умолчанию имеет значение FALSE
, но вы можете использовать нестандартную настройку. Измените этот параметр на FALSE
в php.ini
или вызовите ignore_user_abort(false)
в скриптах, которые обрабатывают эти прерываемые запросы. Недостаток: сценарий просто заканчивается. Любая незавершенная работа отбрасывается, возможно, оставляя систему в грязном состоянии.
echo
во время вашего долгого сценария. Недостаток: эти фиктивные данные могут повредить нормальный вывод вашего скрипта. И здесь сценарий может оставить систему в грязном состоянии.
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); });