本章介绍一下HTML5新增的离线存储特性Localstorage,主要包括Localstorage的发展史、兼容性、优缺点以及使用场景。
说到Localstorage,为什么要使用Localstorage呢
因为开发程序当然就要存储数据了,但是Web开发场景比较特殊,数据正常情况下是要通过HTTP协议发送给服务器端,存储在服务器上,但是呢,如果所有数据都存到服务器一方面会浪费服务器资源,另一方面也会降低网页响应速度,所以设计网页时会抽取一些不太重要的或者临时性的数据使用离线存储方式放在浏览器上。
总的来说,Localstorage是一个简单的离线存储技术,通过官方提供的增删改查的API可以方便的操作它,需要考虑的难点是每个浏览器的容量限制,使用时做好容错即可。
在早期的互联网发展中,浏览器制定了不同的标准用于存储离线数据,其中比较出名的有微软IE浏览器的userData(单个页面可存储64kb)、Adobe的flash6中的flash-cookies(允许存储100kb)、flash8中的externalinterface、Google的gears,不幸的是这些技术没有统一的标准,而且只适用于单一的浏览器,不能跨平台,所以没有收录在HTML标准中。HTML5之前,Cookie是唯一在HTML标准中用于离线存储的技术,但是Cookie有一些不太友好的特征限制了它的应用场景:
这两个缺点在Localstorage中得到了有效的解决,下面我们就开始学习Localstorage。
截止目前为止,已经有大部分浏览器已经支持Localstorage,包括IE8。
具体浏览器是否支持Localstorage可以通过简单的JavaScript代码判断。
实例演示
functiontestLocalstorage(){if(typeofwindow.localStorage=="object")returntrue;//判断localstorage对象是否定义elsereturnfalse;//未定义返回false}1234可查看在线运行效果
Localstorage是一个简单的key/value形式的数据库,以键值对的方式存储,所以提供的接口主要是基于k/v的操作。基于提供的接口只能存储简单的一维数组,但是有些业务场景可能会牵涉到多维数据甚至对象的存储,怎么办?
window.localStorage.setItem("test",1)//设置key=test的值为1localStorage.setItem("test",1)//设置key=test的值为1,localstorage可以作为全局对象处理localStorage.test=1//可以通过属性值的方式直接操作localstorage的key代码块123运行下面案例代码,试一试:
getItem
vara=window.localStorage.getItem("test")//获取key=test的值vara=localStorage.test//可以直接通过对象属性的方式操作123可查看在线运行效果
如果获取一个不存在的key返回null,下同。
vara=window.localStorage.key(0)//可以根据key在localstorage的位置的方式操作,类似操作JavaScript的array的方式12可查看在线运行效果
window.localStorage.removeItem("test")//删除key=test的值window.localStorage.test=''//可以通过赋空值的方式等价操作123可查看在线运行效果
window.localStorage.clear()//clear函数清空整个localstorage12可查看在线运行效果
当localstorage发生改变时,可以通过监听storage事件作出相应的业务处理。
if(window.addEventListener){//通过addEventListener方式监听事件,为了兼容IEwindow.addEventListener("storage",function(e){//监听storage事件//业务处理},false);}else{window.attachEvent("onstorage",function(e){//通过attachEvent方式监听事件//业务处理});}可查看在线运行效果
前边提到Localstorage相比较Cookie的优势是容量大和节省HTTP带宽,但是它还是有自身的缺点,下边罗列了它的缺点
那么以上缺点有没有解决方案,肯定是有的,例如HTML的webSql或者indexDB,那肯定有人问了,为什么不直接用最复杂的数据库,跳过Localstorage呢?原因是技术没有最好的,只有最适合的,不同的业务场景应该选择最匹配的而且成本最小的解决方案。例如你在存储简单的业务场景中的临时数据时完全可以使用Localstorage甚至Cookie搞定,假如使用indexDB的话系统的开发成本以及维护成本会翻番,得不偿失。
所以说总结下来Localstorage的适用业务场景是:
之前开发一个场馆管理系统时有一个功能是根据用户输入的关键字搜索场馆,业务方的需求是需要临时保留搜索关键词的历史记录,考虑到是临时保存,而且只保存关键字不需要复杂的数据结构存储且只保存10条最新的数据,项目组商量下来决定使用Localstorage保存,搜索成功之后添加到历史记录。
functionchooseClubItem(e){letmid=e.currentTarget.dataset.idletfindAddressInfo=this.data.markers.find(item=>item.id===mid)consthistoryList=window.localStorage.getItem('historyList')||[]//获取localstorage需要操作的键值if(findAddressInfo){constindex=historyList.findIndex(history=>history.id==findAddressInfo.id)if(index!==-1){historyList.splice(index,1)}if(historyList.length>=10)historyList.pop();//超过最大历史数目,删除最后一个historyList.unshift(findAddressInfo)//加入到历史存储队列中window.localStorage.setItem('historyList',historyList)//设置离线存储}},可查看在线运行效果
清空历史记录
functiondelHistory(){letthat=thisshowModal({//弹出确认对话框title:'',content:'您确定要清空搜索历史吗',showCancel:true,cancelText:'取消',cancelColor:'#000000',confirmText:'确定',confirmColor:'#3CC51F',success:result=>{if(result.confirm){window.localStorage.removeItem("historyList")//情况历史队列}}})},123456789101112131415161718可查看在线运行效果
现实中考虑到浏览器对Localstorage毕竟不是百分之百兼容,而且Localstorage本身提供的API比较简单,所以实际项目中可以考虑使用第三方封装库操作,比如store.js。
store.js优先选择localStorage来进行存储,在IE6和IE7下降级使用userData来达到目的。没有使用flash,不会减慢你的页面加载速度。也没有使用Cookies,不会使你的网络请求变得臃肿。store.js依赖JSON来序列化数据进行存储。
以上介绍了Localstorage和传统离线存储的优缺点对比,Localstorage的使用方法以及项目实战分析。总的来说Localstorage适用于业务简单的轻量级存储中,通过简单的API操作增删改查存储键值对,而且可以通过事件监听的方式获取Localstorage的操作事件,无需发送HTTP请求,真正实现了离线存储
本章介绍HTML中用来绘图的元素画布。它是HTML5中新增的元素,通过使用JavaScript调用画布的函数可以控制画布中的每个像素,用来生成图形、字符或者图像。画布元素本身没有绘图功能,初始化定义的画布没有任何视觉效果,必须通过JavaScript拿到画布的id,然后控制画布的绘制功能。所以想要使用画布,必须对JavaScript有一定的了解。画布牵涉到很多知识点,本章介绍简单的画布创建以及几种简单的基础形状绘制。
画布元素最早是Safari浏览器在1.3版本引入的,为了解决在dashboard组件中支持脚本控制的图形,之后Firefox1.5和Opera9先后支持了画布元素,目前画布已经是HTML5中正式的标签元素了。
代码说明:如果当前你的浏览器不支持Canvas元素,则显示Canvas标签内的文字。JavaScript可以通过Canvas定义的id来寻找Canvas元素,进而操控它绘图。
varcontext=a.getContext(contextID)代码块1通过getContext函数可以获取画布的SDK对象,在HTML中它被称为CanvasRenderingContext2D对象。CanvasRenderingContext2D提供了一系列用于绘图的函数,其中包含以下几大类。
通过函数fillRectangle可以创建一个矩形,使用fillStyle属性为矩形填充颜色。
使用moveTo函数定义线的开始坐标,lineTo函数定义线的结束坐标,stroke函数进行最终的绘制操作。
使用arc可以画出一个圆形。
使用strokeText绘制文字。
使用createLinearGradient方法可以绘制线性的渐变,适用于矩形、圆形、线条、文本等。
绘制渐变对象,必须使用两种或两种以上的颜色。停止颜色,使用addColorStop方法指定颜色停止,参数为0-1
使用shadow系列函数可以绘制阴影,shadowBlur表示阴影效果如何延伸double值。浏览器在阴影运用高斯模糊时,将会用到该值,它与像素无关,只会被用到高斯模糊方程之中,其默认值为0。shadowColor定义颜色值,默认值是rgba(0,0,0,0)。shadowOffsetX定义阴影在X轴方向的偏移量,以像素为单位,默认值为0,shadowOffsetY定义阴影在Y轴方向的偏移量,以像素为单位,默认值是0。
填充纹理原理上是指图案的重复,通过createPattern()函数进行初始化。有两个参数,第一个是Image实例,第二个是形状中如何显示repeat图案。可以使用这个函数加载图像或者整个画布作为形状的填充图案。
上述代码使用HTML的画布功能实现了一个简单的五子棋功能,其中除了用到画布还使用到了一些简单的数据结构和算法,比如判断棋局是否结束等。
本章介绍了HTM5中新增的绘图工具Canvas,Canvas的历史,以及通过几种简单的实操方式介绍了如何实际使用画布。
学习过JavaScript的可能会了解,JavaScript的宿主浏览器只有一个线程运行JavaScript,除了JavaScript的线程,浏览器中单个页面还有一些其他线程,例如:UI线程负责处理渲染DOM元素;GUI线程用于处理与用户交互的逻辑;网络线程用于发送接收HTTP请求;file线程用于读取文件;定时器线程处理定时任务等等。
为什么不能像很多高级语言一样支持多线程呢?假定JavaScript同时有两个线程,一个线程在HTML中创建了一个标签元素,另一个线程删除了这个标签,这时浏览器应该执行什么操作?浏览器中JavaScript的主要用途是操作DOM。这决定了它只能是单线程,否则会带来很复杂的同步问题。为了避免复杂性,大部分主流浏览器的JavaScript运行环境只支持单线程。
既然JavaScript只支持单线程,那么有人可能会好奇为什么浏览器中的JavaScript可以同时发送多个网络请求或者执行多个事件回调函数呢?
这是因为JavaScript是基于事件驱动,当需要进行网络请求时,JavaScript线程会把请求发送给network线程执行,并等待执行结果;当进行文件读取时则调用file线程,然后等待结果。然后JavaScript会一直轮询事件库eventloop,直到有事件完成,这时浏览器会驱动JavaScript去执行事件的回调函数。这就是JavaScript的事件驱动模型。
单线程的最大问题是不能利用多核CPU的优点,HTML5推出的WebWorker标准,允许JavaScript创建多线程,但是子线程受主线程约束,且不得操作DOM。所以,这个新标准不会产生多线程同步的问题。
WebWorker能解决传统的JavaScript单线程出现的执行阻塞问题,因而适合以下几种业务场景:
初始化一个WebWorker,由于不是所有的浏览器都支持WebWorker,所以需要判断一下浏览器是否支持:
if(window.Worker){//判断浏览器是否支持webworkervarworker=newWorker('test.js');//创建一个线程,参数为需要执行的JavaScript文件}可查看在线运行效果
新的线程的上下文环境跟原宿主环境相对独立的,所以变量作用域不同,如果需要互相读取变量的话需要通过消息发送的方式传输变量,例如:
worker.postMessage('test');//数据类型可以是字符串worker.postMessage({method:'echo',args:['Work']});//数据类型可以是对象123可查看在线运行效果
跟上述场景类似,主线程也需要通过监听的方式获取辅线程的消息:
worker.onmessage=function(event){console.log('接收到消息:'+event.data);}1234可查看在线运行效果
子线程内部也可以通过函数加载其他脚本:
importScripts('script1.js','script2.js');12可查看在线运行效果
//主线程中关闭子线程worker.terminate();//子线程关闭自身self.close();12345可查看在线运行效果
从n个不同元素中任取m(m≤n)个元素,按照一定的顺序排列起来,叫做从n个不同元素中取出m个元素的一个排列。当m=n时所有的排列情况叫全排列。
worker.js代码如下:
functiongetGroup(data,index=0,group=[]){//生成全排列varneed_apply=newArray();need_apply.push(data[index]);for(vari=0;i
上述代码实现了一个使用JavaScript的WebWorker实现的全排列的功能。上半部分是主线程的代码,主要实现了创建子线程、发送数据给子线程、接收子线程的消息这几个功能;下半部分是子线程,子线程主要负责运算,并将运算结果发送给主线程。
早期的JavaScript由于考虑操作DOM的一致性问题,以及当时的网页没有过多的交互所以不需要大量的计算,所以只支持单线程。这在多核CPU时代的劣势愈发明显,所以HTML5中推出多线程解决这个问题。回顾本章主要介绍了WebWorker的使用方式以及其适用场景。
本章介绍一个比较专业性的HTML知识点-数学置标语言,它是一种基于XML的标准,用来在互联网上书写数学符号和公式的置标语言,由万维网联盟的数学工作组提出。
MathML包含两个子语言:PresentationMathML和ContentMathML。PresentationMathML主要负责描述数学表达式的布局。ContentMathML主要负责标记表达式的某些含义或数学结构。MathML的这一方面受到OpenMath语言的很大影响,在MathML3中,与OpenMath更为贴近。为什么需要使用MathML呢?我们要想在网页中插入一些数学公式,早期的方式只能通过特殊符号或者图片来实现,现在利用MathML标签可以方便款姐的实现所有数学公式的显示。
介绍语法之前先看一个简单的demo:
是不是看起来有点眼熟,没错,它就是基于XML语法格式。math元素之最顶层的根元素,每个实例都必须包含在math标签内,一个math元素不能包含另一个math元素。
mrow标签用于对表达式进行分组,至少由一个到多个运算符组成,此元素呈水平展示。良好的分组对数学表达式结构展示起到一定的改善效果。
mi标签表示运算表达式中的变量,例如:
mo标签用于表示运算符,例如:
mn标签用于显示表达式中的数字。
123可查看在线运行效果
以上是简单的写法.
这个标签用于呈现由其表示法属性指定的封闭符号内的内容。它接受一个参数作为多个子元素的推断。它包含一个属性notation,可选项有:
这个标签是一种使用fencing运算符(如花括号,括号和括号)而不是使用标签的快捷方法。包含一个属性,可选值有:
通过上述代码可以看得出,使用这个标签可以减少代码量。
这个标签用于绘制分数,它的子元素必须是2个,不然的话会出现报错,例如:(请使用Firefox运行下面代码)
以上示例中的分母是10,分子是y。
这个标签用于绘制长的分区,它的简单语法格式是:(请使用Firefox运行下面代码)
这个标签比较类似于HTML中的表格元素,结合使用mtr,mtd可以绘制出表格,例如:(请使用Firefox运行下面代码)
用于分组,例如:(请使用Firefox运行下面代码)
这个标签用于绘制下标,例如:(请使用Firefox运行下面代码)
这个标签用于在其内容周围添加填充或额外空间,它可用于调整尺寸和定位,例如:(请使用Firefox运行下面代码)
这个标签用于渲染无形中保持相同的大小和其他维度,包括基线位置,例如:(请使用Firefox运行下面代码)
这个元素用于构造平方根,例如:(请使用Firefox运行下面代码)
这个元素用于绘制下标表达式,例如:(请使用Firefox运行下面代码)
这个元素用于将下标和上标附加到表达式,例如:(请使用Firefox运行下面代码)
这个元素用于将上标绘制到表达式,例如:(请使用Firefox运行下面代码)
这个元素用于绘制下标,可用于在表达式中添加重音或者限制,例如:(请使用Firefox运行下面代码)
这个元素用于绘制下方和上方,它支持在表达式上和下同事添加重音或者限制,例如:(请使用Firefox运行下面代码)
由于mathml牵涉到的专业技术门槛较高,对数学知识要求较高,一般情况下如果只是项目中偶尔使用的话可以使用第三方工具降低开发成本。
这个网站可以在线将数学公式转换成mathml代码
通过调用第三方库,可以使用mathml语法在不支持的浏览器上进行兼容模拟,例如mathml.js(下面例子可以使用chorme浏览器试试了,平方根也是可以显示出来的)
本章介绍了小众语法mathml,由其发展历史以及适用场景引申开来,进而简单介绍了它的语法结构,最后说明了其兼容性问题以及兼容性解决方案,由于目前只有极少数浏览器支持,所以在需要使用时需要先进行兼容性判断。
本章介绍用于描述图像和绘制图形的标记语言SVG,SVG使用XML的语法标准,用于绘制和定义矢量图形,它符合w3c的标准。SVG全称scalablevectorgraphics,使用它可以绘制三种类型的图形:矢量图形、图像、文本。SVG是一整套矢量图形绘制协议,放在HTML中也可以是一个标准的HTML元素
SVG在既能满足现有图片的功能的前提下,又是矢量图,在可访问性上面也非常不错,并且有利于SEO和无障碍,在性能和维护性方面也比icon,font要出色许多,简单的理解,它是图形的另一种格式例如它和常见的图片格式png、jpg、gif等是一类。
使用rect表示矩形,例如:
包含6个属性
使用circle表示圆形:
其中包含3个属性
使用ellipse标签表示椭圆:
其中包含4个属性
使用line元素表示直线:
它包含4个属性
使用polyline表示折线:
使用points属性表示折线的一系列的中间点:
使用path表示路径:
使用这个元素可以实现任何其他图形。
和使用图片相比,SVG有很多优点:
总的来说SVG拥有很多优点,但是其复杂的语法决定了它的入门门槛较高。
Canvas是通过JavaScript调用的方式绘制图像,而SVG是使用标签的方式绘制图像,所以两种的渲染方式有很大差别。
直接使用SVG来绘制一个较复杂的图形的话可能入门门槛较高,使用第三方类库可以节省不少代码量,在这里推荐一个比较常用的SVG的类库snap.svg,它的GitHub地址是snap.svg。
上述代码使用snap.svg实现了一个图形旋转。
回顾本章介绍了HTML中的矢量图形绘制语言SVG,已经SVG的适用场景以及和Canvas的对比。
地理定位功能是HTML5新增的标准,早期的HTML和JavaScript没有操控硬件和文件的权限,因为页面交互效果比较简单;但是HTML5之后网页已经逐渐应用于各种复杂场景包括移动设备,所以增加了各种与硬件交互的API接口,地理位置就是其中之一。
在HTML5之前,获取地理位置的解决方法是在已知IP位置的数据库中查找访问者的IP地址,然后根据IP数据库查找到对应的位置。虽然这种方法的准确度远低于使用GPS设备的准确度,但是这些数据库通常能够定位到访客大致的地址范围,这对于许多应用来说是足够有用的,但是数据库需要经常维护更新。
并非所有的浏览器或者硬件设备都支持地理位置功能,所以使用之前需要进行容错判断:
if(navigator.geolocation){//判断地理位置是否支持//业务代码}else{x.innerHTML="该浏览器不支持获取地理位置。";}代码块1234567获取地理位置之前需要用户点击同意按钮,因为该功能牵涉到隐私。
使用getCurrentPosition函数获取用户当前的地理位置,这个函数有3个参数:
例如:
navigator.geolocation.getCurrentPosition(function(position){//TODO成功时的处理vartimestamp=position.timestamp;varcoords=position.coords;},function(error){//TODO失败时的处理console.log(error);},{//参数设置})代码块12345678910成功获取之后的回调函数中通过参数传递的方式可以拿到地理位置的对象,它是一个Geoposition对象,上述示例使用position变量表示,这个对象包含2个属性:
使用watchPosition函数可以定时获取用户地理位置信息,在用户设备的地理位置发生改变的时候自动被调用。这个函数跟getCurrentPosition函数的使用方式基本一致。
navigator.getlocation.watchPosition(function(pos){//业务代码},function(err){},{})代码块1234563.3清除监视使用clearWatch函数删除watchPosition函数注册的监听器:
varwatch=navigator.geolocation.watchPosition(show_map,handle_error,{enableHighAccuracy:true,timeoout:175000,maximumAge:75000})clearWatch(watch);//清除监视代码块124.定位失败由于获取地理位置功能依赖硬件信号,例如GPS信号、WiFi信号等等,所以有时可能会出现获取不到位置的情况,在这里做了一下总结:
有些旧版本的浏览器不支持HTML5,如IE较低版本的浏览器。这时调用定位接口会出现error信息,message字段包含BrowsernotSupporthtml5geolocation信息。
需要用户开启定位权限,error信息的message字段包含Geolocationpermissiondenied。
比如Chrome、IOS10已经陆续禁止,需要升级站点到HTTPS,error信息的message字段包含Geolocationpermissiondenied信息。注意:Chrome不会禁止localhost域名HTTP协议下的定位
由于信号问题有时会出现超时问题,可以适当增加超时属性的设定值以减少这一现象。某个别浏览器本身对定位接口的友好程度较弱,也会超时返回失败,error信息的message字段包含Geolocationtimeout信息。
Chrome、Firefox以及一些套壳浏览器接入的定位服务在国外,有较大的限制,也会造成定位失败,且失败率较高。
之前的教程中已经简单的介绍过了表单,早期的网页中为了实现复杂的交互效果,通常需要使用div+css模拟复杂的表单类型实现类似日期、滑块条、颜色选择等效果。HTML5标准中考虑到这种情况,增加了不少的复杂表单效果。本章主要介绍HTML5新增的几种增强的表单类型。
此类型的表单跟普通text类型的表单类型表现方式一致,只是在输入完成之后如果不符合email类型浏览器会有提示,且不允许提交,定义方式如下:
url类型的表单视觉展现跟text类型的一致,只是在输入完成之后如果不符合URL类型浏览器会有提示,且不允许提交,语法如下:
number类型的表单也跟text表现形式一致,但是浏览器会强制不能输入非数字类型的字符,表单最后侧默认会有上下两个按钮,语法如下:
此类型将显示一个可拖动的滑块条,并可通过设定max/min/step值限定拖动范围。拖动时会反馈给value一个值。
在实际项目中可以根据动态获取滑块的value值,来实现一定的效果。以下展示了一个使用range表单实现了一个动态缩放图片的功能:
此类型表单,可让用户通过颜色选择器选择一个颜色值,并反馈到value中,可以设置默认值,语法如下:
实际项目中,一般用来作为为画笔或者绘图选择颜色,以下示例展示了一个简单的颜色选择器表单:
这个类型的表单包含几种类型,用来实现繁琐的日历控件,效果各有不同,语法如下:
此类型表示输入的将是一个搜索关键字,通过results=s或者x-webkit-speech可显示一个搜索小图标。语法如下:
这个表单在实际项目中适用场景较少,所以没有示例可以参考。
回顾本章介绍了几种实时交互效果较强的表单控件及用法,弥补了早期HTML中的交互缺失的情况。
之前的章节有讨论过web中的存储方式,包括传统的cookie和新的localstorage,这两种方式实现了HTML中的离线存储,但是存储方式比较简单,在有些复杂的业务场景可能不能满足条件。本章我们介绍一个计算机中一个重要的学科数据库,以及它在HTML5中的支持。数据库是一个内容庞大的知识体系,本章只介绍一些简单的用法以及它在HTML中的适用场景。
缺点是:
WebSQL不是HTML5标准中的一部分,它是一个独立的规范,引入了SQL的api,关于SQL的语法可以参考第三方的教程,在此不做解释。WebSQL有3个函数
这个函数用于打开一个数据库,如果数据库不存在就创建。它有5个参数,分别表示:
/***创建数据库或者此数据库已经存在那么就是打开数据库*name:数据库名称*version:版本号*displayName:对数据库的描述*estimatedSize:设置数据的大小*creationCallback:回调函数(可省略)*/vardb=openDatabase("MySql","1.0","数据库描述",1024*1024);代码块1234567892.2transaction这个函数使用事务执行SQL语句,它是一个闭包,例如:
dataBase.transaction(function(tx){tx.executeSql("createtableifnotexiststest(idREALUNIQUE,nameTEXT)",[],function(tx,result){alert('创建test表成功');},function(tx,error){alert('创建test表失败:'+error.message);});});2.3executeSql这个方法用于执行SQL语句。
tx.executeSql("updatestusetname=whereid=",[name,id],function(tx,result){},function(tx,error){alert('更新失败:'+error.message);});});3.indexedDBIndexedDB是HTML5规范里新出现的浏览器里内置的数据库。它提供了类似数据库风格的数据存储和使用方式。存储在IndexedDB里的数据是永久保存,不像cookies那样只是临时的。IndexedDB里提供了查询数据的功能,在线和离线模式下都能使用。
跟WebSQL不同的是,IndexedDB更像是一个NoSQL数据库,而WebSQL更像是关系型数据库。
window.indexedDB=window.indexedDB||window.mozIndexedDB||window.webkitIndexedDB||window.msIndexedDB;if(!window.indexedDB){console.log("你的浏览器不支持IndexedDB");}3.3创建库使用open方法创建数据库。
回顾本章,由关系数据库的优缺点及适用场景引申到HTML5中的数据库解决方案,以及使用方法,需要注意的是在使用HTML数据库的过程中需要检测浏览器是否支持数据库。实际开发项目由于考虑前端数据库的安全性以及性能等问题,如果切实需要使用需要谨慎,毕竟一般项目中数据库保存的都是敏感数据,即使保存在服务器中也需要一定的安全加密措施,所以一般前端存储的都是一些临时的数据。
网页中的绝大多数请求使用的是HTTP协议,HTTP是一个无状态的应用层协议,它有着即开即用的优点,每次请求都是相互独立的,这对于密集程度较低的网络请求来说是优点,因为无需创建请求的上下文条件,但是对于密集度或者实时性要求较高的网络请求(例如IM聊天)场景来说,可能HTTP会力不从心,因为每创建一个HTTP请求对服务器来说都是一个很大的资源开销。这时我们可以考虑一个相对性能较高的网络协议Socket,他的网页版本被称为Websocket。
近年来,随着HTML5和w3c的推广开来,WebSocket协议被提出,它实现了浏览器与服务器的实时通信,使服务端也能主动向客户端发送数据。在WebSocket协议提出之前,开发人员若要实现这些实时性较强的功能,经常会使用一种替代性的解决方案——轮询。
轮询的原理是采用定时的方式不断的向服务端发送HTTP请求,频繁地请求数据。明显地,这种方法命中率较低,浪费服务器资源。伴随着WebSocket协议的推广,真正实现了Web的即时通信。
WebSocket的原理是通过JavaScript向服务端发出建立WebSocket连接的请求,在WebSocket连接建立成功后,客户端和服务端可以实现一个长连接的网络管道。因为WebSocket本质上是TCP连接,它是一个长连接,除非断开连接否则无需重新创建连接,所以其开销相对HTTP节省了很多。
通过使用新建一个websocket对象的方式创建一个新的连接,不过在创建之前需要检测一下浏览器是否支持Websocket,因为只有支持HTML5的浏览器才能支持Websocket,如下:
由于JavaScript的各种IO操作是基于事件回调的,所以Websocket也不例外,我们需要创建一个连接成功的回调函数来处理连接创建成功之后的业务处理,如下:
ws.onmessage=function(event){vard=event.data;//接收到消息之后的业务处理switch(typeofd){//判断数据的类型格式case"String":break;case"blob":break;case"ArrayBuffer":break;default:return;}}上述实例通过监听message事件对websocket的消息进行一定的业务处理,这其中需要判断数据类型格式,因为Websocket是基于二进制流格式的,传输过来的消息可能不一定是基于utf8的字符串格式,因此需要对格式进行判断。
客户端通过使用send函数向服务端发送数据,例如:
ws.send("一段测试消息");代码块1可以发送文本格式,也可以发送二进制格式,例如:
varinput=document.getElementById("file");input.onchange=function(){varfile=this.files[0];if(!!file){//读取本地文件,以gbk编码方式输出varreader=newFileReader();reader.readAsBinaryString(file);reader.onload=function(){//读取完毕后发送消息ws.send(this.result);}}}2.5监听错误信息类似上述提到的如果创建实例失败的情况,系统会出现异常,但是我们并不能准确判断出异常的信息,这时需要通过监听错误事件来获取报错信息,例如:
ws.onerror=function(event){//这里处理错误信息}代码块12342.6关闭连接当服务端或者客户端关闭websocket连接时,系统会触发一个关闭事件,例如:
ws.onclose=function(event){//这里处理关闭之后的业务}代码块12342.7连接的状态通过websocket对象的readyState属性可以获取到当前连接的状态,其中常用的有4种,通过websocket对象的几种定义常量对比判断:
switch(ws.readyState){caseWebSocket.CONNECTING:break;//处于正在连接中的状态caseWebSocket.OPEN:break;//表示已经连接成功caseWebSocket.CLOSING:break;//表示连接正在关闭caseWebSocket.CLOSE:break;//表示连接已经关闭,或者创建连接失败default:break;}3.websocket实例实例演示
实际项目中使用websocket需要注意一些问题:
本章介绍了websocket的前世今生,详细说明其对应的API的调用方式,最后使用了一个简单的聊天室的例子来对其函数串通了一下,最后延伸了一下实际项目中使用websocket需要注意的地方,希望大家在实际开发中针对其优缺点来选择合适的使用场景。
在远古时代,网页大都是静态展示,服务器无需处理复杂且过多的请求,只需要静静地等待客户端的请求,将HTML代码通过HTTP的方式返回给客户端。因此服务器也没有主动推送数据给客户端的能力,毕竟HTTP是无状态的协议,即开即用。
后来随着互联网的发展,服务端有一些即时消息需要立即展示给客户端,早期的处理方式是通过客户端定时发起HTTP请求,这种方式命中率较低且浪费服务端资源。现在有了HTML5之后不需要那么麻烦了,可以使用websocket或者SSE。SSE全称server-sentevents单项消息传递事件,相对于websocket这种双向协议,SSE较为轻量,它只支持服务端向客户端推送消息。
通过新建一个sse对象可以创建一个SSE实例,但是不要忘记检测浏览器的支持情况:
上述示例实现了一个创建SSE对象的功能,创建之前需要检测是否支持,目前IE之外的大部分浏览器都支持SSE。sse对象只有一个初始化参数,用于指定服务器的url。
创建实例成功之后,通过监听message事件来实时获取服务端的消息:
source.onmessage=function(event){//处理业务请求console.log(event.data)}12345可查看在线运行效果
服务器端需要对客户端发起的HTTP请求做相应的回复,主要是将HTTP报文头的content-type字段设置成text/event-stream,下边以PHP举例:
除了监听message事件用于获取服务端的数据之外,还有open事件用于监听连接打开的状态,error事件用于监听错误信息。
并非所有场景都适合使用sse处理,在消息推送接收不频繁的情况下选用ajax轮询或者sse或者websocket其实差别不太大。sse应该适用于服务端向客户端发送消息频繁而客户端几乎无需向服务端发送数据的场景下,例如:
sse的优缺点:
本章介绍了websocket的轻量级版本sse协议,简述了sse协议的使用方法,对比了其他网页中常用的消息推送方式以及他们的优缺点,这些协议涵盖了大部分的使用场景,选用适合的协议类型可以避免不必要的资源和性能消耗。
本章节我们来介绍一个抽象的知识点-语义化。什么是语义化,浅显的来说就是使用合适的语法来实现相应的功能,这里说的合适并非是从性能、数据结构、算法等深度层面,而是从阅读和维护方式等层面。
编程过程中实现一个相同的功能,往往可以使用多种不同的方式,选择一个合适的方式需要综合考虑可维护性、扩展性、性能等几种不同的维度,而可维护性是其中比较重要的一个因素。可维护性就是指书写的代码是否通俗易懂方便阅读,当大家都遵守一种统一的书写标准时,团队的开发效率、协调能力就能得到很大的提升。
HTML语义化是指使用恰当语义的html标签、class类名、ID、属性名称等内容,让页面具有良好的结构与含义,从而让人和机器都能快速理解网页内容。语义化的HTML页面一方面可以让搜索引擎高效的理解和搜集网页内容;另一方面方便开发维护人员读懂代码。总结起来就是:正确的标签做正确的事情,页面内容结构化方便开发人员阅读,便于浏览器搜索引擎解析。
上述罗列了包含明确语义内容的标签,实际项目中应当根据实际场景选择对应的语义标签。
small标签属于HTML中的格式元素,用于显示较小的文本,例如:
用于定义小的文本1可查看在线运行效果
em用于显示斜体,它和i标签的效果类似,不同的是em是语义化元素,用于强调斜体,例如:
用于显示斜体1可查看在线运行效果
Mark标签用于显示黄色背景的文本,例如:
标记文本1可查看在线运行效果
figure标签用于在文档中插入图片、图标、照片、代码等流内容,例如:
figcaption标签用于figure标签的标题,它必须定义在figure内部,一个figure只能放一个figcaption,例如:
cite标签用于表示对某个文献引用的文本定义,例如书籍、杂志等内容,它所展示的是斜体文本,是一个典型的语义化标签,例如:
语义化标签已经远远超过了改变它所包含的文本外观的作用,它使浏览器能够以各种实用的方式来向用户表达文档的内容1可查看在线运行效果
blockquote用于定义源于另一个块内容的引用,它的默认展示方式是左右两侧缩进,例如:
1234可查看在线运行效果引用的段落1
引用的段落2
q标签用于定义短引用,浏览器默认会为它左右显示引号,例如:
知识付费市场蓬勃兴起,但也存在内容良莠不齐、服务跟不上等问题
,需要加以改进完善1可查看在线运行效果
dfn标签用于首次定义术语,仅仅包含术语,不必包含术语的定义,再次出现术语时可abbr元素表示,例如:
TheGDOisadevicethatallowsoff-worldteamstoopentheiris.
1可查看在线运行效果abbr标签用于定义一个缩写内容,当鼠标停留在内容上时,浏览器会展示title属性的内容,例如:
乘风破浪这个词,语出南朝名将宗悫1可查看在线运行效果
del标签用于定义带有删除线(下划线)的文本,例如:
原价:50,促销价:10
ins类似于del,不同的是这个标签是用于插入新的内容,展现形式是文本下边加上下划线,例如:
一打有二十十二件。
code标签用于展示计算机编程代码或者伪代码,专为软件开发人员设计的,文本将用等宽、类似电传打字机样式的字体(Courier)显示出来,例如:
document.getELementById("test");
12345可查看在线运行效果
meter元素用于度量给定范围内的数据,例如:
progress标签是用于定义进度条,HTML5之前的版本都是需要用div或者其他标签配合css以及JavaScript才能实现出来滚动条效果,现在只要定义一个标签就可以了,例如:
max属性用于表示滚动条的最大长度,value值表示当前完成了多少。
实际项目中应尽量按照如下标准,做到代码易扩展、易维护:
如下div布局及结构标签布局两个例子,在网页中展现一模一样。明显结构标签布局语义行更强,便于开发者理解和阅读: