(十)Javascript中的JSON,渲染,异步加载,时间线(进程优化基础)

(十)Javascript中的JSON,异步加载,时间线(进程优化基础)

JSON

  • JSON是一种传输数据的格式(以对象为样板,本质上就是对象,但用途有区别,对象就是本地用的,json是用来传输的)
    • 为了区分对象和JSON,JSON中的属性名要加双引号
    • 所以前端后台传输数据的格式其实是字符串,只不过这个是JSON格式的字符串,使用下面的方法,来使对象变为JSON传输给后台
<student>
	<name>deng</name>
	<age>40</age>
</student>
好比创建了一个对象,标签名就是标签名
传输数据要满足JSON的格式(即对象的格式)
  • JSON.stringify(); json——>string


//JSON是一个静态类,是个构造函数,但不需要构造它
//因为JSON自身带着很多函数

<script type="text/javascript">
	var obj = {
    	"name":"deng";
        "age":40
    }
	console.log(JSON.stringify(obj));
//会返回字符串"{"name":"deng","age":123}"
	var str = JSON.stringify(obj);
</script>


  • JSON.parse(); string——> json(从后端接受字符串,转为对象)
var obj1 = JSON.parse(str);
//从后台传过来
//通过js操作把属性放在网页上

关于渲染

  • 浏览器在渲染前会创建一个domTree,把HTML代码一行一行识别,然后挂到树上,树的顶端,分叉为和,里面可能又有很多
  • 符合的原则:深度优先原则。一条枝干走到头
dom结点的解析
<img src="xxx">
<ifram src="xxx"></iframe>
<img src="xxx">
dom树的完成代表所有结点的解析完毕,并不是所有结点的解析完毕
  • 当dom树结构完成之后先等着,开始生成cssTree,与dom结点对应,同样是深度优先。

    • domTree + cssTree = randerTree

    • randerTree形成之后,浏览器才开始渲染页面

      • randerTree的重构 reflow(效率最低)重排

        • 会如何触发:dom结点的增删

          ​ dom结点的宽高变化,位置变化,display,none->block

          ​ offsetWidth offsetLeft(查看dom结点尺寸,因为求出结果是实时的,所以要重构randerTree)

      • 所以要避免重排

      • repaint 重绘

        • 比如背景颜色,字体颜色,背景图片位置(因为不影响位置)

异步加载JS

  • JS加载的缺点: 加载工具方法没必要阻塞文档,过度JS加载会影响页面效率,一旦网速不好,那么整个网站将等待js加载而不进行后续渲染等工作
  • 有些工具方法需要按需加载,用到再加载,不用不加载

当代码执行到script的时候,做的是同步加载,会阻断CSS和HTML的下载线,因为执行的JS会修改CSS和HTML,所以执行的时候是单线程的,要不然一个线程去增加一个结点,一个线程去删除一个结点,就没有定论了。所以JS是单线程的

  • 但有些JS文件不是用于操作页面的
    • 可能是初始化页面或是工具包
    • 所以我们希望它能实现异步加载(按需加载)

1、defer(IE)

- 用法:放入script标签中
- 概念:异步加载,但是要等到dom文档全部解析完(非加载)即构造好了randerTree才会被执行。注意这个只有IE能用,同时==可以将代码写至标签内部==

2、async

  • 概念:异步加载,加载完就执行,async==只能加载外部脚本(即内部不能写入代码)
  • 特点:执行时不阻塞页面
  • AJAX: asychronous javascript and xml

3、创建script,插入到DOM中,加载完毕后callback

  • 可按需加载
<script type = "text/javascript">
    //1.创建
	var script = document.createElement("script");
	//2.设置
	script.type = "text/javascript";
	//3.下载(发送请求的过程),这也是实现异步加载的过程
	script.src = "tools.js";
	//4.执行
	document.body.appendChild(script);
</script>

问题:没加载完src就执行了,调用src里面的函数会被报错未定义

  • 因为第三步的加载是异步加载,当代码来到第9行时,这个script放到body已经放入body中了,加入后面调用这个tool.js中的方法,但src认为加载完,会报错说调用的这个方法没有定义

  • 解决办法:提醒src下载完了,然后即可调用里面的方法

    script.onload=function(){test();}
    //这个load前面讲过,表示当script加载完就执行这个函数
    

    兼容性高,但是IE无法使用,所以对于IE(使用监听)

    //IE不用方法,IE用状态码(一个静态类的属性)
    script.readyState = "loading" 或者"complete" 或者"loaded"
    //表示script的加载状态
    script.onreadystatechange= function(){
        //进行校验
        if(script.readyState=="complete" || script.readyState=="loaded")
        test();   
    }
    
  
  - 衍生出来的问题:加入src一下下载完了,在执行下面的这个函数时,readyState实际上根本没有变化,状态从"complete"还是到"complete",所以不生效
    - 解决办法,先绑定函数的状态,再进行加载,即将`script.src=url;`放在这两个函数的后面,这样就一定会经过状态的改变

