JSON传输格式,浏览器渲染页面过程,JS异步加载,js时间线

JSON传输格式

json是一种传输数据的格式(以对象为样板,本质上即使对象,但是用途有区别,对象就是本地用的,json是用来传输的)

对象的属性加不加双引号都可以,但是json规定 json格式的属性名必须加上双引号

JSON是一个静态类(类似于Math),不用去构造它,它自己就有这些方法。

  • JSON.stringifg(); json—>string

  • JSON.parse(); string—>json

 var obj = {
	   "name" : "abc",
       "age"  : 123
  }
var str = JSON.stringify(obj);
console.log(str);//"{"name":"abc","age":123}"

console.log(JSON.parse(str));//Object{name: "abc", age: 123}

前后端传输的时候传的都是json格式的字符串

浏览器渲染页面过程

第一步,首先是建立一个dom树,它是解析所有的dom节点(深度遍历的方法)
解析dom节点就是解析到哪个dom节点就把它挂到dom树上
像碰到< img src = “XXX”/>这样的还是只把img节点挂到dom树上,意思就是说dom树的构建完成就是所有dom节点的解析完毕,并不代表所有dom节点加载完毕(dom的解析完毕一定在dom加载完毕之前)。
在这里插入图片描述

第二步生成cssTree
浏览器解析CSS代码,计算出最终的样式数据。解析CSS的时候会按照如下顺序来定义优先级:浏览器默认设置,用户设置,外联样式,内联样式,html中的style(嵌在标签中的行间样式)。
在这里插入图片描述

第三步生成randertree,也可以说是渲染树
渲染树中每一个节点都存储着对应的CSS属性。
因为js可以操作dom,所以当渲染树建立后,如果动态的操作了dom,机会导致页面重新渲染,叫做reflow重排(重构)

reflow重排:dom节点的删除,添加。dom节点的宽高变化,位置变化,displaynone–>block,offsetwidth,offsetLeft等一系列都会导致重排。

repaint重绘:js改变了节点 的css,会导致那一部分的重绘,这样影响比较小。

在这里插入图片描述

第四步:当渲染树创建完成之后,浏览器就可以根据渲染树直接把页面绘制到屏幕上。
DOM树完全和html标签一一对应,而渲染树会忽略不需要渲染的元素(head、display:none的元素)。

JS异步加载

js加载的缺点

js加载本身是属于同步加载的,加载js文件会阻塞文档,比如有多个js文件,在加载到一个文件处有错后面的就加载不了

或者一旦网速不好,那么整个网站将等待js加载而不进行后续渲染等工作

但是有些工具方法需要按需加载,有一些工具js文件它是不会改变页面的,用到再加载,不用不加载。

javascript异步加载的三种的方案

  1. . defer异步加载

defer异步加载,但要等到dom文档全部解析完才会被执行,也可以将代码写到内部。
defer 属性是一个布尔属性。

<script src="demo_defer.js" defer></script> 
  1. async 异步加载

async 异步加载,加载完就执行,async 只能加载外部脚本(只有在使用 src 属性时),不能把js写在script标签里。
Internet Explorer 9 及之前的版本不支持 script 标签的 async 属性。
异步脚本一定会在页面 load 事件前执行。

<script src="demo_async.js"  async></script>

defer和async异步加载时不阻塞页面,但是兼容性不好,不能控制加载的顺序

3. 创建script,插入到DOM中,加载完毕后callBack

<script>
       var script = document.createElement('script');
       script.type = "text/javascript";
       script.src = "demo.js";//到了这一步之后就会异步的去下载demo.js文件
       document.head.appendChild(script);//当把标签插入到页面的时候才会去执行这个js脚本
 </script>

接下来我么创建一个名为demo.js文件写入test函数

