1、json: 轻量级的数据交换格式;[前后端数据传输都是json格式的,对象里面的键必须要有双引号,不可省略;传输过程中json是以字符串进行传输的,直接对象形式传输不可以,其识别的是二进制,所以传输过程中使用的是二进制的文本格式即字符串]
(1).xml: 其是一种语言(xml ->xhtml ->html),最初也作为数据交换格式使用,其以标签作为数据名,标签内容作为数据值进行传递数据,其可以自定义标签,传输效率低下,如今大多使用json;[前后端通信传递数据是以字符串的形式进行,字符串内填充数据,而且数据就是对象的形式,前端给后端传递数据,传递的是字符串类型的数据,后台收到进行解析成对象再进行一系列的操作(类如:表单数据收集),同理后台传递给前端的数据也是字符串格式,需要转化为对象] [传递数据需要高效、便捷]
(2).json 是以对象为样板,本质上就是对象,在js中“一切都是对象”,但其和对象的用途上有区别,对象是本地使用(浏览器端、服务器端),json是用来传输的,形式上也有区别,json中的属性必须加双引号,不可省略;对象中双引号可以省略【区分json和对象的要点】
json数据:var obj = { "name": "abc","age": 18};json字符串:"{ "name": "abc","age": 18}"
(3).以下这两个方法很重要:进行解析数据的第一步【JSON、Math都是静态类,使用过程中不能new +构造函数创建对象使用;其上有很多属性和方法,直接使用就OK】
JSON.stringify(); json --->>> string; JSON.parse(); string --->>> json;
[var obj = {name:"nba",age:18} --->> JSON.stringify(obj); -->> "{ "name": "nba","age": 18}", json本质也是对象,目前JSON操作时也识别为json对象]
2、异步加载:前面谈到html和css是异步加载,js是同步加载,加载到js部分阻塞页面的加载直到js加载完成,所谓异步加载:工具类/数据初始化的js脚本库异步加载,操作dom元素的js脚本进行同步加载即可;(操作dom元素的js脚本若是异步加载,每次改动必然会影响domTree,进而影响randerTree,耗费性能); 【js是单线程,若是双线程,一个线程增加dom元素,一个线程删除dom元素,执行哪个?
浏览器内核中有渲染引擎和js引擎,渲染页面的过程是怎样的?html、css、js文件执行顺序是怎么样的呢?
头部引入的css文件和html是异步线程执行,引入的js文件和html是同步执行:js文件加载完成后,html才能接着进行解析,也就是js会阻塞后面的dom解析(若遇到网速不好等情况,整个网站将等待js库加载而不进行后续渲染);日常开发中,一些工具类的js库、引入的第三方库,我们希望其可以同时进行加载,没必要阻塞dom解析,影响页面效率,最好采用异步加载的方式;
(1).接下来先分析一些页面渲染过程:(结合原生js小结图示过程)
[1].渲染引擎是一行行(按像素点)进行渲染页面的,代码中就是一行行执行代码(当然并非视觉编程的顺序,有预编译过程),首先它会进行domTree的绘制,遵循“深度优先原则”,渲染dom的过程中,若是存在一些Img标签、a标签等含有src、href属性,和css样式有所关联的,内部依旧会继续解析dom元素到domTree上,但css相关样式也开始绘制;
[2].domTree树绘制完成后,cssTree的绘制是同时进行的,[1]中只是绘制相关元素的位置,现在开始绘制和domTree有关的所有样式;
[3].cssTree树绘制完成后,其和domTree会进行结合形成渲染树,domTree + cssTree = renderTree; 有了renderTree后,渲染引擎才开始按着它开始渲染页面;
[4].期间
标签部分引入的js文件,其会阻塞页面的渲染过程,这里还需要介绍两个重要概念:reflow 、 repaint;[4.1] js可以操作html,进而也可以间接操作css,每一次操作都会对domTree产生影响,domTree一变化,就需要重新绘制domTree、cssTree,这种改变称为reflow重排(重构、重做),很影响性能,这也是我们不要随便修改html结构的原因[常见可引起重构的行为:dom节点的删除增加、dom元素的宽高变化、位置变化,display:none -->>> display: block; 改变某个元素会对后续元素产生一系列影响; offsetWidth offsetHeight 这两个虽是查看元素,但依旧会对dom元素产生影响]
[4.2]repaint 重绘,其区别于reflow,只需要进行部分domTree重绘即可,大多是一些样式的微弱改变,不影响html结构,例如字体颜色、背景图片、背景颜色等等,对后续元素也无影响,对性能也有影响,但很小;
(2).JS异步加载的三种方法:操作dom元素的还是采取同步加载,对于工具库/初始化数据的库,采取异步加载或者按需加载来提高页面效率;
[1].defer异步加载,只有IE9以下可用,在script标签加入单属性即可; ; 其不仅可以引入外部文件,也可以将代码写入内部,; 其只能加载外部脚本,不能把js代码写在内部,同时其是加载后就执行;
如何处理兼容性:封装在任何浏览器都能异步加载脚本库;
方法一: 这种方式也不合理;
--->>> 开发中采取的方法:进行if判断,if(IE){使用defer}else{使用async}
[3].按需加载:异步加载并且按需加载,什么时候用到该脚本,什么时候进行加载,不用就不用管它;应用场景也很多,例如:有的按钮用户很少会点击,但却有产品价值,而且点击有可能会出现很多信息,可以对其进行“按需加载”,用户点击的时候动态加载完毕即可,不一定执行到该脚本库就阻塞页面或异步加载;
按需加载才是最合适的异步加载方案:创建script,插入到html中,加载完毕后callBack;(内容较多,附详细过程)
[3.1]. 重点:创建script标签后,添加script.src="tools.js"时,只是进行异步加载,并没有执行;
-------->>>>>>>代码跑起来的时候会报错,下载资源需要过程:发出请求,等待响应,响应后开始反馈资源,期间过程是以微秒(us)计算,由于是异步加载,下面的代码在加载过程中便开始执行,执行过程中若是找不到该方法便会报错;错误原因:加载时间大于代码执行时间;
[3.2]使用定时器验证上述说法:
-------->>>>>代码可以正常运行,加载的时间受很多因素影响,例如网速不好等,接下来进行一些操作解决bug,等其加载完成后再执行代码;
[3.3].load事件,很多对象都有load事件,并非window独有(涉及到下载的就有load事件);表示:下载完成后触发事件,兼容性很好,safari/chrome/firefox/opera都兼容,IE浏览器也有load事件,但IE中的script标签上没有load事件;
[3.4].IE使用: readystatechange事件,IE在script上设置了状态码readState,随着加载过程其的属性值会变化;开始:script.readyState = "loading",--->>>加载完成后:script.readyState="complated" / script.readyState="loaded";[IE和高版本的chrome、firefox的script有此事件,但是其他浏览器的dom元素上也有此事件和属性;document.readyState,表示状态]
[3.5]封装兼容性函数:url:引入的脚步库,callback(); 回调函数,当满足一定条件才执行的函数;将script.src=url;换位置的原因是解决bug,防止IE无法判断,解释:IE判断的标准就是script的状态码是否发生变化,若是代码执行到script.src=url; 加载速度特别特别快,在执行下面的判断语句前,已经加载完成,这时候script.readyState="complete"; 这时候就那些if条件判断时,里面的事件就无法触发,这时里面的函数也无法执行,所以可以先让其进行if条件判断,然后再加载;
[3.6]封装兼容性函数[最终版]:如果只是异步加载脚本库,传入url即可,封装的是较为灵活的,按需加载脚本库、函数,callback如果多个函数,可以以数组形式传入,灵活应用;
补充:
(1).实际操作中又报错;解释:结合预编译的过程,函数执行前并不能解析函数内部到底有什么内容,当函数执行时,执行到第二个参数的时候,里面的脚本库还未加载成功,会报错;
解决方案1:使用函数引用作为参数,当传入时并不会解析里面的内容,用到的时候才会解析;
解决方案2: loadScript("tools.js","test()"); 第二个参数可以为字符串形式,eval();和setInterval();可以将字符串转化为代码执行;不常用,es3.0也不支持eval();
对象属性名的方式也可以;(实操中也可使用)
总结:
(1).渲染引擎解析html/css,js引擎解析javascript代码,domTree + cssTree = renderTree;渲染引擎开始渲染页面;
(2).js会阻塞dom的解析,解析过程就是识别dom元素的过程(domTree包含元素节点/文本节点等系列节点,聚焦点为元素节点),而dom树的加载完成包含里面的图片、a标签的链接等都下载完毕,触发window.onload,显然dom解析必然是在dom加载之前完成;
(3).当属性等于属性值的时候,可直接写一个属性名即可,也称为单属性,系统可以识别,但是最好写成属性=“属性值”的写法;
3、js时间线:
(1).创建document对象,开始解析web页面。解析HTML元素和他们的文本内容后添加Element对象和Text节点到文档中。这个阶段document.readyState = ‘loading’;
(2).遇到link外部css,创建线程加载,并继续解析文档;
(3).遇到script外部js,并且没有设置async、defer,浏览器加载,并阻塞,等待js加载完成并执行该脚本,然后继续解析文档;
(4).遇到script外部js,并且设置有async、defer,浏览器创建线程加载,并继续解析文档。 对于async属性的脚本,脚本加载完成后立即执行;(异步禁止使用document.write())
(5).遇到img等,先正常解析dom结构,然后浏览器异步加载src,并继续解析文档;
(6).当文档解析完成,document.readyState = ‘interactive’;
(7).文档解析完成后,所有设置有defer的脚本会按照顺序执行。(注意与async的不同,但同样禁止使用document.write());【defer脚本监视的便是document.readyState的状态】;
(8).document对象触发DOMContentLoaded事件,这也标志着程序执行从同步脚本执行阶段,转化为事件驱动阶段;
(9).当所有async的脚本加载完成并执行后、img等加载完成后,document.readyState =‘complete’,window对象触发load事件;
(10).从此,以异步响应方式处理用户输入、网络事件等。
补充:
[1].关于document.write();其会把括号里的内容当作是html文档输出到页面里去,但有两种特殊情况,1.当页面全部加载完成,其会将页面内容全部清空;2.异步加载过程中使用也会将页面内容清空;【开发中也没太大用处,尽量不要使用】
[2].文档解析完成:domTree解析完成,不同于页面加载完成,页面加载完成包括randerTree、js都加载完成;(文档解析完成发生在页面加载完成之前)
[3].事件驱动阶段,页面加载完成后基本都是都是这个阶段,没有事件的为纯静态页面;
[4].window.onload=function(){}; 整个页面加载完成后执行; $(document).ready(function(){ }); jquery中这种方式表示dom解析完就执行;document.addEventListener('DOMContentLoaded',function(){},false); dom解析完成后就执行;[此事件没有句柄的方式,只能使用addEventListener();]
如图也不会报错,阻断dom解析进行加载,完成后继续进行dom解析,此事件会在dom解析完成后开始执行,所以这种写法没错,但是不建议;【dom解析目的是生成dom树,script是标签当然也会存在于dom树上,但里面的js代码是js引擎进行解析的,渲染引擎和js引擎功能不同,最后渲染引擎开始渲染页面,就是视图所看到的】