快乐的封装函数时间

- 这个函数的作用是通过异步加载来调用某个js文件中的函数

​```javascript
function loadScript(url,callback){
	//1.创建
	var script = document.createElement("script");
	//2.设置
	script.type = "text/javascript";
    //兼容IE的检查src是否加载完
    if(script.readyState){
        script.onreadystatechange= function(){
		if(script.readyState == "complete" || script.readyState == "loaded"){callback();}
		}
  	}
    else {
        script.onload = function(){ callback(); }
    }
    //3.异步加载文件
    script.src = url;
   //
    document.head.appendChild(script);
}
  • 这里同样衍生出一个问题,文件和调用文件内的方法一起传入,但是没见过这个方法,也就是说想要调用的函数存在于文件中,但文件并未加载,现在作为实参传进去,系统不识别,会给他认为是未定义报错

    • 解决方法一:(比如像调用tool.js文件中的test方法)
    loadScript("tool.js",function(){test();});
    
    • 解决方法二:传入字符串
    loadScript("tool.js", "test();");
    //需要把callback改为 eval(callback)
    //eval的作用就是把字符串当作带代码来使
    //但注意es3.0不能用,开启严格模式可以
    
    • 解决方法三:同样传入字符串,但需要配合
    loadScript("tool.js", "test");
    //在tool.js中,test()被归属于它里面的一个对象的对象的方法
    var tool = {
    	test : function(){}
    }
    //需要把callback改为tool[callback]
    

JS加载时间线(为后面优化做铺垫)

  • 依据JS出生那一刻开始,记录的一系列浏览器按照顺序做的事

    1. 创建Document对象,开始解析web页面。document.readyState = “loading”
    2. 遇到link外部css,创建线程加载,并继续解析文档
    3. 遇到script外部js,并且没有设置async、defer,浏览器加载,并阻塞,等待js加载完并执行完该脚本,然后继续解析文档
    4. 遇到script外部js,并且有设置async、defer,浏览器创建线程加载,并继续解析文档。对于async属性的脚本,脚本加载完成后立即执行(异步禁止使用document.write())
    //假设在这个script标签前面有一系列的html和css,他们刚形成randerTree
    <script>
    	window.onload = function(){
    		document.write("a");
    	}
    </script>
    
    //这时候页面剩下a,这个document.write("a")会把前面的文档流都清空
    
    1. 遇到img等,先正常解析dom结构,然后浏览器异步加载src(图片的源头),并继续解析文档
    2. 当文档解析完成(domTree完成),document.readyState = “interactive”.
    3. 文档解析完成后,所有设置有defer的脚本会按照顺序执行(根据第六步的监听)。(注重与async不同,async的script一解析完就执行)
    4. document对象触发DOMContentLoader事件,这也标志着程序执行从同步脚本执行阶段,转化为事件驱动阶段(以及可以接触事件了)
    5. 当所有async脚本加载完成并执行后、img等加载完成后,document.readyState = “complete”
    6. 从此异步响应方式处理用户输入、网络事件

    主要记1文档解析 6 文档解析完成 7defer按顺序执行 8触发事件,转化阶段 9所有东西执行并加载好

    <script>
    	console.log(doncument.readtState);
    	//这里显示loading,因为打印出来这时,整个文档还没解析完,就是这里,
    	//domTree还没形成完,script自个也是个结点,这里形成了一半
    	
    	//给document绑定监听事件
    	document.onreadtstatechange = function(){
    	console.log(document.readyState)
    	}
    	//这里显示 loading(前面的) 
    	//interactive(监听到解析好) complete(监听到加载好)
    
    	//关于第8步
    	//在document上,给这个DOMContnetLoader绑定事件处理的程序
    	document.addEventListener("DOMContentLoaded",function(){
    		console.log("a")
      },false)
    	//这时后页面的控制台上为
      //loading interactive a complete
    	//所以含有这个的script可以不用写在尾部,因为它可以在下面的domTree解析构建完后执行 
    
```
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值