function test(){
condole.log("a“)}

执行他

<script>
       var script = document.createElement('script');
       script.type = "text/javascript";
       script.src = "demo.js";//到了这一步之后就会异步的去下载demo.js文件

       document.head.appendChild(script);//当把标签插入到页面的时候才会去执行这个js脚本
       test();
  
    </script>

执行到test()时候会报错
Uncaught ReferenceError: test is not defined

这是因为文件还没有下载完,读程序是以微秒计的。
有可能异步的下载demo.js文件还没有下载完,程序就读到test执行这了
还没有下载完demo.js,当然没有test函数了

接着我们 添加一个setTimeout() 方法,让test()在1000毫秒后再执行时不时就不报错了

<script>
       var script = document.createElement('script');
       script.type = "text/javascript";
       script.src = "demo.js";//到了这一步之后就会异步的去下载demo.js文件

       document.head.appendChild(script);//当把标签插入到页面的时候才会去执行这个js脚本
       setTimeout(function () {
            test();
        }, 1000)
  </script>     

但是这样并不能从根本上解决问题,我们需要知道程序什么时候异步把外部js文件下载完成

下面介绍几种方法让我们知道什么时候加载完成

  • load事件监听

Safari,chrome,firefox,opera都可以用这个来监听什么时候这个文件异步下载完毕

<script>
       var script = document.createElement('script');
       script.type = "text/javascript";
       script.src = "demo.js";
       script.onload = function(){
             test();
       }
       document.head.appendChild(script);
    </script>

当文件下载完之后就会执行onload方法,这样就知道什么时候demo.js加载完了。

  • 如果是IE浏览器 就用·状态码的改变·来知道什么时候完成文件的下载
<script>
       var script = document.createElement('script');
       script.type = "text/javascript";
       script.src = "demo.js";
	   script.onreadystatechange = function(){
           if(script.readyState == "complete" || script.readyState == "loaded"){
               test();
           }
       }
	   document.head.appendChild(script);
    </script>

综合以上两钟方法实现所有浏览器兼容

<script>
       var script = document.createElement('script');
       script.type = "text/javascript";
       script.src = "demo.js";//到了这一步之后就会异步的去下载demo.js文件
       
       if(script.readyState){
            script.onreadystatechange = function(){
            if(script.readyState == "complete" || script.readyState == "loaded"){
                test();
            }
         }
       }else{
            script.onload = function(){
                test();
            }
       }
   
       document.head.appendChild(script);
      
    </script>

案例:封装一个函数兼容性的异步加载js文件并且可以按需执行该文件里面的函数

callback:回调函数
在事件里面的绑定的事件处理函数就是回调函数,回调函数其实就是当满足一定条件才调用的函数。

      function loadScript (url, callback){
           // url是异步下载的js文件
           //callback是异步下载的js文件中的某一个函数
        var script = document.createElement('script');
        script.type = "text/javascript";
        script.src = url;//异步下载的js文件
        if(script.readyState){
            script.onreadystatechange = function(){
                if(script.readyState == "complete" || script.readyState == "loaded"){
                    callback();
                }
           }
        }else{
            script.onload = function(){
                callback();
            }
        }
        
        document.head.appendChild(script);
       }
</script>

在IE上如果下载太快(比读程序还快),IE的readystatechange 事件检测状态码的时候,它早已经从loading变成complete或者loaded(以极快的速度加载完了文件,你还没来得及检测),
那你再检测它就不会变了,它一直都是complete或者loaded,这个时候检测也没用了。

<script>
function loadScript (url, callback){
           // url是异步下载的js文件
           //callback是异步下载的js文件中的某一个函数
        var script = document.createElement('script');
        script.type = "text/javascript";
  
        if(script.readyState){
            script.onreadystatechange = function(){
                if(script.readyState == "complete" || script.readyState == "loaded"){
                    callback();
                }
           }
        }else{
            script.onload = function(){
                callback();
            }
        }
        script.src = url;//开始异步下载的js文件
        document.head.appendChild(script);
       }
</script>

先绑定事件,然后再script.src = url开始异步下载js文件,那么这个时候下载,肯定有一个状态码的转换,这样就解决了来不及检测状态码的尴尬。

时间线
  1. 创建Documen对象开始解析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.wite()) ;

  8. document对象触发DOMContentLoaded事件,这也标志着程序执行从同步脚本执行阶段,转化为事件驱动阶段。

  9. 当所有async的脚本加载完成井执行后。img等加载完成后,document.readyState = ‘complete’, window对象触发load事件。

  10. 从此,以异步响应方式处理用户输入,网络事件等。

document.write()会清除文档流

<body>
    <div style="width:100px;height:100px;background-color:red;"></div>
    <script>
        window.onload = function () {
            document.write('a');
        }
    </script>
</body>

这个时候页面就只会输出a,div就被清除了

创建Documen对象开始解析web页面,script标签也是dom元素,所以它也要识别,这个阶段document.readyState= ‘loading’ 。

<!DOCTYPE html>
<html lang="en">
<head></head>
<body>
 <script>
        console.log(document.readyState);//loading  
<script>
</body>
</html>

用状态码改变才能检测文档解析到哪个状态了

<body>
<script>
      console.log(document.readyState);//loading  
       document.onreadystatechange = function (){
          console.log(document.readyState);// interactive   complete
      }
<script>
</body>

DOMContentLoaded事件只有用addEventListener绑定才有效

document.addEventListener('DOMContentLoaded',function(){ console.log('a')},false);

正常的情况下,当文档加载(解析文档,就是构成dom树,然后再加载dom元素)完毕后,才执行js代码,
但是document对象触发DOMContentLoaded事件可以当dom解析完了(dom树构建完成,还没加载完毕的时候)就去执行js代码

/就像jquery里面的
当dom解析完就执行的部分
$(document).ready(function (){

})

现在用document对象触发DOMContentLoaded事件放在head里面,照样可以拿到div
因为它是在dom树构建完成之后就调用事件的那个处理函数,不用等到文档全部加载完毕
而window.onload()就是要等到文档全部加载完毕了(像img的src的图片加载完成了),它才会执行window.onload()里面的js。

<!DOCTYPE html>
<html lang="en">
<head>
    <script>
        document.addEventListener('DOMContentLoaded',function(){
            var div = document.getElementsByTagName('div')[0];
            console.log(div);
        },false);
    </script>
</head>
<body>
    <div style="width:100px;height:100px;background-color:red"></div>
</body>
</html>
  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>铜仁市3D地图(点击地图区域跳转到相应页面)</title> [removed][removed] [removed][removed] [removed][removed] </head> <body> <!-- 3D地图容器 --> <div id="main" 100%; height: 800px;"></div> [removed] // 初始化图表 var myChart = echarts.init(document.getElementById('main')); // JSON文件(地图数据)路径 var uploadedDataURL = "json/522200.json"; // 显示加载动画效果,可以在加载数据前手动调用该接口显示加载动画,在数据加载完成后调用 hideLoading 隐藏加载动画。 myChart.showLoading(); // 引入JSON文件 $.getJSON(uploadedDataURL, function(geoJson) { // 注册地图名字(tongren)和数据(geoJson) echarts.registerMap('tongren', geoJson); // 隐藏动画加载效果。 myChart.hideLoading(); // 图表配置项 var option = { title : { // 标题 top : '5%', text : '铜仁市3D地图', subtext : '', x : 'center', textStyle : { color : '#ccc' } }, tooltip : { // 提示框 trigger : 'item', formatter : function(params) { return params.name; } }, series: [{ type: 'map3D', // 系列类型 name: 'map3D', // 系列名称 map: 'tongren', // 地图类型。echarts-gl 中使用的地图类型同 geo 组件相同(ECharts 中提供了两种格式的地图数据,一种是可以直接 script 标签引入的 js 文件,引入后会自动注册地图名字和数据。还有一种是 JSON 文件,需要通过 AJAX 异步加载后手动注册。) // 环境贴图,支持純颜色值,渐变色,全景贴图的 url。默认为 'auto',在配置有 light.ambientCubemap.texture 的时候会使用该纹理作为环境贴图。否则则不显示环境贴图。 environment: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ // 配置为垂直渐变的背景 offset: 0, color: '#00aaff' // 天空颜色 }, { offset: 0.7, color: '#998866' // 地面颜色 }, { offset: 1, color: '#998866' // 地面颜色 }], false), label: { // 标签的相关设置 show: true, // (地图上的城市名称)是否显示标签 [ default: false ] //distance: 50, // 标签距离图形的距离,在三维的散点图中这个距离是屏幕空间的像素值,其它图中这个距离是相对的三维距离 //formatter:, // 标签内容格式器 textStyle: { // 标签的字体样式 color: '#000', // 地图初始化区域字体颜色 fontSize: 8, // 字体大小 opacity: 1, // 字体透明度 backgroundColor: 'rgba(0,23,11,0)' // 字体背景色 }, }, itemStyle: { // 三维地理坐标系组件 中三维图形的视觉属性,包括颜色,透明度,描边等。 color: 'rgba(95,158,160,0.5)', // 地图板块的颜色 opacity: 1, // 图形的不透明度 [ default: 1 ] borderWidth: 0.5, // (地图板块间的分隔线)图形描边的宽度。加上描边后可以更清晰的区分每个区域 [ default: 0 ] borderColor: '#000' // 图形描边的颜色。[ default: #333 ] }, emphasis: { // 鼠标 hover 高亮时图形和标签的样式 (当鼠标放上去时 label和itemStyle 的样式) label: { // label高亮时的配置 show: true, textStyle: { color: '#fff', // 高亮时标签颜色变为 白色 fontSize: 15, // 高亮时标签字体 变大 } }, itemStyle: { // itemStyle高亮时的配置 areaColor: '#66ffff', // 高亮时地图板块颜色改变 } }, groundPlane: { // 地面可以让整个组件有个“摆放”的地方,从而使整个场景看起来更真实,更有模型感。 show: false, // 是否显示地面。[ default: false ] color: '#aaa' // 地面颜色。[ default: '#aaa' ] }, regions: [{ // 可对单个地图区域进行设置 name: '玉屏侗族自治县', // 所对应的地图区域的名称 //regionHeight: '', // 区域的高度,可以设置不同的高度用来表达数据的大小。当 GeoJSON 为建筑的数据时,也可以通过这个值表示简直的高度。 itemStyle: { // 单个区域的样式设置 color: '#00FF00', opacity: 1, borderWidth: 0.4, borderColor: '#5F9EA0' }, }, { name: '碧江区', itemStyle: { color: '#EEEE00', opacity: 1, borderWidth: 0.4, borderColor: '#5F9EA0' }, }], //shading: 'lambert', // 三维地理坐标系组件中三维图形的着色效果,echarts-gl 中支持下面三种着色方式: // 'color' 只显示颜色,不受光照等其它因素的影响。 // 'lambert' 通过经典的 lambert 着色表现光照带来的明暗。 // 'realistic' 真实感渲染,配合 light.ambientCubemap 和 postEffect 使用可以让展示的画面效果和质感有质的提升。ECharts GL 中使用了基于物理的渲染(PBR) 来表现真实感材质。 // realisticMaterial: {} // 真实感材质相关的配置项,在 shading 为'realistic'时有效。 // lambertMaterial: {} // lambert 材质相关的配置项,在 shading 为'lambert'时有效。 // colorMaterial: {} // color 材质相关的配置项,在 shading 为'color'时有效。 light: { // 光照相关的设置。在 shading 为 'color' 的时候无效。 光照的设置会影响到组件以及组件所在坐标系上的所有图表。合理的光照设置能够让整个场景的明暗变得更丰富,更有层次。 main: { // 场景主光源的设置,在 globe 组件中就是太阳光。 color: '#fff', //主光源的颜色。[ default: #fff ] intensity: 1.2, //主光源的强度。[ default: 1 ] shadow: false, //主光源是否投射阴影。默认关闭。 开启阴影可以给场景带来更真实和有层次的光照效果。但是同时也会增加程序的运行开销。 //shadowQuality: 'high', // 阴影的质量。可选'low', 'medium', 'high', 'ultra' [ default: 'medium' ] alpha: 55, // 主光源绕 x 轴,即上下旋转的角度。配合 beta 控制光源的方向。[ default: 40 ] beta: 10 // 主光源绕 y 轴,即左右旋转的角度。[ default: 40 ] }, ambient: { // 全局的环境光设置。 color: '#fff', // 环境光的颜色。[ default: #fff ] intensity: 0.5 // 环境光的强度。[ default: 0.2 ] } }, viewControl: { // 用于鼠标的旋转,缩放等视角控制。 projection: 'perspective', // 投影方式,默认为透视投影'perspective',也支持设置为正交投影'orthographic'。 autoRotate: false, // 是否开启视角绕物体的自动旋转查看。[ default: false ] autoRotateDirection: 'cw', // 物体自传的方向。默认是 'cw' 也就是从上往下看是顺时针方向,也可以取 'ccw',既从上往下看为逆时针方向。 autoRotateSpeed: 10, // 物体自传的速度。单位为角度 / 秒,默认为10 ,也就是36秒转一圈。 autoRotateAfterStill: 3, // 在鼠标静止操作后恢复自动旋转的时间间隔。在开启 autoRotate 后有效。[ default: 3 ] damping: 0, // 鼠标进行旋转,缩放等操作时的迟滞因子,在大于等于 1 的时候鼠标在停止操作后,视角仍会因为一定的惯性继续运动(旋转和缩放)。[ default: 0.8 ] rotateSensitivity: 1, // 旋转操作的灵敏度,值越大越灵敏。支持使用数组分别设置横向和纵向的旋转灵敏度。默认为1, 设置为0后无法旋转。 rotateSensitivity: [1, 0]——只能横向旋转; rotateSensitivity: [0, 1]——只能纵向旋转。 zoomSensitivity: 1, // 缩放操作的灵敏度,值越大越灵敏。默认为1,设置为0后无法缩放。 panSensitivity: 1, // 平移操作的灵敏度,值越大越灵敏。默认为1,设置为0后无法平移。支持使用数组分别设置横向和纵向的平移灵敏度 panMouseButton: 'left', // 平移操作使用的鼠标按键,支持:'left' 鼠标左键(默认);'middle' 鼠标中键 ;'right' 鼠标右键(注意:如果设置为鼠标右键则会阻止默认的右键菜单。) rotateMouseButton: 'left', // 旋转操作使用的鼠标按键,支持:'left' 鼠标左键;'middle' 鼠标中键(默认);'right' 鼠标右键(注意:如果设置为鼠标右键则会阻止默认的右键菜单。) distance: 200, // [ default: 100 ] 默认视角距离主体的距离,对于 grid3D 和 geo3D 等其它组件来说是距离中心原点的距离,对于 globe 来说是距离地球表面的距离。在 projection 为'perspective'的时候有效。 minDistance: 40, // [ default: 40 ] 视角通过鼠标控制能拉近到主体的最小距离。在 projection 为'perspective'的时候有效。 maxDistance: 400, // [ default: 400 ] 视角通过鼠标控制能拉远到主体的最大距离。在 projection 为'perspective'的时候有效。 alpha: 40, // 视角绕 x 轴,即上下旋转的角度。配合 beta 可以控制视角的方向。[ default: 40 ] beta: 15, // 视角绕 y 轴,即左右旋转的角度。[ default: 0 ] minAlpha: -360, // 上下旋转的最小 alpha 值。即视角能旋转到达最上面的角度。[ default: 5 ] maxAlpha: 360, // 上下旋转的最大 alpha 值。即视角能旋转到达最下面的角度。[ default: 90 ] minBeta: -360, // 左右旋转的最小 beta 值。即视角能旋转到达最左的角度。[ default: -80 ] maxBeta: 360, // 左右旋转的最大 beta 值。即视角能旋转到达最右的角度。[ default: 80 ] center: [0,0,0], // 视角中心点,旋转也会围绕这个中心点旋转,默认为[0,0,0]。 animation: true, // 是否开启动画。[ default: true ] animationDurationUpdate: 1000, // 过渡动画的时长。[ default: 1000 ] animationEasingUpdate: 'cubicInOut' // 过渡动画的缓动效果。[ default: cubicInOut ] }, data: [{ // 可对单个地图区域进行设置 name: '玉屏侗族自治县', // 所对应的地图区域的名称 //regionHeight: '', // 区域的高度,可以设置不同的高度用来表达数据的大小。当 GeoJSON 为建筑的数据时,也可以通过这个值表示简直的高度。 itemStyle: { // 单个区域的样式设置 color: '#00FF00', opacity: 1, borderWidth: 0.4, borderColor: '#5F9EA0' }, }, { name: '碧江区', itemStyle: { color: '#EEEE00', opacity: 1, borderWidth: 0.4, borderColor: '#5F9EA0' }, }] }] }; // 设置图表实例的配置项以及数据,万能接口,所有参数和数据的修改都可以通过setOption完成,ECharts 会合并新的参数和数据,然后刷新图表。 myChart.setOption(option); }); // 处理点击事件并且跳转到相应的百度搜索页面 myChart.on('click', function (params) { var subSystem = params.name; var url = 'https://www.baidu.com/s?ie=UTF-8&wd;='; // 根据点击地图区域的名称,跳转到对应页面 if(subSystem == '德江县'){ window.open(url.concat(subSystem)); }else if(subSystem == '思南县'){ window.open(url.concat(subSystem)); }else if(subSystem == '江口县'){ window.open(url.concat(subSystem)); }else if(subSystem == '沿河土家自治县'){ window.open(url.concat(subSystem)); }else if(subSystem == '万山区'){ window.open(url.concat(subSystem)); }else if(subSystem == '碧江区'){ window.open(url.concat(subSystem)); }else if(subSystem == '石阡县'){ window.open(url.concat(subSystem)); }else if(subSystem == '玉屏侗族自治县'){ window.open(url.concat(subSystem)); }else if(subSystem == '松桃苗族自治县'){ window.open(url.concat(subSystem)); }else if(subSystem == '印江土家族苗族自治县'){ window.open(url.concat(subSystem)); } /*alert(params.name); */ }); [removed] </body> </html>

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

周偏偏偏

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值