###概览:
requestIdleCallback是一个当浏览器处于闲置状态时,调度工作的新的性能相关的API
###正文:
如今,大多数的站点和app都需要执行很多的js脚本。你的js通常需要尽可能快地执行,而且,你又不希望通过获取用户行为的方式来达成目的。如果当用户滚动页面的时候,你的JS开始上报数据,或者当用户点击按钮的时候,你往DOM中添加元素,你的web应用其实就已经变得迟钝,导致很差的用户体验。
现在有个好消息,一个新的API能够帮助你: requestIdleCallback
。跟requestAnimationFrame
一样,requestAnimationFrame
允许我们正确地安排动画,同时最大限度地去提升到60fps。而requestIdleCallback
则会在某一帧结束后的空闲时间或者用户处于不活跃状态时,处理我们的工作。这表明在不获取用户行为条件下,你能执行相关的工作。目前这个新的API在Chrome Canary(M46+)下可用(需要打开chrome://flags/#enable-experimental-web-platform-features 去开启该功能),这样你从今天开始先尝试玩玩。但要记着,这个API是一个实验性的功能,该规范仍在不断变化,所以任何东西都可能随时改变。
##为什么我要使用requestIdleCallback?
靠自己人工的安排不必要的工作是很困难的。比如,要弄清楚一帧剩余的时间,这显然是不可能的,因为当requestAnimationFrame
的回调完成后,还要进行样式的计算,布局,渲染以及浏览器内部的工作等等。上面的话貌似还不能说明什么。为了确保用户不以某种方式进行交互,你需要为各种交互行为添加监听事件(scroll、touch、click),即使你并不需要这些功能,只有这样才能绝对确保用户没有进行交互。另一方面,浏览器能够确切地知道在一帧的结束时有多少的可用时间,如果用户正在交互,通过使用requestIdleCallback
这个API,允许我们尽可能高效地利用任何的空闲时间。
接下来让我们看看它的更多细节,且让我们知道如果使用它。
检查requestIdleCallback
目前requestIdleCallback
这个API仍处于初期,所以在使用它之前,你应该检查它是否可用。
1 2 3 4 5 |
if ('requestIdleCallback' in window) { // Use requestIdleCallback to schedule work. } else { // Do what you’d do today. } |
现在,我们假设已经支持该API
##使用requestIdleCallback
调用requestIdleCallback跟调用requestAnimationFrame十分相似,它需要把回调函数作为第一个参数:
1 |
requestIdleCallback(myNonEssentialWork); |
当 myNonEssentialWork 被调用,会返回一个 deadline
对象,这个对象包含一个方法,该方法会返回一个数字表示你的工作还能执行多长时间:
1 2 3 4 |
function myNonEssentialWork (deadline) { while (deadline.timeRemaining() > 0) doWorkIfNeeded(); } |
调用 timeRemaining
这个方法能获得最后的剩余时间,当 timeRemaining() 返回0,如果你仍有其他任务需要执行,你便可以执行另外的requestIdleCallback:
1 2 3 4 5 6 7 |
function myNonEssentialWork (deadline) { while (deadline.timeRemaining() > 0 & tasks.length > 0) doWorkIfNeeded(); if (tasks.length > 0) requestIdleCallback(myNonEssentialWork); } |
##确保你的方法已被调用
当事件很多的时候,你会怎么做?你可能会担心你的回调函数永远不被执行。很好,尽管requestIdleCallback跟requestAnimationFrame很像,但它们也有不同,在于requestIdleCallback有一个可选的第二个参数:含有timeout属性的对象。如果设置了timeout这个值,回调函数还没被调用的话,则浏览器必须在设置的这个毫秒数时,去强制调用对应的回调函数。
1 2 |
// Wait at most two seconds before processing events. requestIdleCallback(processPendingAnalyticsEvents, { timeout: 2000 }); |
如果你的回调函数是因为设置的这个timeout而触发的,你会注意到:
- timeRemaining()会返回0
- deadline对象的didTimeout属性值是true
如果你发现didTimeout是true,你的代码可能会是这样子的:
1 2 3 4 5 6 7 8 9 10 |
function myNonEssentialWork (deadline) { // Use any remaining time, or, if timed out, just run through the tasks. while ((deadline.timeRemaining() > 0 || deadline.didTimeout) & tasks.length > 0) doWorkIfNeeded(); if (tasks.length > 0) requestIdleCallback(myNonEssentialWork); } |
因为设置timeout对你用户导致的潜在破坏(这个操作会使你的app变得迟钝且低质量),请小心地设置这个参数。所以,在这,就让浏览器自己去决定什么时候触发回调吧。
##使用requestIdleCallback去上报数据
让我们试试用requestIdleCallback去上报数据。在这种情况下,我们可能希望去跟踪一个事件,如“点击导航栏菜单”。然而,因为通常他们是通过动画展现在屏幕上的,我们希望避免立即发送事件到Google Analytics,因此我们将创建一个事件的数组来延迟上报,且在未来的某个时间点会发送出去。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
ý相关的API
###正文: 现在有个好消息,一个新的API能够帮助你:
靠自己人工的安排不必要的工作是很困难的。比如,要弄清楚一帧剩余的时间,这显然是不可能的,因为当 接下来让我们看看它的更多细节,且让我们知道如果使用它。
目前
现在,我们假设已经支持该API
调用requestIdleCallback跟调用requestAnimationFrame十分相似,它需要把回调函数作为第一个参数:
当 myNonEssentialWork 被调用,会返回一个
调用
当事件很多的时候,你会怎么做?你可能会担心你的回调函数永远不被执行。很好,尽管requestIdleCallback跟requestAnimationFrame很像,但它们也有不同,在于requestIdleCallback有一个可选的第二个参数:含有timeout属性的对象。如果设置了timeout这个值,回调函数还没被调用的话,则浏览器必须在设置的这个毫秒数时,去强制调用对应的回调函数。
如果你的回调函数是因为设置的这个timeout而触发的,你会注意到:
如果你发现didTimeout是true,你的代码可能会是这样子的:
因为设置timeout对你用户导致的潜在破坏(这个操作会使你的app变得迟钝且低质量),请小心地设置这个参数。所以,在这,就让浏览器自己去决定什么时候触发回调吧。
让我们试试用requestIdleCallback去上报数据。在这种情况下,我们可能希望去跟踪一个事件,如“点击导航栏菜单”。然而,因为通常他们是通过动画展现在屏幕上的,我们希望避免立即发送事件到Google Analytics,因此我们将创建一个事件的数组来延迟上报,且在未来的某个时间点会发送出去。
|