javascript中的新api
梦想还是要有的,万一见鬼了呢。
requestAnimationFrame
早期动画循环
在js中创建动画最简单的方式是使用setInterval()
,如下所示:
1 | (function(){ |
编写这种动画的关键是知道delta多长合适.一方面delta越短,动画越平滑;另一方面考虑到性能的问题,delta要足够长.多数显示器的刷新频率是60Hz,因此最平滑的delta = 1000 / 60 = 17ms,但是问题来了setInterval()
函数的间隔是不确定的,只是指定了把动画代码添加到浏览器UI线程队列中以等待执行的时间。如果队列前面已经加入了其他任务,那动画代码就要等前面的任务完成后再执行。简言之,以毫秒表示的延迟时间并不代表到时候一定会执行动画代码,而仅代表到时候会把代码添加到任务队列中。如果UI线程繁忙,比如忙于处理用户操作,那么即使把代码加入队列也不会立即执行。
另一方面,计时器的精度是不同的,IE8为15.625ms,现代浏览器的计时精度一般是4ms,更为严重的问题是浏览器会限制后台的非活动标签页,即使做了间隔时间的优化也不可能得到我们想要的结果.
为什么使用requestAnimationFrame渲染动画更好
首先思考这样一个问题:CSS动画相比与javascript动画的优势在哪?CSS变换和动画的优势在于浏览器知道动画什么时候开始,因此会计算出正确的时间间隔,在恰当的事件刷新UI,而对于javascript动画,无知晓什么时候开始.因此requestAnimationFrame()
这个API就告诉浏览器某些js代码会执行动画,这样浏览器就会对其进行优化.该方法就收的参数是重绘前调用的一个函数,用于改变下一次重绘时的DOM样式.我们可以像setTimeout()
一样使用:
1 | function updateProgress(){ |
目前来看,mozRequestAnimationFrame()解决了浏览器不知道JavaScript动画什么时候开始、不知道最佳循环间隔时间的问题,但不知道代码到底什么时候执行的问题呢?同样的方案也可以解决这个问题。我们传递的mozRequestAnimationFrame()函数也会接收一个参数,它是一个时间码(从1970年1月1日起至今的毫秒数),表示下一次重绘的实际发生时间。注意,这一点很重要:mozRequestAnimationFrame()会根据这个时间码设定将来的某个时刻进行重绘,而根据这个时间码,你也能知道那个时刻是什么时间。然后,再优化动画效果就有了依据。要知道距离上一次重绘已经过去了多长时间,可以查询mozAnimationStartTime,其中包含上一次重绘的时间码。用传入回调函数的时间码减去这个时间码,就能计算出在屏幕上重绘下一组变化之前要经过多长时间。使用这个值的典型方式如下:
1 | (function(){ |
Page Visibility API
如果页面不是处于活动状态,有些功能是可以停下来的,例如(轮询Server或者动画效果).可见性API就是针对这个而设计的.该API有3部分组成:
- document.hidden:页面处于隐藏(后台标签页或者浏览器最小化)
- document.visibilityState有以下4个状态:
- 后台标签页中或浏览器最小化
- 在前台标签页中
- 实际的页面已经隐藏,但用户可以看到页面的预览(例如win7任务栏预览)
- 页面在屏幕外执行渲染
visibilitychange事件,当文档从可见变为不可见或从不可见变为可见时,触发该事件,检测页面是否隐藏:
1 | if (document.hidden || document.msHidden || document.webKitHidden){ |
以上代码在不支持该API的浏览器中会提示页面未隐藏。这是Page Visibility API有意设计的结果,目的是为了向后兼容。
1 | function handleVisibilityChange(){ |
Geolocation API
地理定位(geolocation)是最令人兴奋,而且得到了广泛支持的一个新API。以下代码将在地图上绘制用户的位置:
1 | navigator.geolocation.getCurrentPosition(function(position){ |
如果你希望跟踪用户的位置,那么可以使用另一个方法watchPosition()。这个方法接收的参数与getCurrentPosition()方法完全相同。实际上,watchPosition()与定时调用getCurrentPosition()的效果相同。在第一次调用watchPosition()方法后,会取得当前位置,执行成功回调或者错误回调。然后,watchPosition()就地等待系统发出位置已改变的信号(它不会自己轮询位置)。
调用watchPosition()
会返回一个数值标识符,用于跟踪监控的操作。基于这个返回值可以取消监控操作,只要将其传递给clearWatch()
方法即可(与使用setTimeout()和clearTimeout()类似)。
1 | var watchId = navigator.geolocation.watchPosition(function(position){ |
只能被调用一次的函数
1 | function only_once(fn) { |
以上函数返回一个只能被调用1次的函数。
1 | function debug(){ console.log('debug') } |
以上代码是闭包的经典应用,出自async.js源码。
原生js模拟用户点击
1 | document.body.addEventListener('click', function listener(e) { |
值传递和引用传递
基本数据类型是值传递,对象是引用传递。
1 | typeof [] // 'object' |