浏览器中javascript的执行过程
2015-07-15 14:43
447 查看
http://www.360doc.com/content/13/0412/11/7492958_277750522.shtml
在讲这个问题之前,先来补充几个知识点,如果对此已经比较了解可以直接跳过 1. 大多数浏览器的组件构成如图 在最底层的三个组件分别是网络,UI后端和js解释器。作用如下: (1)网络- 用来完成网络调用,例如http请求,它具有平台无关的接口,可以在不同平台上工作 (2)UI 后端- 用来绘制类似组合选择框及对话框等基本组件,具有不特定于某个平台的通用接口,底层使用操作系统的用户接口 (3)JS解释器- 用来解释执行JS代码 ps:上图和知识点主要来自《HOW BROWSERS WORK: BEHIND THE SCENES OF MODERN WEB BROWSERS》 想深入了解的同学可以重点看下。 2. 大多数浏览器(比如chrome)让一个单线程共用于执行javascrip和更新用户界面。这个线程通常被称为“浏览器UI线程”, 每个时刻只能执行其中一种操作,这意味着当Javascript代码正在执行时用户界面无法响应输入,反之亦然。这样做是因为javascript代码的作用就是操作DOM更新用户界面,用同一个线程来做负责这两件事情可以更高效 3. 浏览器UI线程的工作基于一个简单的队列系统,任务会被保存到队列中直到进程空闲。一旦空闲,队列中的下一个任务就被重新提取出来并运行。这些任务要么是运行javascript代码,要么执行UI更新,包括重绘和重排。 4. 重点再强调下,javascript是单线程运行,千万别被setTimeout()和setInterVal()这种函数迷惑而误以为它是多线程。 ok,基础点讲解完毕,让我们进入正题,来讲解在浏览器中javascript的执行过程。 一、原理 一般而言,<script>标签每次出现都会霸道地让页面等待脚本的解析和执行,无论当前的Javascript是内嵌的还是包含了外链文件,页面的下载和渲染都必须停下来等待脚本执行完成。这在页面的生存周期中是必要的,因为脚本执行过程中可能修改页面内容,一个典型的例子就是在页面中使用document.write()。 当javascript代码是内嵌在html里面时,这点还是比较容易理解,但当javascript是外链文件时稍微有点负载,因为存在一个加载过程,而且浏览器加载好这个js文件之后往往还对其缓存。 首先,我们用以下这个例子来说明下缓存问题 <html> <head> <script type='text/javascript' src='js/f2.js'></script> </head> <body> </body> </html> 第一次打开页面时: 第二次打开页面时: 从上例中可以明显看出,像chrome之类的高版本浏览器会对js文件进行缓存,作用是不言而喻,减少网络请求。 其次,第二个问题,当一个javascript文件被加载时是否会阻塞其他javascript文件或者其他文件的加载。《高性能Javascript》一书中对这个问题做了较好的解答:各种浏览器的低版本的处理是当一个javascript文件在加载时,会同时阻塞页面其他文件的加载(包括其他javascript文件),但IE8,Firfox3.5,Safari 4和Chrome 2都允许并行下载javascript文件,但遗憾的是,javascript下载过程仍然会组舍其他资源的下载,比如图片。尽管javascript脚本的下载过程不会相互影响,但页面仍然必须等待所有的javascript代码下载并执行完成才能继续。 这里说句题外话:浏览器对同一域名下的并发链接数也是有限制的,其他一些参数如下: 二、技巧 1. 脚本位置 由于脚本会阻塞页面其他资源的下载,因此推荐将所有的<script>标签放到<body>标签的底部,已尽量减少对整个页面下载的影响。 2. 将能合并的js文件合并 3. 无阻塞脚本 现在比较常用的方法就是动态加载执行脚本。你的原理是通过DOM,你几乎可以用Javascript动态创建HTML中的所有内容,其根本在于,<script>标签与页面中其他元素并无差异:都能通过DOM引用,都能在文档中移动,删除和创建。文件在改该<script>元素被添加到页面时开始现在,它不会阻止其他文件下载,只在执行阶段阻塞渲染。特别强调:《高性能javascript》一文中说“这种技术的重点在于:无论何时启动下载,文件的下载和执行都不会阻塞页面其他进程”,这并不是说它在执行不会阻塞其他javascript代码,而是要强调不会阻塞其他资源的下载等其他任务。 具体的代码如下: function loadScript(url){ var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true; ga.src = url; (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(ga); } 4. 神奇的setTimeout() 这里我不过多的将setTimeout()的原理,有兴趣的读者可以具体去看《高性能javascript》的第六章。我重点强调下,setTimeout的第二个参数并不是一个精确的时间,二是必须在javascript线程空闲时才能运行。利用这个特性,如下代码简单可以实现等待其他js代码执行完毕后再执行function里面的代码。 setTimeout(function(){ // do some before other javascripe codes had processed }, 25) 但在function里面不要使用document.write()方法,因为执行setTimeout里面函数时往往已经到了页面onload之后,此时再执行 document.write 将导致当前页面的内容被清空,因为它会自动触发 document.open 方法。 |
相关文章推荐
- jsonp 跨域请求
- js获取事件源及触发该事件的对象
- 重写Backbone.js的加载动作
- BZOJ 1015 [JSOI2008]星球大战starwar
- 判断页面是关闭还是刷新的js代码
- js调用cs中函数的方法及在cs中调用js函数
- JSP通用7动作命令
- jsp中的js嵌入Extjs与后台action交互
- json.dumps loads 终于区分出来了
- md5 jsp页面,加密用
- jsp内置对象 的使用范围和类型【说明】
- JavaScript高级程序设计【面向对象-创建对象】
- 页面自动执行(加载)js的几种方法
- js的二维数组
- Javascript简单改变表单元素背景的方法
- 求帮看!!!!BZOJ 1014 [JSOI2008]火星人prefix
- js原生弹出框
- js原生贪吃蛇游戏
- 从网址获取json字符串
- 跨域请求问题以及相关解决方法之JSONP