Синхронный Ajax - у Chrome есть тайм-аут на доверенных событиях?
Ситуация
У нас есть ситуация, когда нам нужно onclick - открыть новую вкладку в браузерах после выполнения запроса XHR/Ajax.
Мы делаем это, устанавливая запрос Ajax синхронно, чтобы сохранить контекст события доверенного клика, и это работает нормально.
Проблема
Однако в последней версии Chrome (36) у нас появляются всплывающие предупреждения, когда вызов Ajax имеет некоторое отставание... Для Chrome достаточно отображать всплывающее предупреждение, а не открывать вкладку как это предполагается. Сам код работает, я могу нажать эту кнопку несколько раз, и он работает все время до тех пор, пока запрос не задержит некоторое отставание. Затем я получаю всплывающее предупреждение...
Вопрос
Есть ли тайм-аут, применяемый к синхронным запросам Ajax, в течение которых он должен быть завершен, чтобы доверенное событие все еще было доступно?
Есть ли способ обойти это? В конце концов, вызов уже синхронный и замораживает все остальное, пока результат не достигнет.
Спасибо.
Обновить JSFiddle
Обновление: я создал JSFiddle, чтобы продемонстрировать проблему: http://jsfiddle.net/23JNw/9/
/**
* This method will give open the popup without a warning.
*/
function performSlowSyncronousRequest() {
$.ajax({
url: '/echo/html',
data: {delay: 2}, //JSfiddle will delay the answer by 2 seconds
success: function(){
window.open('http://www.thirtykingdoms.com'); //this causes the popup warning in Chrome
},
async: false
});
}
Ответы
Ответ 1
Что может помешать, это открыть новую вкладку до того, как запрос XHR вернется и пока вы все еще находитесь в доверенном контексте. Вкладки браузера и окна, открытые через Javascript, поддерживают соединения с родительским окном и могут взаимодействовать туда и обратно.
Если вы открываете новую вкладку при нажатии ссылки, вы можете показать экран загрузки в новом окне во время вызова XHR. Этот рабочий процесс не так чист, как ваш первоначальный запрос, но с некоторыми соображениями это было бы жизнеспособным решением. script ниже - это просто быстрый пример, использующий window.setTimeout() для имитации запроса async XHR.
<html>
<body>
<h4>
Hello
</h4>
<a id="openWindow" href="">Make http call and open window.</a>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<script>
(function ($) {
var newWindow = null,
timeout = null;
$(document).ready(function () {
$('#openWindow').on('click', function (evt) {
evt.preventDefault();
newWindow = window.open('about:blank', 'tempWindow');
$(newWindow.document).find('body').append('<div class="loading">Loading...</div>');
timeout = window.setTimeout(function () {
// simulates async XHR
$(newWindow.document).find('.loading').remove();
$(newWindow.document).find('body').append('Done loading, here\ your data');
}, 5000)
});
});
}(jQuery));
</script>
</body>
Ответ 2
Привет @ChristopherLörken. Можете ли вы привести примерный код или скрипку того, что вы делаете? Возможно, я не понимаю, чего вы хотите.
Я думаю, что это поможет:
Если вам нужно событие в вашем контексте, вы можете сохранить ссылку на событие для последующего использования, например, в обратном вызове.
Пример использования jQuery:
$(myBtn).click(function(ev){
var event = ev; //Save the event object reference
$.ajax({
// ... your options
success: function(res){
//do stuff with the event in the callback
console.log(event);
});
});
Таким образом, вам не нужно вызывать запрос синхронизации для использования события в вашем контексте и, как запрос async, хром не жалуется на это.:)
Ответ 3
Ваша проблема не в XMLHttpRequest
, а при delay
(задержка синхронизации, возможно, ошибка в WebKit/Blink)
См. пример (http://jsfiddle.net/23JNw/32/ в Snippet не разрешает всплывающие окна):
function performSlowSyncronousRequest() {
var endsIn, initial;
delay = 5000;
endsIn = new Date().getTime() + delay;
for (; endsIn >= new Date().getTime();) {}//Delay
window.open('http://www.thirtykingdoms.com');
}
<button onclick="performSlowSyncronousRequest()">Test case</button>
Примечание: что sjax (синхронизация XMLHttpRequest) считается устаревшей некоторыми браузерами, очень плохо для пользователя.
Я попытался имитировать клик, но не работал:
function clickFire(evt){
var el, evtFake, pos;
el = document.createElement("a");
el.href = "javascript:void(0);";
el.innerHTML = "test";
el.onclick = evt;
document.body.appendChild(el);
pos = el.getBoundingClientRect();
evtFake = new MouseEvent("click", {
bubbles: false,
cancelable: false,
view: window,
detail: 0,
screenX: window.screenX,
screenY: window.screenY,
clientX: pos.left + 1,
clientY: pos.top + 1,
ctrlKey: false,
shiftKey: false,
altKey: false,
metaKey: false,
button: 1,
buttons: 0,
relatedTarget: el
});
el.dispatchEvent(evtFake);
window.setTimeout(function() {
document.body.removeChild(el);
}, 1);
}
window.setTimeout(function() {
clickFire(function() {
window.open("http://stackoverflow.com");
});
}, 1000);