Can trusted events in Chrome trigger a timeout with Synchronous Ajax requests?

Situation

We are facing a situation where we need to open a new tab in browsers after an XHR / Ajax request is made by clicking on something.

To achieve this, we set the Ajax request to be synchronous in order to maintain the context of the trusted click event and so far it has been working well.

Issue

However, with the latest version of Chrome (36), we are running into popup warnings when there is a delay in the Ajax call. Just a 2-second lag triggers a popup warning instead of opening the tab as expected. The code functions normally when there's no lag, but once there is a delay, the popup warning shows up.

Query

We are wondering if there is a timeout applied to synchronous Ajax requests that must be completed for the trusted event to still work properly?

Is there any workaround for this issue? Keep in mind that the call is already synchronous and halts everything else until the result is received.

Thank you.

Update JSFiddle

Update: I have prepared a JSFiddle to illustrate the problem: http://jsfiddle.net/23JNw/9/

/**
* This method will open the popup without triggering a warning.
*/
function performSlowSyncronousRequest() {
    $.ajax({
     url: '/echo/html',
     data: {delay: 2}, //JSfiddle will delay the response by 2 seconds
     success: function(){
         window.open('http://www.thirtykingdoms.com'); //this causes the popup warning in Chrome
     },
     async: false
    });
}

Answer №1

One way to potentially address this issue is by opening a new tab before the XHR request returns, while still remaining in a trusted context. Web browser tabs and windows created using Javascript can establish connections with the parent window, enabling communication between them.

If you decide to open a new tab when clicking a link, you could display a loading screen in the newly opened window as the XHR call is being processed. Although not as seamless as your initial idea, this approach could serve as a viable solution with some careful planning. Below is a brief code snippet utilizing window.setTimeout() to mimic an asynchronous XHR request:

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

Answer №2

Hey @ChristopherLörken! Could you possibly provide an example code snippet or a JSFiddle showing what exactly you're working on? It seems like I might be missing the mark here.

Here's a suggestion that could help:
If you require the event object within your context, consider storing a reference to it for future use, such as within a callback function. Below is an illustration utilizing jQuery:

$(myBtn).click(function(ev){
   var event = ev; // Store a reference to the event object
   $.ajax({
     // ... your options
     success: function(res){
       // Perform operations involving the stored event object
       console.log(event);
     }
   });
});

This approach eliminates the need to make synchronous calls in order to utilize the event within your context, and since it's an asynchronous request, Chrome won't raise any objections to this method. :)

Answer №3

It seems that the issue lies not with XMLHttpRequest, but rather with the delay (potentially a sync delay or a bug in WebKit/Blink).

You can check out an example here (please note that the sandbox in Snippet does not allow pop-ups):

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>

Keep in mind that using sjax (XMLHttpRequest sync) is considered obsolete by some browsers and could negatively impact user experience.

I attempted to simulate a click, however, it did not work as expected:

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

Modern web browsers are quite intelligent and difficult to deceive.

Solution

Avoid using pop-ups (who likes pop-ups anyway?), consider simulating a "pop-up" using an <iframe>:

Alternatively, you can add a button using a modal (like bootstrap) and prompt the user to click:

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

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

When executing the app.delete function, the req.body is found to be empty

I've encountered an issue when trying to send JSON data in an $http Delete call, as the req.body returned is coming back as an empty JavaScript object. Below is my $http delete call where "scenario" is a json object: //Deletes the item from the data ...

Why does clicking to add to an existing array only result in the array being cleared instead?

Need help with an AngularJS question relating to scope binding and click events. I want to add one value on the first click and another value on the second click, but it's only returning an empty array and filling the first value again. Why is that ha ...

Master the Art of Transforming an Array into a Variable

