Skip to content

Commit 90ebf7a

Browse files
committed
Abort pending XHR in popstate handler.
1 parent a200310 commit 90ebf7a

File tree

2 files changed

+59
-5
lines changed

2 files changed

+59
-5
lines changed

jquery.pjax.js

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -331,11 +331,7 @@ function pjax(options) {
331331
}
332332

333333
// Cancel the current request if we're already pjaxing
334-
var xhr = pjax.xhr
335-
if ( xhr && xhr.readyState < 4) {
336-
xhr.onreadystatechange = $.noop
337-
xhr.abort()
338-
}
334+
abortXHR(pjax.xhr)
339335

340336
pjax.options = options
341337
var xhr = pjax.xhr = $.ajax(options)
@@ -402,6 +398,12 @@ if ('state' in window.history) {
402398
// You probably shouldn't use pjax on pages with other pushState
403399
// stuff yet.
404400
function onPjaxPopstate(event) {
401+
402+
// Hitting back or forward should override any pending PJAX request.
403+
if (!initialPop) {
404+
abortXHR(pjax.xhr)
405+
}
406+
405407
var state = event.state
406408

407409
if (state && state.container) {
@@ -504,6 +506,15 @@ function fallbackPjax(options) {
504506
form.submit()
505507
}
506508

509+
// Internal: Abort an XmlHttpRequest if it hasn't been completed,
510+
// also removing its event handlers.
511+
function abortXHR(xhr) {
512+
if ( xhr && xhr.readyState < 4) {
513+
xhr.onreadystatechange = $.noop
514+
xhr.abort()
515+
}
516+
}
517+
507518
// Internal: Generate unique id for state object.
508519
//
509520
// Use a timestamp instead of a counter since ids should still be

test/unit/pjax.js

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -749,6 +749,49 @@ if ($.support.pjax) {
749749
}, 0)
750750
}
751751

752+
asyncTest("clicking back while loading cancels XHR", function() {
753+
var frame = this.frame
754+
755+
frame.$("#main").one('pjax:complete', function() {
756+
757+
frame.$("#main").one('pjax:send', function() {
758+
759+
// Check that our request is aborted (need to check
760+
// how robust this is across browsers)
761+
frame.$("#main").one('pjax:complete', function(e, xhr, textStatus) {
762+
equal(xhr.status, 0)
763+
equal(textStatus, 'abort')
764+
})
765+
766+
// Make sure the URL and content remain the same after the
767+
// XHR would have arrived (delay on timeout.html is 1s)
768+
setTimeout(function() {
769+
var afterBackLocation = frame.location.pathname
770+
var afterBackTitle = frame.document.title
771+
772+
setTimeout(function() {
773+
equal(frame.location.pathname, afterBackLocation)
774+
equal(frame.document.title, afterBackTitle)
775+
start()
776+
}, 1000)
777+
}, 500)
778+
779+
frame.history.back()
780+
781+
})
782+
783+
frame.$.pjax({
784+
url: "timeout.html",
785+
container: "#main"
786+
})
787+
})
788+
789+
frame.$.pjax({
790+
url: "hello.html",
791+
container: "#main"
792+
})
793+
})
794+
752795
asyncTest("popstate going back to page", function() {
753796
var frame = this.frame
754797

0 commit comments

Comments
 (0)