发表于2016/10/1721:25:587809人阅读
分类:前端
转载请注明出处:
2014年10月29日,W3C宣布,经过接近8年的艰苦努力,HTML5标准规范终于制定完成。
HTML5将会取代1999年制定的HTML4.01、XHTML1.0标准,以期能在互联网应用迅速发展的时候,使网络标准达到符合当代的网络需求,为桌面和移动平台带来无缝衔接的丰富内容。
作为2010年入坑IT的程序员来说,可以说一步一步见证着HTML5的发展。这些年为了兼容IE6放弃了很多HTML5的新特性。但是今时不同以往,移动设备的流行,天然支持HTML5,以及桌面端IE最终被用户和微软唾弃,更多支持HTML5浏览器的受欢迎,我要重新研究一下HTML5带来的这些新特性。
①语义特性(Semantic)
HTML5赋予网页更好的意义和结构。
②本地存储特性(OFFLINE&STORAGE)
③设备访问特性(DEVICEACCESS)
从Geolocation功能的API文档公开以来,HTML5为网页应用开发者们提供了更多功能上的优化选择,带来了更多体验功能的优势。HTML5提供了前所未有的数据与应用接入开放接口。使外部应用可以直接与浏览器内部的数据直接相连,例如视频影音可直接与microphones及摄像头相联。
④连接特性(CONNECTIVITY)
更有效的连接工作效率,使得基于页面的实时聊天,更快速的网页游戏体验,更优化的在线交流得到了实现。HTML5拥有更有效的服务器推送技术,Server-SentEvent和WebSockets就是其中的两个特性,这两个特性能够帮助我们实现服务器将数据“推送”到客户端的功能。
⑤网页多媒体特性(MULTIMEDIA)
支持网页端的Audio、Video等多媒体功能,与网站自带的APPS,摄像头,影音功能相得益彰。
⑥三维、图形及特效特性(3D,Graphics&Effects)
基于SVG、Canvas、WebGL及CSS3的3D功能,用户会惊叹于在浏览器中,所呈现的惊人视觉效果。
⑦性能与集成特性(Performance&Integration)
没有用户会永远等待你的Loading——HTML5会通过XMLHttpRequest2等技术,解决以前的跨域等问题,帮助您的Web应用和网站在多样化的环境中更快速的工作。
下面分别对这七个新特性进行研究。
HTML5增加了新的内容标签,这些标签带有一定的语义,使搜索引擎爬取你的网站信息更高效。
HTML4中的内容标签级别相同,无法区分各部分内容。而HTML5中的内容标签互相独立,级别不同,搜索引擎以及统计软件等均可快速识别各部分内容。
这些标签在新闻类网站,博客类网站很有用。
最大的问题就是当使用这些新的语义元素时,那些不支持的浏览器如何处理这些元素。
见过的最多的解决方法是这样的。
HTML5提供了网页存储的API,方便Web应用的离线使用。除此之外,新的API相对于cookie也有着高安全性,高效率,更大空间等优点。
先看W3C对离线存储的介绍。
WebAppscanstartfasterandworkevenifthereisnointernetconnection,thankstotheHTML5AppCache,aswellastheLocalStorage,IndexedDB,andtheFileAPIspecifications.
HTML5离线存储包含应用程序缓存,本地存储,索引数据库,文件接口。
下面依次展开介绍。
使用HTML5,通过创建cachemanifest文件,可以轻松地创建web应用的离线版本。
HTML5引入了应用程序缓存,这意味着web应用可进行缓存,并可在没有因特网连接时进行访问。
应用程序缓存为应用带来三个优势:
甭废话,先来感受一下ApplicationCache的魅力。Shutup,showmethedemo!
1.打开这个网页,第一次等待加载完成之后,页面和普通的网页没有区别。
2.点击刷新按钮,或者强制刷新按钮,看一下第二次打开的速度。有没有快到爆。(速度)
3.现在我要求你拔掉网线,断开WiFi,再次点击刷新按钮,或者强制刷新按钮,看一下第三次打开的速度。有没有快到爆。注意,现在并没有联网,和服务器失去连接,依然秒开网页,还能正常操作网页。(离线浏览,减少服务器负载)
看完了效果,看一下AppCache的原理。
当我们第一次正确配置cachemanifest后,浏览器会将清单文件中的资源缓存下来。当我们再次访问该应用时,浏览器会直接返回缓存中的资源,然后检查manifest文件是否有变动,如果有变动就会把相应的变动更新下来,同时改变浏览器里面的appcache。
使用方法
CACHEMANIFESTtheme.csslogo.gifmain.jsNETWORK:login.aspFALLBACK:/html5//404.htmlmanifest文件可分为三个部分:
CACHEMANIFEST-在此标题下列出的文件将在首次下载后进行缓存NETWORK-在此标题下列出的文件需要与服务器的连接,且不会被缓存FALLBACK-在此标题下列出的文件规定当页面无法访问时的回退页面(比如404页面)
CACHEMANIFEST,是必需的NETWORK规定文件“login.asp”永远不会被缓存,且离线时是不可用的FALLBACK规定如果无法建立因特网连接,则用“404.html”替代/html5/目录中的所有文件
一旦应用被缓存,它就会保持缓存直到发生下列情况:
需要注意的是,更新后的资源需要下次打开页面才能生效,本次打开的页面在更新资源之前就已经从缓存中拿到资源并加载完毕了。
由程序来更新,需要依赖manifest文件被修改这一条,因为调用的是浏览器提供的接口,检测window.applicationCache.status的值,如果是UPDATEREADY,说明浏览器比较manifest文件完毕,可以更新缓存了。window.applicationCache.swapCache()。更新完了,不会立即生效,window.location.reload();重新加载一下页面。
缓存有这么多状态。
varappCache=window.applicationCache;switch(appCache.status){caseappCache.UNCACHED://UNCACHED==0return'UNCACHED';break;caseappCache.IDLE://IDLE==1return'IDLE';break;caseappCache.CHECKING://CHECKING==2return'CHECKING';break;caseappCache.DOWNLOADING://DOWNLOADING==3return'DOWNLOADING';break;caseappCache.UPDATEREADY://UPDATEREADY==4return'UPDATEREADY';break;caseappCache.OBSOLETE://OBSOLETE==5return'OBSOLETE';break;default:return'UKNOWNCACHESTATUS';break;};程序更新缓存的方法。
总的来说,AppCache的三个优点非常明显。但是有几个坑,却会导致没人愿意使用这个新特性。
1.使用了AppCache的页面在清单文件更新之后去更新页面资源,但是只在下次打开页面才能生效,这意味着,我们需要使用代码判断是不是最新版本,不是的话,刷新一次页面。这种体验很不好。
2.使用了AppCache的页面也会被缓存,这对于需要动态更新的页面来说,几乎是个噩梦。用户访问到的页面不是最新的,会导致非常多的问题。
本地存储发展历史.
最早的Cookies自然是大家都知道,问题主要就是太小,大概也就4KB的样子,而且IE6只支持每个域名20个cookies,太少了。优势就是大家都支持,而且支持得还蛮好。很早以前那些禁用cookies的用户也都慢慢的不存在了,就好像以前禁用javascript的用户不存在了一样。
userData是IE的东西,垃圾。现在用的最多的是Flash吧,空间是Cookie的25倍,基本够用。再之后Google推出了Gears,虽然没有限制,但不爽的地方就是要装额外的插件(没具体研究过)。到了HTML5把这些都统一了,官方建议是每个网站5MB,非常大了,就存些字符串,足够了。比较诡异的是居然所有支持的浏览器目前都采用的5MB,尽管有一些浏览器可以让用户设置,但对于网页制作者来说,目前的形势就5MB来考虑是比较妥当的。
首先自然是检测浏览器是否支持本地存储。在HTML5中,本地存储是一个window的属性,包括localStorage和sessionStorage,从名字应该可以很清楚的辨认二者的区别,前者是一直存在本地的,后者只是伴随着session,窗口一旦关闭就没了。二者用法完全相同,这里以localStorage为例。
if(window.localStorage){alert('ThisbrowsersupportslocalStorage');}else{alert('ThisbrowserdoesNOTsupportlocalStorage');}存储数据的方法就是直接给window.localStorage添加一个属性,例如:window.localStorage.a或者window.localStorage[“a”]。它的读取、写、删除操作方法很简单,是以键值对的方式存在的,如下:
localStorage.a=3;//设置a为"3"localStorage["a"]="sfsf";//设置a为"sfsf",覆盖上面的值localStorage.setItem("b","isaac");//设置b为"isaac"vara1=localStorage["a"];//获取a的值vara2=localStorage.a;//获取a的值varb=localStorage.getItem("b");//获取b的值localStorage.removeItem("c");//清除c的值这里最推荐使用的自然是getItem()和setItem(),清除键值对使用removeItem()。如果希望一次性清除所有的键值对,可以使用clear()。另外,HTML5还提供了一个key()方法,可以在不知道有哪些键值的时候使用,如下:
varstorage=window.localStorage;functionshowStorage(){for(vari=0;i
varstorage=window.localStorage;if(!storage.getItem("pageLoadCount")){storage.setItem("pageLoadCount",0);}storage.pageLoadCount=parseInt(storage.getItem("pageLoadCount"))+1;//必须格式转换document.getElementById("count").innerHTML=storage.pageLoadCount;showStorage();不断刷新就能看到数字在一点点上涨,如下图所示:
需要注意的是,HTML5本地存储只能存字符串,任何格式存储的时候都会被自动转为字符串,所以读取的时候,需要自己进行类型的转换。这也就是上一段代码中parseInt必须要使用的原因。
从本质上说,IndexedDB允许用户在浏览器中保存大量的数据。任何需要发送大量数据的应用都可以得益于这个特性,可以把数据存储在用户的浏览器端。当前这只是IndexedDB的其中一项功能,IndexedDB也提供了强大的基于索引的搜索api功能以获得用户所需要的数据。
用户可能会问:IndexedDB是和其他以前的存储机制(如cookie,session)有什么不同?
Cookies是最常用的浏览器端保存数据的机制,但其保存数据的大小有限制并且有隐私问题。Cookies并且会在每个请求中来回发送数据,完全没办法发挥客户端数据存储的优势。
一般来说,有两种不同类型的数据库:关系型和文档型(也称为NoSQL或对象)。关系数据库如SQLServer,MySQL,Oracle的数据存储在表中。文档数据库如MongoDB,CouchDB,Redis将数据集作为个体对象存储。IndexedDB是一个文档数据库,它在完全内置于浏览器中的一个沙盒环境中(强制依照(浏览器)同源策略)。
对数据库的每次操作,描述为通过一个请求打开数据库,访问一个objectstore,再继续。
打开数据库的请求生命周期
IndexedDB是否适合我的应用程序
现在最关键的问题:“IndexedDB是否适合我的应用程序“像往常一样,答案是肯定的:“视情况而定。“首先当你试图在客户端保存数据时,你会考虑HTML5本地存储。本地存储得到广泛浏览器的支持,有非常易于使用的API。简单有其优势,但其劣势是无法支持复杂的搜索策略,存储大量的数据,并提供事务支持。
IndexedDB是一个数据库。所以,当你想为客户端做出决定,考虑你如何在服务端选择一个持久化介质的数据库。你可能会问自己一些问题来帮助决定客户端数据库是否适合您的应用程序,包括:
IndexedDB用法
现在,你已经有机会熟悉了一些的整体概念,下一步是开始实现基于IndexedDB的应用程序。第一个步骤需要统一IndexedDB在不同浏览器的实现。您可以很容易地添加各种厂商特性的选项的检查,同时在window对象上把它们设置为官方对象相同的名称。下面的清单展示了window.indexedDB,window.IDBTransaction,window.IDBKeyRange的最终结果是如何都被更新,它们被设置为相应的浏览器的特定实现。
打开数据库
//打开我们的数据库,数据库名称,版本号varrequest=indexedDB.open("MyTestDatabase",3);indexedDB的三个事件
//数据库打开成功执行request.onsuccess=function(event){//Betteruse"this"than"req"togettheresulttoavoidproblemswith//garbagecollection.//db=request.result;db=this.result;console.debug("initDbDONE");};//数据库打开失败执行request.onerror=function(event){console.error("initDb:",evt.target.errorCode);};//在数据库第一次被打开时或者当指定的版本号高于当前被持久化的数据库的版本号时,触发此事件,可以在这个地方创建对象存储空间结构,更新结构,加索引等.request.onupgradeneeded=function(event){console.debug("initDb.onupgradeneeded");varstore=event.currentTarget.result.createObjectStore(DB_STORE_NAME,{keyPath:'id',autoIncrement:true});};添加数据或更新数据
//我们的客户数据看起来像这样。constcustomerData=[{ssn:"444-44-4444",name:"Bill",age:35,email:"bill@company.com"},{ssn:"555-55-5555",name:"Donna",age:32,email:"donna@home.org"}];vartransaction=db.transaction(["customers"],"readwrite");//当所有的数据都被增加到数据库时执行一些操作transaction.oncomplete=function(event){alert("Alldone!");};transaction.onerror=function(event){//不要忘记进行错误处理!};varobjectStore=transaction.objectStore("customers");for(variincustomerData){varrequest=objectStore.add(customerData[i]);request.onsuccess=function(event){//event.target.result==customerData[i].ssn};}删除数据
varrequest=db.transaction(["customers"],"readwrite").objectStore("customers").delete("444-44-4444");request.onsuccess=function(event){//删除数据成功!};获取数据
vartransaction=db.transaction(["customers"]);varobjectStore=transaction.objectStore("customers");varrequest=objectStore.get("444-44-4444");request.onerror=function(event){//错误处理!};request.onsuccess=function(event){//对request.result做些操作!alert("NameforSSN444-44-4444is"+request.result.name);};对于一个“简单”的提取这里的代码有点多了。下面看我们怎么把它再缩短一点,假设你在数据库的级别上来进行的错误处理:
db.transaction("customers").objectStore("customers").get("444-44-4444").onsuccess=function(event){alert("NameforSSN444-44-4444is"+event.target.result.name);};使用游标获取数据
使用get()要求你知道你想要检索哪一个键。如果你想要遍历对象存储空间中的所有值,那么你可以使用游标。看起来会像下面这样:
varcustomers=[];varobjectStore=db.transaction("customers").objectStore("customers");objectStore.openCursor().onsuccess=function(event){varcursor=event.target.result;if(cursor){customers.push(cursor.value);cursor.continue();}else{alert("Gotallcustomers:"+customers);}};这里有一个封装好的完整的例子,简化了这些操作。
除了IndexedDB以外,还有一种已经被W3C放弃的WebSQL。
浏览器支持本地数据库并不是从IndexedDB才开始实现,它是在WebSQL实现之后的一种新方法。类似IndexedDB,WebSQL是一个客户端数据库,但它作为一个关系数据库的实现,使用结构化查询语言(SQL)与数据库通信。WebSQL的历史充满了曲折,但底线是没有主流的浏览器厂商对WebSQL继续支持。
如果WebSQL实际上是一个废弃的技术,为什么还要提它呢有趣的是,WebSQL在浏览器里得到稳固的支持。Chrome,Safari,iOSSafari,andAndroid浏览器都支持。另外,并不是这些浏览器的最新版本才提供支持,许多这些最新最好的浏览器之前的版本也可以支持。有趣的是,如果你为WebSQL添加支持来支持IndexedDB,你突然发现,许多浏览器厂商和版本成为支持浏览器内置数据库的某种化身。
因此,如果您的应用程序真正需要一个客户端数据库,你想要达到的最高级别的采用可能,当IndexedDB不可用时,也许您的应用程序可能看起来需要选择使用WebSQL来支持客户端数据架构。虽然文档数据库和关系数据库管理数据有鲜明的差别,但只要你有正确的抽象,就可以使用本地数据库构建一个应用程序。
在之前我们操作本地文件都是使用flash、silverlight或者第三方的activeX插件等技术,由于使用了这些技术后就很难进行跨平台、或者跨浏览器、跨设备等情况下实现统一的表现,从另外一个角度来说就是让我们的web应用依赖了第三方的插件,而不是很独立,不够通用。在HTML5标准中,默认提供了操作文件的API让这一切直接标准化。有了操作文件的API,让我们的Web应用可以很轻松的通过JS来控制文件的读取、写入、文件夹、文件等一系列的操作。
先看一个demo。之前我们操作一个图片文件,都是先将图片上传到服务器端,然后再使用一个img标签指向到服务器的url地址,然后再进行一个使用第三方插件进行图片处理,而现在这一切都不需要服务器端了,因为FileReader对象提供的几个读取文件的方法变得异常简单,而且全部是客户端js的操作。
现在我们自己来使用这些API。
先写好我们的HTML页面。
$("#btnGetFile").click(function(e){varfileList=document.getElementById("fileDemo").files;for(vari=0;i
");}else{$("#result").append("type:"+fileList[i].type+"--name:"+fileList[i].name+"--size:"+fileList[i].size+"
");}}});readAsDataURL()
开始读取指定的Blob对象或File对象中的内容.当读取操作完成时,readyState属性的值会成为DONE,如果设置了onloadend事件处理程序,则调用之.同时,result属性中将包含一个data:URL格式的字符串以表示所读取文件的内容.
这个方法很有用,比如,可以实现图片的本地预览.
functionshowDataByURL(){varresultFile=document.getElementById("fileDemo").files[0];if(resultFile){varreader=newFileReader();reader.readAsDataURL(resultFile);reader.onload=function(e){varurlData=this.result;document.getElementById("result").innerHTML+="
开始读取指定的Blob对象或File对象中的内容.当读取操作完成时,readyState属性的值会成为DONE,如果设置了onloadend事件处理程序,则调用之.同时,result属性中将包含所读取文件的原始二进制数据.
functionshowDataByBinaryString(){varresultFile=document.getElementById("fileDemo").files[0];if(resultFile){varreader=newFileReader();//异步方式,不会影响主线程reader.readAsBinaryString(resultFile);reader.onload=function(e){varurlData=this.result;document.getElementById("result").innerHTML+=urlData;};}}readAsText()
开始读取指定的Blob对象或File对象中的内容.当读取操作完成时,readyState属性的值会成为DONE,如果设置了onloadend事件处理程序,则调用之.同时,result属性中将包含一个字符串以表示所读取的文件内容.
functionshowDataByText(){varresultFile=document.getElementById("fileDemo").files[0];if(resultFile){varreader=newFileReader();reader.readAsText(resultFile,'gb2312');reader.onload=function(e){varurlData=this.result;document.getElementById("result").innerHTML+=urlData;};}}事件处理程序
onabort当读取操作被中止时调用.onerror当读取操作发生错误时调用.onload当读取操作成功完成时调用.onloadend当读取操作完成时调用,不管是成功还是失败.该处理程序在onload或者onerror之后调用.onloadstart当读取操作将要开始之前调用.onprogress在读取数据过程中周期性调用.
在文件上传时,HTML5还支持拖拽功能。
来一段W3C对这个特性的介绍。
BeginningwiththeGeolocationAPI,WebApplicationscanpresentrich,device-awarefeaturesandexperiences.Incredibledeviceaccessinnovationsarebeingdevelopedandimplemented,fromaudio/videoinputaccesstomicrophonesandcameras,tolocaldatasuchascontacts&events,andeventiltorientation.
大致包含地理位置API,媒体访问API,访问联系人及事件,设备方向。
下面分别进行研究。
HTML5GeolocationAPI用于获得用户的地理位置。鉴于该特性可能侵犯用户的隐私,除非用户同意,否则用户位置信息是不可用的。一般网页在调用此信息时,会弹出权限申请窗口。
如果电脑获取不到位置信息的话,就在手机上试一下吧。
getCurrentPosition()
getCurrentPosition()方法来获得用户的位置。
标准用法如下:
-检测是否支持地理定位-如果支持,则运行getCurrentPosition()方法。如果不支持,则向用户显示一段消息。-如果getCurrentPosition()运行成功,则向参数showPosition中规定的函数返回一个coordinates对象-showPosition()函数获得并显示经度和纬度
上面的例子是一个非常基础的地理定位脚本,不含错误处理。
完整的处理应该是这样的.
错误代码:-Permissiondenied-用户不允许地理定位-Positionunavailable-无法获取当前位置-Timeout-操作超时-Unknownerror-未知错误
先上demo。麦克风和摄像头也涉及到用户隐私,所以浏览器会向用户申请访问权限。
getUserMedia()
以上的效果,都是通过getUserMedia()方法实现的。
这个纯属于W3C的美好设想,还没有正式纳入标准。目前没有搜到靠谱的资料。
但是有两个类似的变通实现。
FirefoxOS(已结束生命)示例代码。
DeviceOrientation常用于检测重力感应方向,DeviceMotion常用于摇一摇功能。
①DeviceOrientation
重力感应也是原生APP中经常见到的一个功能,在WebApp中的应用多见于判断屏幕的旋转方向,以及在此基础上实现的场景应用,如控制页面上物体的左右移动,加减速等。
在WebApp中实现以上的功能,需要实时获取屏幕的旋转方向参数,这些参数可以从浏览器的利用HTML5的DeviceOrientationAPI获得。
当浏览器的Orientation发生变化时,触发DeviceOrientation事件,并返回一个DeviceOrientationEvent对象,其属性列表如下:
注:不同版本的手机操作系统和浏览器,以及不同的应用程序中内置的浏览器对deviceorientation事件的支持不尽相同。尤其在Android平台上,可能会出现有的设备正常工作,有的则毫无反应的情况。
工作原理
根据event对象的三个方向的参数来确定设备的旋转角度。其中,alpha的取值范围是0-360,这个需要根据设备的指南针设定情况而定,一般来说,设备指向正北方向时为0.beta值为设备绕x轴旋转的角度,取值范围为-180-180。gamma取值范围-90-90.
这里面alpha值的意义并不大,主要参考beta和gamma值。当屏幕从水平沿y轴向左倾斜时gamma值变为负值,向右倾斜变为正值。档屏幕从水平沿x轴向前倾斜时beta值变为正值,向后倾斜时变为负值。所以,如果我们设定一个阈值,当beta和gamma的绝对值大于这个阈值时,我们就认为设备发生了旋转。另外根据beta和gamma的值来判断向左倾斜还是向右倾斜,以及倾斜的程度。
实现方式和示例
首先是为浏览器绑定deviceorientation事件和处理程序。
//adddeviceorientationeventlistenerif(window.DeviceOrientationEvent){window.addEventListener('deviceorientation',DeviceOrientationHandler,false);}else{alert("您的浏览器不支持DeviceOrientation");}functionDeviceOrientationHandler(event){varalpha=event.alpha,beta=event.beta,gamma=event.gamma;if(alpha!=null||beta!=null||gamma!=null){dataContainerOrientation.innerHTML="alpha:"+alpha+"
beta:"+beta+"
gamma:"+gamma;//判断屏幕方向varhtml="";if(Math.abs(gamma)
"+gamma_htmlstage.innerHTML=html;}else{dataContainerOrientation.innerHTML="当前浏览器不支持DeviceOrientation";}}这个示例中展示了如何利用beta和gamma值来展示屏幕的旋转方向和侧翻方向。要实现更精确的物体判断,还需要复杂的算法来计算。
扩展应用
使用DeviceOrientationAPI接口可以实现在web中获取手机设备的屏幕旋转方向参数,在示例的基础上进行改进,可以扩展到在屏幕上控制页面元素的移动,实现动画或游戏的目的。例如通过调整屏幕的方向控制页面上的小球走迷宫,控制小车的移动躲避障碍等。
②DeviceMotion
在WebAPP中HTML5也提供了类似的接口,就是DeviceMotionEvent。DeviceMotion封装了运动传感器数据的事件,可以获取手机运动状态下的运动加速度等数据。
DeviceMotionEvent对象属性列表:
event.accelarationIncludingGravity与event.accelaration的区别在于前者加入了重力加速度,即在z轴方向加了9.8,在x,y方向上的值两者相同。
实现摇一摇
先看W3C的定义。
Moreefficientconnectivitymeansmorereal-timechats,fastergames,andbettercommunication.WebSocketsandServer-SentEventsarepushing(punintended)databetweenclientandservermoreefficientlythaneverbefore.
下面对这两种连接方式分别进行研究。
运行原理
浏览器端示例
varwsServer='ws://localhost:8888/Demo';//服务器地址varwebsocket=newWebSocket(wsServer);//创建WebSocket对象websocket.send("hello");//向服务器发送消息alert(websocket.readyState);//查看websocket当前状态websocket.onopen=function(evt){//已经建立连接};websocket.onclose=function(evt){//已经关闭连接};websocket.onmessage=function(evt){//收到服务器消息,使用evt.data提取};websocket.onerror=function(evt){//产生异常};服务器端
握手协议的客户端数据已经由浏览器代劳了,服务器端需要我们自己来实现,目前市场上开源的实现也比较多如:
KaazingWebSocketGateway(一个Java实现的WebSocketServer);mod_pywebsocket(一个Python实现的WebSocketServer);Netty(一个Java实现的网络框架其中包括了对WebSocket的支持);node.js(一个Server端的JavaScript框架提供了对WebSocket的支持);WebSocket4Net(一个.net的服务器端实现);其实在目前的.net4.5框架中已经实现了WebSocket,不用官方实现,我们自己来写个简单的。服务器端需要根据协议来握手、接收和发送。
握手
///
解析接收的客户端信息
///
浏览器通过HTTP向服务器发送请求,服务器端拿出数据库中的最新的信息,立即返回给客户端,客户端等待三秒后再次发出下一个请求。
客户端示例
服务器端示例
服务器负载
-Long-polling占一小部分CPU资源,但是创建空的进程将浪费系统的内存-Server-SentEvents工作的方式有很多,除非Server-SentEvents不必在每一次响应发出后都关闭连接。-WebSockets,服务器只需要一个进程处理所有的请求,没有循环,不必为每个客户端都分配cpu和内存。
客户端负载
-Long-polling取决于实现方式,但终究是一个异步的方式-Server-SentEvents采用浏览器的内置的实现方式,只花费很少的一部分资源。-WebSockets跟Server-SentEvents一样,采用浏览器的内置的实现方式,只花费很少的一部分资源。
-Long-polling接近实时,但是发送新的请求和发送相应会有一定的时延。-Server-SentEvents默认延时3秒,但是可以调整。-WebSockets真正的实时
实现方式复杂度
-Long-polling实现起来非常简单-Server-SentEvents甚至比Long-polling更简单-需要一个WebSockets服务器处理事件,并开放一个端口
看一下W3C的定义。
AudioandvideoarefirstclasscitizensintheHTML5web,livinginharmonywithyourappsandsites.Lights,camera,action!
看的出来HTML5原生支持音视频让W3C很兴奋。也是广大开发者多年的期待。终于可以将Flash踹入茅坑了。
虽然支持音视频很强大,但是确实没有什么好说的,就是两个标签。
HTML5音频处理接口与Audio标签是不一样的。页面上的Audio标签只是HTML5更语义化的一个表现,而HTML5提供给JavaScript编程用的AudioAPI则让我们有能力在代码中直接操作原始的音频流数据,对其进行任意加工再造。
原理
一段音频到达扬声器进行播放之前,半路对其进行拦截,于是我们就得到了音频数据了,这个拦截工作是由window.AudioContext来做的,我们所有对音频的操作都基于这个对象。通过AudioContext可以创建不同各类的AudioNode,即音频节点,不同节点作用不同,有的对音频加上滤镜比如提高音色(比如BiquadFilterNode),改变单调,有的音频进行分割,比如将音源中的声道分割出来得到左右声道的声音(ChannelSplitterNode),有的对音频数据进行频谱分析。
所有的操作都是基于AudioContext这个对象进行的。
得到AudioContext对象。
搜索了一下,并没有找到与AudioAPI这么强大的功能同一级别的VideoAPI。
来看W3C的介绍。
BetweenSVG,Canvas,WebGL,andCSS33Dfeatures,you’resuretoamazeyouruserswithstunningvisualsnativelyrenderedinthebrowser.
大致包含SVG,Canvas,WebGL,和CSS33D,下面分别进行研究。
SVG是用于描述二维矢量图形的一种图形格式。
与其他图像格式相比,使用SVG的优势在于:-SVG可被非常多的工具读取和修改(比如记事本)-SVG与JPEG和GIF图像比起来,尺寸更小,且可压缩性更强。-SVG是可伸缩的-SVG图像可在任何的分辨率下被高质量地打印-SVG可在图像质量不下降的情况下被放大-SVG图像中的文本是可选的,同时也是可搜索的(很适合制作地图)-SVG可以与Java技术一起运行-SVG是开放的标准-SVG文件是纯粹的XML
SVG有三种用法。
①把SVG直接当成图片放在网页上
画一个五角星
属性stroke-dasharray是让你指定画出的线段每段的长度,第二个值是各段之间空隙的长度。属性stroke-dashoffset是让你指定每个小段的起始偏移量。
想对SVG了解更多的,可以参考下面的网址。
HTML5的canvas元素使用JavaScript在网页上绘制图像。画布是一个矩形区域,您可以控制其每一像素。canvas拥有多种绘制路径、矩形、圆形、字符以及添加图像的方法。
创建Canvas元素
canvas元素本身是没有绘图能力的。所有的绘制工作必须在JavaScript内部完成:
Canvas和SVG都允许您在浏览器中创建图形,但是它们在根本上是不同的。
SVG
SVG是一种使用XML描述2D图形的语言。SVG基于XML,这意味着SVGDOM中的每个元素都是可用的。您可以为某个元素附加JavaScript事件处理器。在SVG中,每个被绘制的图形均被视为对象。如果SVG对象的属性发生变化,那么浏览器能够自动重现图形。
Canvas
Canvas与SVG的比较
Canvas-依赖分辨率-不支持事件处理器-弱的文本渲染能力-能够以.png或.jpg格式保存结果图像-最适合图像密集型的游戏,其中的许多对象会被频繁重绘
SVG-不依赖分辨率-支持事件处理器-最适合带有大型渲染区域的应用程序(比如谷歌地图)-复杂度高会减慢渲染速度(任何过度使用DOM的应用都不快)-不适合游戏应用
想对Canvas了解更多的,可以参考下面链接。
先上demo。
WebGL(全写WebGraphicsLibrary)是一种3D绘图标准,这种绘图技术标准允许把JavaScript和OpenGLES2.0结合在一起,通过增加OpenGLES2.0的一个JavaScript绑定,WebGL可以为HTML5Canvas提供硬件3D加速渲染,这样Web开发人员就可以借助系统显卡来在浏览器里更流畅地展示3D场景和模型了,还能创建复杂的导航和数据视觉化。显然,WebGL技术标准免去了开发网页专用渲染插件的麻烦,可被用于创建具有复杂3D结构的网站页面,甚至可以用来设计3D网页游戏等等。
WebGL基本原理
WebGL的出现使得在浏览器上面实时显示3D图像成为现实,WebGL本质上是基于光栅化的API,而不是基于3D的API。
WebGL对象获取
WebGL也是基于Canvas画布做的,下面看一下WebGL获取方法。
无论要实现的图形尺寸有多大,其投影矩阵的坐标的范围始终是从-1到1。下面是一个关于实现WebGL对象的一个简单例子。
//GetAWebGLcontextvarcanvas=document.getElementById("canvas");vargl=canvas.getContext("experimental-webgl");//setupaGLSLprogramvarprogram=createProgramFromScripts(gl,["2d-vertex-shader","2d-fragment-shader"]);gl.useProgram(program);//lookupwherethevertexdataneedstogo.varpositionLocation=gl.getAttribLocation(program,"a_position");//Createabufferandputasingleclipspacerectanglein//it(2triangles)varbuffer=gl.createBuffer();gl.bindBuffer(gl.ARRAY_BUFFER,buffer);gl.bufferData(gl.ARRAY_BUFFER,newFloat32Array([-1.0,-1.0,1.0,-1.0,-1.0,1.0,-1.0,1.0,1.0,-1.0,1.0,1.0]),gl.STATIC_DRAW);gl.enableVertexAttribArray(positionLocation);gl.vertexAttribPointer(positionLocation,2,gl.FLOAT,false,0,0);//drawgl.drawArrays(gl.TRIANGLES,0,6);下面是两个着色器。
再往后面实在是太过专业了,需要掌握图形图像学的知识,通过demo确实能看出来非常强大,但是需要更专业的人才能搞了。
想对WebGL了解更多,参考这里。
CSS3允许元素以3D的形式显示。
下面讲解一下这个demo是怎样显示出来的。
@-webkit-keyframesmydhua{0%{-webkit-transform:rotateX(0deg)rotateY(0deg)rotateZ(0deg);-webkit-transform-origin:centercenter;}100%{-webkit-transform:rotateX(180deg)rotateY(180deg)rotateZ(180deg);-webkit-transform-origin:centercenter;}}@-moz-keyframesmydhua{0%{-moz-transform:rotateX(0deg)rotateY(0deg)rotateZ(0deg);-webkit-transform-origin:centercenter;}100%{-moz-transform:rotateX(180deg)rotateY(180deg)rotateZ(180deg);-webkit-transform-origin:centercenter;}}接下来就是使用动画。
.wrap{-webkit-animation:mydhua5seaseinfinite;-moz-animation:mydhua5seaseinfinite;}这样我们就得到了一个CSS33D旋转的效果。
想要对CSS33D了解更多的,可以参考下面网址。
看看W3C的介绍。
MakeyourWebAppsanddynamicwebcontentfasterwithavarietyoftechniquesandtechnologiessuchasWebWorkersandXMLHttpRequest2.Nousershouldeverwaitonyourwatch.
性能与集成特性主要包括两个东西,WebWorkers和XMLHttpRequest2。
下面依次介绍。
当在HTML页面中执行脚本时,页面的状态是不可响应的,直到脚本已完成。
Ajax向服务器端发送请求,是异步接收响应的。不然页面会卡住。
WebWorkers是运行在浏览器后台的JavaScript,独立于其他脚本,不会影响页面的性能。您可以继续做任何愿意做的事情:点击、选取内容等等,而此时WebWorkers在后台运行。
setInterval和setTimeout是单线程执行的。
虽然在JavaScript中有setInterval和setTimeout函数使javaScript看起来好像使多线程执行,单实际上JavaScript是单线程的,一次只能做一件事情。
看一个例子。
WebWorkers
这样的设计使JavaScript比较简单,但有时候也很令人烦恼,因为单线程的设计意味着JavaScript代码必须很快运行完,常见的问题就是一段复杂的JavaScript脚本会中断页面其它脚本执行,甚至会出现页面失去响应,这也就是为什么Ajax的API要设计成异步的。
WebWorkers用法
在html5规范中引入了webworkers概念,解决客户端JavaScript无法多线程的问题,其定义的worker是指代码的并行线程,不过webworker处于一个自包含的环境中,无法访问主线程的window对象和document对象,和主线程通信只能通过异步消息传递机制。
我们需要把希望单独执行的javascript代码放到一个单独的js文件中,然后在页面中调用Worker构造函数来创建一个线程,参数是该文件路径,参数存放如果是相对地址,那么要以包含调用Worker构造函数语句所在脚本为参照,如果是绝对路径,需要保证同源(协议+主机+端口)。这个文件不需要我们在页面使用script标签显示引用
w=newWorker("/example/html5/demo_workers.js");worker对象只有两个属性,其实是两个回调函数句柄。
onerror:当worker运行出现错误,并且没有在worker中被捕获,会在此捕获onmessage:当worker向主线程发送消息是调用在其prototype内有两个重要方法
postMessage:很熟悉的赶脚,之前我们介绍过window对象的postMessage()方法,woker的postMessage方法和window的比较类似,但参数略有不同,只需要传递消息内容就可以,而且支持所有JavaScript原生数据类型,当然不放心的话同样也可以序列化为字符串传递terminate:终止worker执行,有些worker执行比较慢,主线程可以主动终止其执行
demo_workers.js
vari=0;functiontimedCount(){i=i+1;postMessage(i);setTimeout("timedCount()",500);}timedCount();demo.html
计数:
想对WebWorkers了解更多的,参考下面链接。
XMLHttpRequest是一个浏览器接口,使得Javascript可以进行HTTP(S)通信。也就是Ajax。
上一代Ajax有以下缺点。
XMLHttpRequest2也就是新的Ajax。针对老版本的缺点,做出了大幅改进,有下面的特点。
XMLHttpRequest2示例
前台代码.
PrintWriterout=newPrintWriter(response.getOutputStream());FileItemFactoryfactory=newDiskFileItemFactory();//为该请求创建一个DiskFileItemFactory对象,通过它来解析请求。执行解析后,所有的表单项目都保存在一个List中。ServletFileUploadupload=newServletFileUpload(factory);List
varaf=newAjaxForm({id:"uploadForm",url:'upload',method:'POST',timeout:5000,onTimeout:function(event){alert('Itistimeout.');},onProgress:function(loaded,total){varcomplete=(loaded/total*100|0);varprogress=document.getElementById('uploadProgress');progress.value=complete;progress.innerHTML=complete;},onComplete:function(result){alert(result);}});af.request();可以看出,虽然是XMLHttpRequest2,但是还是XMLHttpRequest对象。使用新的特性,需要先判断是否支持window.FormData。
但是我们不应该悲观,解决方法总比困难多,Chrome和Firefox也一直在推动浏览器性能提升。前端再也不是切个图,调调颜色,改改字体大小,放个Flash的时代了。HTML5会给我们一个更加美好的未来,前端开发者也有一个提升技术含量,迎接各种机遇的机会了。