zoukankan      html  css  js  c++  java
  • 前端--关于客户端javascript

    • 浏览器中的Javascript

      客户端javascript就是运行在浏览器中的javascript,现代的浏览器已经有了很好的发展,虽然它是一个应用程序,但完全可以把它看作是一个简易的操作系统,因为像windows、linux等操作系统提供的文档存储、网络调用、绘制图像等功能在浏览器中也同样都可以得到支持,所以就像操作系统中的应用程序叫做桌面应用一样,浏览器中可互动的web文档也叫做web应用。

      在web应用中,浏览器是javascript的运行环境,这个运行环境不仅包含了javascript解释器以使js程序可以正确的运行,还为解释器提供了其他服务的接口来扩展了javascript的功能,比如发起网络调用、DOM编程等。当一个页面开始加载的时候js解释器就会启动,启动后做的第一件事就是初始化一个全局对象,这个全局对象在不同运行环境中会有不同的标识符表示和内容,在nodeJS中这个全局对象叫global,而在浏览器中这个全局对象叫window。一个window对象就代表一个窗体,里面除了包含javascript语法内置的函数和对象外,还包括浏览器为其扩展的功能对象,这些功能对象就是前面说的服务接口,是浏览器提供的服务的对象化表示。

    • Javascript的执行

      解释器启动之后就可以执行javascript代码了,在浏览器中触发javascript代码运行的情况只有两种:

    • 文档加载的时候:浏览器在加载解析页面文档的过程中如果遇到了<script>标签引用或者包含的js代码,解释器就会执行一遍。
    • 事件触发的时候:这种情况是异步且由事件驱动的,解释器执行的代码是前一种情况下为事件注册的处理函数。

      其中第一种情况要尤其注意,当浏览器在下载执行js文件的时候,页面的解析和渲染是被阻塞的,也就是说页面的其他有关资源会停止下载(比如css文件、图片等),同时DOM树的构建也会暂停,因为js程序的执行是有可能影响到DOM树的结构的(比如说使用到了document.write方法),DOM树的解析一暂停,页面的UI渲染也会被迫暂停。这样就会产生性能问题,如果js文件过大或者js代码执行时间过长,浏览器等待响应的时间就越久。所以考虑到性能问题,浏览器中js脚本应该尽可能的是无阻塞的脚本。

    • 无阻塞脚本

      由阻塞脚本的阻塞过程可以知道,无阻塞的脚本可以从两个方面来考虑:不阻塞页面相关资源的下载和不阻塞页面UI的渲染。

        要是单单实现不阻塞其他资源的下载只有一种方法,就是在<script>标签中添加defer或者async,这种方法的效果是实现并行下载,也就是说当js文件在下载的时候不会阻塞其他资源的下载,它俩的区别是下载完后js代码执行的时机,defer会一直推迟到页面解析完,而async会在js文件下载完后立即执行,但js文件在执行过程中还是会阻塞页面解析和渲染的。由于浏览器对这种方法的支持不是很充分,所以这并不是一个兼容性很强的方法。

      其他的几种方法就是既不阻塞下载也不阻塞渲染了,首先是一种讨巧的方法,就是把<script>标签放到<body>底部,因为浏览器是一边解析渲染一边显示出来的,等解析到body标签最底部的时候页面也就完全在浏览器中显示出来了,这时候再下载和执行js文件基本上不存在阻塞这回事情了,但是要注意的是放到最后面的js文件尽量不要再对DOM进行操作,因为更改了DOM可能会产生回流或者重绘,回流和重绘也是非常耗性能的两个操作,影响用户的使用体验。还有一点是asp.net程序要注意的是在webform编程中,如果后台代码要用到前台的js函数,那么放在body标签底部的函数是注册不过去的,后台只能注册放在head标签中的函数。

      还有一种方法是创建动态脚本元素,这种方法可以说是做到了异步无阻塞,在js文件下载和执行的时候都不会阻塞页面的解析和渲染。该方法需要动态的创建script标签,并把标签添加到head元素中,比如

    var script = document.createElement('script');
    script.type='text/javascript';
    script.src='xxxxx.js';
    document.getElementsByTagName('head')[0].appendChild(script);
    

     当代码执行到最后一句的时候js文件开始下载,下载完后立即执行,这整个过程不会阻塞页面解析和渲染。这是动态创建带有src属性的script标签的时候,还有另外一种动态创建内联脚本的方式,该方法通过Ajax请求获取到js脚本内容,再动态创建script标签把脚本内容注入到script标签当中。这种方法不是很常用因为有一个缺点就是获取的js内容只能是同域中的。

      一个性能良好的页面不只是要做到无阻塞脚本,还有很多其他方面要注意的。 其中一条就是不要让一段js代码执行太长时间,因为javascript语言中不存在任何线程机制,并且js引擎也是单线程模型的,所以js代码的执行都是同步的,长时间的占用执行线程会使其他的js代码无法得到执行。如果必须要计算一个密集的任务,那么可以把这个任务通过setTimeout或setInterval分离成多个异步子任务。这里的同步和异步看起来似乎有些矛盾,javascript怎么可能既是单线程同步的又是多线程异步的呢? 原因在于浏览器的机制。

    • Javascript单线程与事件的异步        

       虽然javascript引擎是单线程的,但是浏览器是多线程的,在一个浏览器进程中一般有四个线程:javascript引擎线程、渲染引擎线程、浏览器事件线程(我也不知道叫什么)、http请求线程。在javascript引擎线程中有一个执行队列,里面的任务是同步的依次执行,而在浏览器事件线程中有一个任务队列,当某个事件触发时,该事件对应的回掉函数会放到这个任务队列中,这个任务队列是一个先进先出结构,当javascript引擎线程中的任务都执行完毕后,会从浏览器事件线程中的任务队列里读取任务放到javascript引擎线程中的执行队列里去执行,这个过程是不断循环的,这有个专业术语叫Event Loop。所以就算setTimeout(fun,0)这种看起来是立即执行的函数也并不一定会立即执行的,这个fun函数会先放到任务队列里面等待执行队列中的任务执行完毕才会被执行,所以fun函数的执行会延迟一段时间,这么样子的写法只是改变了fun函数的执行顺序。

      

  • 相关阅读:
    虚拟机更新为阿里数据源
    linux设置开机同步时间
    linux免密码登录
    Google 开源的 Python 命令行库:深入 fire(一)
    统计各个分类和标签下的文章数
    缩写名词解释
    Google 开源的 Python 命令行库:初探 fire
    稳定易用的 Django 分页库,完善分页功能
    Python 命令行之旅:使用 click 实现 git 命令
    Python 库打包分发、setup.py 编写、混合 C 扩展打包的简易指南(转载)
  • 原文地址:https://www.cnblogs.com/jinjilin/p/5191611.html
Copyright © 2011-2022 走看看