Here is an example of an array: const [listArr, setLA]= useState([ { id: Math.floor(Math.random * 100000), data: "This is data 1", }, { id: Math.floor(Math.random * 100000), data: "This is data 2", ...

React-Native: Issue with state not being updated despite using useEffect and fetch

Currently, I am attempting to make a GET fetch request to a specific endpoint. The issue I am facing is that upon running the application, I am encountering the following error message: Possible Unhandled Promise Rejection (id: 39): TypeError: Cannot read ...

Recurring loop in React while making a GET request

I'm facing an issue with my React code. I need to send a GET request to the backend, which will return a boolean value in response. Within the useEffect hook, I want to check this boolean value and if it's TRUE, display something in the console. ...

Unlocking the data within an object across all Components in Vue

Recently, I've started using Vue and encountered a problem. I'm trying to access data stored inside an Object within one of my components. To practice, I decided to create a cart system with hardcoded data for a few games in the app. Below is the ...

How to convert two arrays into JSON strings and store them in variables using JavaScript

After receiving an ajax response in JSON format, my JavaScript code (within the ajax response success function) stringifies two arrays. Now, I need to assign the data from one curly bracket to two variables, and the data from the other curly bracket to ano ...

What is the best way to incorporate a for loop in order to create animations with anime.js?

I am currently working on implementing a for loop to create a page loader using JQuery along with the animation framework anime.js var testimonialElements = $(".loader-animation"); for(var i=0; i < Elements.length; i++){ var element = ...

What is the best way to animate or manipulate individual points on a 3D plane using three.js?

I have applied a texture to a plane. If I only want to move specific points within the plane, how can I achieve this? For instance, I would like to animate the bottom right corner at a certain speed and the top right corner at a different speed. var came ...

Retrieve the information in a div element from an external website by utilizing AJAX

Exploring the world of AJAX is new to me, and I am eager to fetch content from a div on an external site and display it on my own website. Below is the current code snippet I have: <html> <head> <script src="https://ajax.googleapis.com ...

Using this functionality on a ReactJS Functional Component

Hey everyone, I'm fairly new to using React and I'm currently trying to wrap my head around some concepts. After doing some research online, I stumbled upon a situation where I am unsure if I can achieve what I need. I have a functional componen ...

Calculate a new value based on input from a dynamic textbox within a datatable when a key is pressed

This question is a follow-up from the following solved queries (please do not mark it as a duplicate): jquery: accessing textbox value in a datatable How to bind events on dynamically created elements? I have generated a dynamic textbox within a dat ...

Is there a way to prevent a 'keyup' event from being triggered by a 'keydown' event?

I have a tool that resolves zip codes and I am currently utilizing a keyup event handler to trigger a server query once the input length reaches 5 characters. However, I want to prevent unnecessary calls to the script, so I am exploring the possibility o ...

React is currently throwing an error because it is unable to recognize the properties "position"

Hey, I'm encountering some errors here. Does anyone have any idea how to resolve this? The errors are related to properties 'position' and 'sx' not being recognized in React. ........................................................ ...

Tips for retrieving information from an API and displaying it in a table

I'm struggling to retrieve data (an array of objects) from an API using a Token and display them in a table using Material-UI. However, I keep encountering the following error: Uncaught (in promise) SyntaxError: Unexpected token 'A', "Access ...

Steps to eliminate a choice from the MUI Datagrid Column Show/Hide feature

I am attempting to customize which columns are displayed on the <GridToolbarColumnsButton/> component within the MUI Datagrid toolbar (refer to the image below) https://i.stack.imgur.com/joZUg.jpg Potential solution: I have been exploring the AP ...

The JQuery library seems to be unresponsive on my webpage, despite being correctly included

Despite trying multiple ways to include the JQuery library on my page, I keep encountering the "$ is not defined" error. I have ensured that all the links were correct and from various sources, both local and external. What other options should I consider ...

Creating a Nuxt project and integrating the Axios module

I'm running into an issue where I'm not receiving any data from my Axios async calls. I've configured my calls in my Nuxt config as follows: modules: [ '@nuxtjs/axios', ], And in my component, it's set up like this: <tem ...

Error when parsing JSON due to the presence of backslashes within the serialized object

When trying to call a server side function and parse the response in client side using JavaScript and Ajax, I encountered a parse error. It seems that the issue lies with the backslash that the JavaScriptSerializer adds to serialize the object. The respons ...

Assistance needed in loading the gallery "galleria" using the .load function

With an image gallery containing over 100 images, optimizing loading speed is key. I aim to divide the gallery into groups of 30 and implement navigation tabs "Gallery 1 2 3 4 5" so that users can easily navigate through the content. When a user clicks on ...