恶心的 ios scroll问题!!Why the Scroll Event Change in iOS 8 is a Big Deal

原文地址:https://developer.telerik.com/featured/scroll-event-change-ios-8-big-deal/


If you’ve read any of the “What’s new in iOS 8 guides”, you may have noticed a change to how scroll events work. Although many may consider this a minor change, any developer that has tried to implement scrolling logic on the mobile web knows that this is actually fairly important. In this article I’ll explain what changed, what it means, and discuss one major caveat for Cordova developers.

A brief history lesson

When iOS Safari was first being developed, Apple’s engineers faced some difficult challenges displaying the existing web on a small screen. For better or worse, many of their internal engineering decisions became enshrined as “features” of the web — such as touch events, meta viewport tags, and so forth. One of these decisions was to pause all JavaScript execution whenever the user scrolled. To show this in action consider the following code that counts scroll events:

varcount=0;window.addEventListener("scroll",function(event){count++;});

In the two gifs below I display the event count in a fixed header and scroll a few times. Notice that in iOS 7 (left) the count does not increment until scrolling has completely stopped, whereas in iOS 8 (right) the count grows continuously.

Why exactly Apple pauses JavaScript execution during scrolls is unclear, but it’s likely for performance reasons, as the scroll event is often abused by web developers. In 2011, after a scroll event handler rendered Twitter unstable for many users, John Resig wrote an article about the scroll event problem, in which he included the following best practice:

It’s a very, very, bad idea to attach handlers to the window scroll event. Depending upon the browser the scroll event can fire a lot and putting code in the scroll callback will slow down any attempts to scroll the page (not a good idea). Any performance degradation in the scroll handler(s) as a result will only compound the performance of scrolling overall. Instead it’s much better to use some form of a timer to check every X milliseconds OR to attach a scroll event and only run your code after a delay (or even after a given number of executions – and then a delay).

So put yourselves in the shoes of an Apple engineer working on the original iPhone. A lot of sites are running performance-intensive code in scroll events and it’s making your browser seem choppy and slow. (And remember we’re talking about running on the original iPhone, not the hardware of today.) What do you do? Apparently you completely pause JavaScript execution during scroll, which is a sane decision given that environment.

Subsequent mobile browsers — notably IE Mobile and the Android browser — followed Apple’s example, possibly for similar reasons, or possibly for compatibility. Regardless, the lack of usable scroll events became a limitation of the entire mobile web for some time.

Why is this important?

As it turns out, there are many completely valid reasons you may want to perform actions during scrolling, for example parallax effects, or performance-friendly infinite scroll lists. And because of Apple’s decision to pause JavaScript during scrolling, these effects became impossible to do on the mobile web, at least without implementing scrolling with JavaScript, which a number of libraries actually do.

For example the popular iScroll library reimplements scrolling using CSS translations to make custom scroll events possible. Kendo UI Mobile includes a custom scroll widget and uses it to drive its list-based widgets. To be fair, these frameworks offer a lot more functionality than simple scroll events, and the custom JavaScript is usually done to get the best possible performance, but, the fact that you have to rebuild scrolling — a basic tenet of a web browser — to get usable scroll events on mobile is…insane.

And keep in mind that we’re not just talking about the scroll event. iOS < 8 pauses all JavaScript execution during scrolling. Therefore, any intervals you create with setInterval() are also paused. For example consider the following code that displays a new number every second:

varcount=0;setInterval(function(){count++;document.body.innerHTML+="<p>"+count+"</p>";},1000);

In the two gifs below I start scrolling after the count hits 3. Notice that in iOS 7 (left) the count stops during scrolling, whereas in iOS 8 (right) the count continues.

So, if you you use intervals in your apps for any reason, they are no longer arbitrarily paused in iOS 8 during scrolls.

Update (September 25th): Per a comment from Rick Byers my wording here is incorrect. iOS does not pause JavaScript execution—it pauses painting. So your app’s JavaScript will continue to run, but any changes to the DOM will not be painted until the scroll action completes.

How the web changed

Usually once a given behavior hits a major web browser we’re stuck with it until the end of time, but thankfully JavaScript execution during scrolling broke out of this mold. The Android team started firing continuous scroll events on the default browser shipped with Ice Cream Sandwich back in 2011. When Chrome started shipping on Android 4.0 it fired continuous scroll events as well. The next browser to change was IE Mobile, which followed suit on Windows Phone 8 back in 2012.

This left iOS as the only holdout, and with iOS 8 they have joined the rest of the mobile world, which finally gives us comprehensive coverage on the mobile web.

Not pausing JavaScript execution actually adds some compatibility for iOS that they didn’t have before. For example, the popular — and fun — scrollorama jQuery plugin started working correctly as of iOS 8. The gif below shows it in action.

One caveat for Cordova developers

Although Apple implemented this change in iOS Safari, as well as its new WKWebView control, it did not change the scroll behavior in its old UIWebView control. And because of a major bug in the replacement WKWebView control, the Cordova team cannot upgrade to WKWebView yet.

This means that at the moment Cordova apps running on iOS 8 continue to pause JavaScript execution, and will continue to until Cordova can upgrade. And this doesn’t just affect Cordova apps. Any iOS app that uses web views — including Facebook, Twitter, and Chrome for iOS — will get the old behavior until they upgrade their apps to WKWebView. So yes, that means you could get different behavior opening the same URL from different iOS apps depending on which API they use internally.

Update (September 25th): Commenter Ben Kennedy found that, for whatever crazy reason, the old scroll behavior also applies to home screen web apps. So to summarize, apps that run in Safari or in a WKWebView get the new scroll behavior, apps that run in a UIWebView or in a home screen web app do not.

Wrapping up

With iOS 8 it’s cool that you can actually execute code while the user scrolls, and that parallax effects are now possible without complex JavaScript hacks, but to me this is cool because the web actually changed. All mobile browsers used to pause JavaScript execution on scroll, but over time, as hardware advanced, they changed to allow JavaScript to run and fire scroll events as expected. This gives me hope that other features of the mobile web can change for the better as well.

Header image courtesy of William Hook

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • rljs by sennchi Timeline of History Part One The Cognitiv...
    sennchi阅读 12,140评论 0 10
  • 写这一篇文章有点小意外,又是在情理之中,说是意外,是因为这是12月值月生雪晴战友发起的一个活动(所谓意外是未曾想到...
    Sencer阅读 4,001评论 0 4
  • 最近看的《明朝那些事》让我爱不释手,差不多接近尾声,感触颇多。 明朝开国大帝朱元璋一个小小的农民凭...
    MIU妙阅读 1,339评论 0 0
  • 凤九准备离开九重天,成玉听后决定办一场小宴,一来为了友情地久天长,二来为了送送凤九…… “哎!小殿下!这里!”成玉...
    愿岁月温柔回首阅读 8,775评论 4 23
  • 注定还是要折腾我一晚上,今夜无眠!
    水里的鱼儿阅读 825评论 0 0