Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ajax request timeout doesn't trigger fail() or always() in Safari #3586

Closed
eriklax opened this issue Mar 22, 2017 · 11 comments · Fixed by GulajavaMinistudio/jquery#17
Closed
Assignees
Milestone

Comments

@eriklax
Copy link
Contributor

eriklax commented Mar 22, 2017

Ajax request timeout (due to server being offline) doesn't trigger fail() or always() in Safari (macOS) in latest jQuery. In jQuery 1.x timeout errors trigged both fail() and always().

"Failed to load resource: The request timed out."

And then this script stops.

function ping()
{
        $.get("?action=ping")
        .fail(function(jqXHR, textStatus, errorThrown) {
                console.log('fail');
        })
        .always(function() {
                console.log('always');
                setTimeout(ping, 1000);
        });
}
ping(); // and reboot the webserver

This shows the console in Safari.

console

@dmethvin
Copy link
Member

The default in all versions of jQuery is no timeout. Where did you set the timeout? I have a feeling that a complete example might show some other cause.

@dmethvin
Copy link
Member

Oh, but this timeout is coming from Safari? It would definitely be useful to see a running example to understand what is happening. Is it only Safari?

@eriklax
Copy link
Contributor Author

eriklax commented Mar 23, 2017

Yes, this timeout is coming from Safari (I guess some sane default xhr request timeout). It works as you would expect in Chrome (as shown in the screenshot) and Firefox.

Trying the same code with jQuery 1.x (in Safari, same browser) the timeout "Failed to load resource" is caught and triggers the callbacks, which makes me think it's jQuery related and jQuery could catch it in 3.x as well.

chrome

@dmethvin
Copy link
Member

We still don't have a complete code example so we can't debug it.

@eriklax
Copy link
Contributor Author

eriklax commented Mar 23, 2017

Here is a test case. For me, it takes about 80 seconds minute until the timeout is triggered in Safari.

Doesn't work:

<script src="https://code.jquery.com/jquery-3.2.1.js"></script>
<script>
function ping()
{
        $.get("http://8.8.8.8") // or any other host causing a timeout
        .fail(function(jqXHR, textStatus, errorThrown) {
                console.log('fail');
        })
        .always(function() {
                console.log('always');
                setTimeout(ping, 1000);
        });
}
$(function() {
 ping();
});
</script>

It works with

<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
...

@eriklax
Copy link
Contributor Author

eriklax commented Mar 23, 2017

This patch seems to solve this issue.

master...eriklax:patch-1

@dmethvin
Copy link
Member

Interesting! It seems our assumption might have been that the underlying XHR never had a timeout, I wonder if this is specific to Safari?

@mgol
Copy link
Member

mgol commented Mar 23, 2017

Interesting... That would mean Safari has extracted timeout handling from xhr.onerror to xhr.ontimeout.

@eriklax Would you like to prepare a PR? I wonder how to test it; we have a native abort test but that can be triggered via xhr.abort() and timeout won't have such an API available...

@eriklax
Copy link
Contributor Author

eriklax commented Mar 23, 2017

@mgol How about settings timeout to 1ms and use the wait url?

xhr.timeout https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/timeout

@dmethvin
Copy link
Member

Seems to me that Safari is violating the XHR spec if they have a default timeout:

The timeout attribute must return its value. Initially its value must be zero. ... When set to a non-zero value will cause fetching to terminate after the given time has passed. When the time has passed, the request has not yet completed, and the synchronous flag is unset, a timeout event will then be dispatched, or a TimeoutError exception will be thrown otherwise (for the send() method).

@mgol
Copy link
Member

mgol commented Mar 23, 2017

@eriklax Good idea. We can't test the native timeout happening after a long wait, that would take too long but if we correctly hook up to the ontimeout handler this gets resolved automatically.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Development

Successfully merging a pull request may close this issue.

4 participants