《JS高级程序设计》读书笔记11
requestAnimationFrame()
用于动画重绘的API,它可以告诉浏览器,动画开始,浏览器就可以确定重绘的最佳方式。
早期的动画的典型方式是使用setInterval()方法来控制所有的动画。下面是早期动画的基本方式:
(function(){function updateAnimations(){doAnimation1();doAnimation2();//others}setInterval(updateAnimations,100);})();
可是一方面,为了让动画尽可能的流畅,必须设置时间间隔尽可能的短,另一方面由于浏览器重绘次数有一定的限制。综合这两方面,动画的循环间隔应该为17ms。但是由于setInterval和setTimeout的性能问题,总会有一定的延迟。为了解决这个问题,mozRequestAnimationFrame()方法被提出,通过它告诉浏览器那些javascript代码需要执行动画。这样浏览器可以运行一些代码后进行适当的优化。
mozRequestAnimationFrame()方法接收一个参数,即在重绘屏幕前地哦啊用的一个函数。这个函数负责改变下一次重绘时的DOM样式。
function updateProgress(){var div=document.getElementById("status");div.style.width=(parseInt(div.style.width,10)+5)+"%";if(div.style.left!="100%"){mozRequestAnimationFrame(updateProgress);}}mozRequestAnimationFrame(updateProgress);
计算屏幕上重绘下一组变化之前经过多长时间:
function draw(timestamp){var diff=timestamp-startTime;//count intervalstartTime=timestamp;mozRequestAnimationFrame(draw);}var startTime=mozAnimationStartTime;mozRequestAnimationFrame(draw);webkitRequestAnimationFrame与msRequestAnimationFrame
这两个方法与Mozilla的不同,首先不会给回调函数传递时间码,其次Chrome又增加了第二个可选参数,即将要发生改变的DOM元素。
那么兼容FireFox4+,IE10+,Chrome的循环动画可以参考以下的代码:
(function(){function draw(timestamp){var drawStart=(timestamp||Date.now()),diff=drawStart-startTime;startTime=drawStart;requestAnimationFrame(draw);}var requestAnimationFrame=window.requestAniamtionFrame||window.mozRequeatAniamtionFrame||window.webkitRequestAnimationFrame||window.msRequestAniamtionFrame,startTime=window.mozAnimationStartTime||Date.now();requestAniamtionFrame(draw);})();
这个API的标准W3C已经开始起草,Mozilla和Google正参与该标准草案的制定工作。
Page Visibility API
这个API就是让开发人员知道页面是否对用户可见而推出的。它由三部分组成的:
document.hidden:表示页面是否隐藏的布尔值。页面隐藏包括页面在后台标签页中或者浏览器最小化,
document.visibilityState:表示下列4个可能的状态值:
页面在后台标签页中或浏览器最小化
页面在前台标签页中
实际页面已经隐藏,但是用户可以看到页面的预览
页面在屏幕外执行渲染处理。
visibilitychange事件:当文档从可见变为不可见或从不可见变为可见时,触发该事件
现在只有IE10和Chrome支持这个API。IE的前面加前缀ms,Chrome的前面加前缀webkit。检查浏览器是否支持这个API的最佳方式:
现在只有document.hidden属性是通用的,而且这一部分的API已经相对稳定了,因此在实际开发中可以使用。
Geolocation API
地理定位API,javascript代码可以通过它访问到用户的当前位置。当然在用户明确的许可下才可以。这个API在浏览器中的实现是navigator.geolocation对象,这个对象包含三个方法。第一个方法是getCurrentPosition(),调用这个方法就会触发请求用户共享地理定位信息的对话框。这个方法接收三个参数:成功回调函数,可选的失败回调函数和可选的选项对象。其中,成功回调函数会接受一个position对象参数,该对象有两个属性:coords和timestamp。而coords对象中将包含下列与位置相关的信息。
latitude:以十进制度数表示的纬度
longitude:以十进制度数表示的经度数
accuracy:经纬度坐标的精度,以米为单位
浏览器还可能会在coords对象中提供如下的属性。
altitude:以米为单位的海拔高度,没有相关数据为null
altitudeAccuracy:海拔高度的精度,数值越大越不精确
heading:指南针的方向,0度表示正北,值为NaN表示没有检测到数据
speed:速度,单位米每秒,如果没有相关数据,则值为null。
在实际开发中latitude和longitude是大多数wen应用最常用到的属性。例如以下代码将在地图上绘制用户的位置:
getCurrentPosition()方法的第二个参数,即失败的回调函数,在被调用的时候接收一个参数。这个参数包含两个属性message和code。其中message属性中保存着给人看的文本信息,解释为什么出错。而code中保存着一个数值,表示错误的类型:用户拒绝共享(1),位置无效(2),超时(3)。实际开发中,大多数web应用只会将错误信息保存到日志当中。
getCurrentPosition()方法的第三个参数,是一个可选对象,用于设定信息类型。
navigator.geolocation.getCurrentPosition(function(position){drawMapCenteredAt(postion.coords.latitude,position.coords.longitude);},function(error){console.log("Error code: "+error.code);console.log("Error message: "+error.message);},{enableHighAccuracy:true,//表示尽可能的使用最准确的位置信息timeout:5000,//以毫秒数为单位等待位置信息的最长时间maximumAge:25000//表示上一次取得的坐标信息的有效时间,以毫秒数为单位,如果时间到则重新取得新坐标信息。});
如果你希望跟踪用户的位置,那么可以使用watchPosition()。这个方法接受的参数与getCurrentPosition()效果完全相同。调用这个方***返回一个数值标识符,用于跟踪监控***作。基于这个返回值可以取消监控***作。
var watchId=navigator.geolocation.watchPosition(function(position){drawMapCenteredAt(position.coords.latitude,position.coords.longitude);},function(error){console.log("Error code: "+error.code);console.log("Error message: "+error.message);});clearWatch(watchId);
File API
FileReader类型实现的是一种异步文件读取机制。可以把FileReader想象成XMLHttpRequest,区别只是它读取的是文件系统,而不是远程服务器。为了读取文件中的数据,FileReader提供了如下几个方法:
readAsText(file,encoding):以纯文件形式读取文件,将读取到的文件保存到result属性中。第二个参数用于指定编码类型,可选的。
readAsDataURL(file):读取文件并将文件以数据URI的形式保存在result属性中
readAsBinaryString(file):读取文件并将一个字符串保存在result属性中,字符串的每一个字符表示一个字节
readAsArrayBuffer(file):读取文件并将一个包含文件内容的ArrayBuffer保存在result属性中
由于读取文件的过程是异步的,因此FileReader提供了几个事件。最常用的事件有三个:progress,load,error分别表示是否又读取了新的数据,是否已经读完了整个文件,是否发生了错误。progress事件每过50ms触发一次,通过事件的可以获取事件的属性:lengthComputable,loaded和total.result属性读取文件的内容。
下面是使用三个事件的例子:
读取文件的部分内容
这个只读取文件一部分的方法是slice()方法。
使用XHR上传文件
前提背景是在HTML5上的拖拽式文件上传
Web计时
度量页面性能指标的唯一方式就是提高代码的复杂程度和巧妙地使用Javascript的Date对象。
web计时机制的核心是window.performance对象。这个对象爱那个中定义了两个属性:第一个属性
performance.navigator,包含着与页面导航相关的多个属性,如下所示
redirectCount:页面加载前的重定向次数。
type:数值常量,表示刚刚发生的导航类型
第二个属性performance.timing,包含着一系列的时间戳属性,不同的事件产生不同的时间值。
Web Workers
长时间运行的js进程会导致用户界面变得缓慢。使用Web Workers可以让js在后台运行解决这个问题。
使用Worker
实例化Worker对象并传入要执行的js文件名称就可以创建一个新的Web Worker。
var worker=new Worker("hidden.js");
实例化后会下载这个文件,只有接收到消息才会执行文件中的代码,示例:
worker.postMessage("start!");
postMessage()可以接受任何能够被序列化的值,也可以接收对象数据,例如json字符串对象。这就意味着传入的消息或者信息是被复制到Worker中的,而非直接传送过去的。Worker是通过message和error事件与页面通信的。来自Worker的数据保存在event.data中。Worker返回的数据也可以是任何能够被序列化的值:
worker.onmessage=function(event){
var data=event.data;
//对数据处理
}
Worker不能完成给定的任务时会触发error事件。具体来说,Worker内部的javascript在执行过程中只要遇到错误,就会触发error事件,就会触发error事件。发生error事件时,事件对象中包含三个属性:filename、lineno、message,分别表示发生错误的文件名,代码行号和完整的错误信息。
worker.onerror=function(event){
throw new Error("Error:"+event.filename+"("+event.lineno+"):"+event.message);
}
一定要启用这个错误事件。终止Worker的运行,可以使用以下方式:
worker.terminate();
Worker全局作用域
web Worker的js代码与当前页面的代码不在同一个作用域中,它有自己的全局作用域和其他的对象以及方法。web Worker中的代码不能访问DOM,也无法通过任何方式影响页面的外观。
Worker中的全局对象是worker对象本身。在这个特殊的运行环境中self和this引用的都是Worker对象。为了方便数据处理,Worker本身也是一个最小化得运行环境。
最小化的navigator,只读的location对象,setTimeout和setInterval以及清除,XMLHttpRequest构造函数。
为了处理来自页面的数据,同样可以在worker对象上创建一个onmessage事件处理程序。
worker导入其它脚本文件的方法给页面中的方式是不一样的,要使用importScripts(),这个方法接收一个或多个指向Javascript文件的URL,每个加载都是异步的。
importScripts("file1.js","file2.js");
file2.js会优先与file1.js先下载完,执行的时候仍然会按照先后顺序执行。当这些脚本中包含与页面相关的代码时,脚本可能无法运行。请记住:worker中的脚本一般具有特殊的用途,不会像页面中的脚本那么功能宽泛。