问题
I have built a product catalog app with angular 2 and now I am working on debugging the warts of IE. So, this is what happens: I have a CatalogComponent
that contains a few children components that display the products in categories. I have 50-60 thumbnails in page so there is not a heavy load on page. The app works perfectly fine in other browsers, performance is ok.
In CatalogComponent
I have a function that detects what is the current displayed category. It listens to scroll events.
this.listeners.catalogScroll = this._renderer.listen(catalog, 'scroll',
event => self.selectCategoryByScroll(event)
);
This particular function does not do some heavy lifting. Actually it's enough to add just a simple scroll
event with no code and scroll perfomance in the catalog div goes down the toilet.
catalog.addEventListener('scroll', function () {
//console.log(1);
});
Even funnier is that if I invoke scrollToCategory()
it triggers a easeInQuad
animation that plays smother than manually scrolling the page. I see this as proof that my page is not too heavy to render fast.
Any ideas on how to proceed to eliminate this issue?
Edit
I just observed that this happens only when scrolling by dragging the scrollbar. Scrolling by scroll wheell works like a charm, no performance dip.
回答1:
As noted in the comments, the problem seems to be that IE is firing way too many scroll events.
The general solution to such problems, as described e.g. in this Q&A thread is throttling the events to some reasonable rate, e.g. like this (using requestAnimationFrame):
var scrollEventPending = false;
function handleScrollEvent () {
scrollEventPending = false;
// handle the event here
}
function throttleScrollEvents () {
if (scrollEventPending) return;
scrollEventPending = true;
requestAnimationFrame(handleScrollEvent);
});
window.addEventListener('scroll', throttleScrollEvents);
However, a limitation of this technique is that the throttled event handler still needs to fire in order to check whether a previously triggered event is pending. In your case, it seems like the event rate may be so high that even this trivial check can be enough to cause noticeable performance issues.
One possible solution could be to use the scroll event handler only to detect when the user starts scrolling, and to uninstall it temporarily until we detect by other means (e.g. comparing the page X and Y offsets) that the scrolling has stopped:
var lastX = window.pageXOffset, lastY = window.pageYOffset;
function runWhileScrolling () {
var currX = window.pageXOffset, currY = window.pageYOffset;
if (currX == lastX && currY == lastY) {
window.addEventListener('scroll', startScrolling);
return; // the page has stopped scrolling
}
// handle scrolling here
lastX = currX; lastY = currY;
requestAnimationFrame(runWhileScrolling);
}
function startScrolling () {
window.removeEventListener('scroll', startScrolling);
runWhileScrolling();
}
window.addEventListener('scroll', startScrolling);
Here's a simple live snippet demonstrating this technique, used here to emulate CSS fixed positioning:
var box = document.getElementById('jsfixed');
var lastX = window.pageXOffset, lastY = window.pageYOffset;
function runWhileScrolling () {
var currX = window.pageXOffset, currY = window.pageYOffset;
if (currX == lastX && currY == lastY) {
window.addEventListener('scroll', startScrolling);
return; // the page has stopped scrolling
}
box.style.top = currY + 80 + 'px';
box.style.left = currX + 10 + 'px';
lastX = currX; lastY = currY;
requestAnimationFrame(runWhileScrolling);
}
function startScrolling () {
window.removeEventListener('scroll', startScrolling);
runWhileScrolling();
}
window.addEventListener('scroll', startScrolling);
#cssfixed, #jsfixed {
box-sizing: border-box;
width: 250px; height: 50px;
padding: 15px 5px;
background: white;
}
#cssfixed {
position: fixed;
top: 20px; left: 10px;
border: 2px solid green;
}
#jsfixed {
position: absolute;
top: 80px; left: 10px;
border: 2px solid red;
}
body {
width: 3000px;
height: 3000px;
background: url(https://i.stack.imgur.com/ybp2X.png);
}
<div id="cssfixed">This box is kept fixed by CSS.</div>
<div id="jsfixed">This box is kept fixed by JS.</div>
Ideally, the two boxes shouldn't move at all with respect to each other as the page is scrolled. On Chrome 57, Opera 44 and Firefox 49, this is indeed the case. On IE 11, the red box does move and flicker noticeably while scrolling, but at least the scrolling itself is smooth and the box correctly returns to its original position after scrolling.
Note that using requestAnimationFrame
like above typically causes the scroll handler to be called about 60 times per second while the page is scrolling. If you don't need such frequent updates, you could replace it with e.g. setTimeout(runWhileScrolling, 200)
(for 5 updates per second).
来源:https://stackoverflow.com/questions/39033878/angular-2-rc-5-internet-explorer-10-poor-scroll-performance