admin管理员组文章数量:1295923
This isn't so much a question, but a discovery as a result of an interesting problem. It's also a sort of "Learn from my fail"
I'm attempting to write unit tests for an HTML5 history duck punch for IE (using window.hash as a substitute for state maintenance). The duckpunch works as expected, and during user testing I get consistent results in IE, Chrome and Firefox.
Where the problem es in is the unit tests. In them I do various binations of history.pushState(), .replaceState, .back() and .forward(). These work fine in Firefox and IE, but Chrome gave me thoroughly inconsistent results. The below answer explains why.
This isn't so much a question, but a discovery as a result of an interesting problem. It's also a sort of "Learn from my fail"
I'm attempting to write unit tests for an HTML5 history duck punch for IE (using window.hash as a substitute for state maintenance). The duckpunch works as expected, and during user testing I get consistent results in IE, Chrome and Firefox.
Where the problem es in is the unit tests. In them I do various binations of history.pushState(), .replaceState, .back() and .forward(). These work fine in Firefox and IE, but Chrome gave me thoroughly inconsistent results. The below answer explains why.
Share Improve this question asked Jul 11, 2012 at 20:34 FordiFordi 2,8861 gold badge28 silver badges20 bronze badges2 Answers
Reset to default 10Consider the following:
var originalPath = window.location.pathname.toString();
history.pushState({ value: 'Foo' }, '', 'state-1');
history.pushState({ value: 'Bar' }, '', 'state-2');
history.pushState({ value: 'Baz' }, '', 'state-3');
history.back();
history.back();
console.log(history.state.value);
//So we can hit refresh and see the results again...
setTimeout(function () {
history.replaceState(null, '', originalPath);
}, 250);
One would expect this chunk of code to return 'Foo' - and in both Firefox and my IE duck punch, this is exactly what it does - but in Chrome, it responds with 'Baz'.
After some investigation, I worked out the problem: IE and Firefox update the history synchronously, then go asynchronous if any page loads are required. Chrome appears to go asynchronous immediately.
The evidence:
window.onpopstate = function () {
console.log('ping');
}
history.pushState({ value: 'Foo' }, '', 'state-1');
history.back();
console.log('pong');
In Firefox, this returns 'ping'; 'pong' - indicating that the event is dispatched as part of the history.back() call. In Chrome, this returns 'pong'; 'ping' - indicating that the event is placed in a queue for dispatch.
This wouldn't be so bad if this event dispatch model weren't being used to manage the history and location objects' state - but apparently it is.
window.onpopstate = function () {
console.log('Event...', history.state, window.location.pathname.toString());
}
history.pushState({ value: 'Foo' }, '', 'state-1');
history.back();
console.log('Inline...', history.state, window.location.pathname.toString());
This is an interesting quirk, and one that requires the use of jQuery Deferred chains to work around properly for my unit tests. I'm not particularly happy about that, but what can you do?
To handle asynchronous back events in unit tests, I used HistoryJS and Jasmine. It was a case of updating a counter in the history event to track when chrome processed the event and Jasmine's async support to block the unit test until we see an event change:
Increment the counter:
History.Adapter.bind(window, 'statechange', function() {
// Increment the counter
window.historyEventCounter++;
});
The Jasmine async unit test. The waitsFor will block until the history event occurs:
describe('back navigation', function () {
it('should change url', function () {
var initialHistoryEventCount;
// Cache the initial count
runs(function() {
initialHistoryEventCount = window.historyEventCounter;
History.back();
});
// Block until the event counter changes
waitsFor(function() {
return (initialHistoryEventCount !== app.historyEventCounter);
}, "The page should be navigated back", 1000);
// Now confirm the expected back behaviour. Event failures will time-out.
runs(function() {
expect(window.location.href).toEqual("http:// my back url");
// ... more tests about the page state
});
}
}
本文标签: javascriptbackand pushStatea tale of two historiesStack Overflow
版权声明:本文标题:javascript - .back, and .pushState - a tale of two histories - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1741623654a2388957.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论