diff --git a/src/ng/httpBackend.js b/src/ng/httpBackend.js index 0a0e1f71680e..0bfe2fc32254 100644 --- a/src/ng/httpBackend.js +++ b/src/ng/httpBackend.js @@ -70,6 +70,11 @@ function createHttpBackend($browser, XHR, $browserDefer, callbacks, rawDocument) // always async xhr.onreadystatechange = function() { if (xhr.readyState == 4) { + // onreadystatechange might by called multiple times + // with readyState === 4 on mobile webkit caused by + // xhrs that are resolved while the app is in the background (see #5426). + xhr.onreadystatechange = undefined; + var responseHeaders = null, response = null; diff --git a/test/ng/httpBackendSpec.js b/test/ng/httpBackendSpec.js index 8c843d2add07..5a392538939a 100644 --- a/test/ng/httpBackendSpec.js +++ b/test/ng/httpBackendSpec.js @@ -90,6 +90,18 @@ describe('$httpBackend', function() { expect(callback).toHaveBeenCalledOnce(); }); + // onreadystatechange might by called multiple times + // with readyState === 4 on mobile webkit caused by + // xhrs that are resolved while the app is in the background (see #5426). + it('should remove onreadystatechange when it is called with readyState=4 to ignore multiple calls', function() { + $backend('GET', 'URL', null, callback); + xhr = MockXhr.$$lastInstance; + + xhr.status = 200; + xhr.readyState = 4; + xhr.onreadystatechange(); + expect(xhr.onreadystatechange).toBeUndefined(); + }); it('should set only the requested headers', function() { $backend('POST', 'URL', null, noop, {'X-header1': 'value1', 'X-header2': 'value2'});