同步Ajax - Chrome在可信事件上是否超时?

时间:2014-08-22 11:39:00

标签: javascript ajax google-chrome popup synchronous

情况

我们需要在执行XHR / Ajax请求后 onclick-在浏览器中打开一个新标签

我们通过将Ajax请求设置为同步来保持受信任点击事件的上下文,这样做可以正常工作。

问题

但是,在最新的Chrome版本(36)中,当Ajax通话有一些延迟时,我们会遇到弹出警告...... Chrome的2秒延迟就足以让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
    });
}

3 个答案:

答案 0 :(得分:5)

可能解决此问题的方法是在XHR请求返回之前以及您仍在可信上下文中时打开新选项卡。通过Javascript打开的浏览器选项卡和窗口保持与父窗口的连接,并且可以来回通信。

如果在单击链接时打开新选项卡,则可以在XHR调用运行时在新窗口中显示加载屏幕。这个工作流程不像原始请求那么干净,但是如果有一些想法,这将是一个可行的解决方案。下面的脚本只是一个使用window.setTimeout()模拟异步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\'s your data');

              }, 5000)

            });
          });

        }(jQuery));
    </script>
</body>

答案 1 :(得分:0)

Hello @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);
   });
});

通过这种方式,您不需要调用同步请求来在您的上下文中使用该事件,并且作为异步请求,chrome不会抱怨。 :)

答案 2 :(得分:0)

问题不在于XMLHttpRequest,而在于delay(同步延迟,可能是WebKit / Blink中的错误)

请参阅示例(代码段中的http://jsfiddle.net/23JNw/32/沙箱不允许弹出窗口):

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 sync)过时对用户体验非常不利。

我尝试过模拟点击,但不能正常工作:

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);

  

注意:今天的网络浏览器非常聪明,我们很难欺骗它们。

解决方案

不要使用弹出窗口(我讨厌弹出窗口:)),尝试使用<iframe>模拟“弹出窗口”:http://demos.jquerymobile.com/1.4.0/popup-iframe/

或使用模态(如引导程序)添加um按钮,并发出询问用户点击的消息:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js"></script>
<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css" rel="stylesheet"/>

<div class="modal fade" id="exampleModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
  <div class="modal-dialog">
    <div class="modal-content">
      <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
        <h4 class="modal-title" id="exampleModalLabel">New message</h4>
      </div>
      <div class="modal-body">
         Open pop-up :)
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
        <button id="popupIsNotPopular" type="button" class="btn btn-primary">Ok</button>
      </div>
    </div>
  </div>
</div>

window.setTimeout(function() {
    $('#exampleModal').modal();
}, 2000);


$("#popupIsNotPopular").click(function() {
    window.open("http://www.stackoverflow.com");
});