浏览器中JavaScript执行原理

简介: 原文:浏览器中JavaScript执行原理本章我们讨论javascript在浏览器中是如果工作的,包括:下载、解析、执行的全过程。javascript的这些讨人嫌的地方我们是知道的: i.需要串行下载 ii.需要解析 iii.需要串行执行 而在chrchromium中,js是这样解析的:(其实第一章末尾已经有了) 至于一些步骤的解释,这里就不再复述了,不懂的请戳:浏览器渲染过程 拉至末尾。
原文: 浏览器中JavaScript执行原理

本章我们讨论javascript在浏览器中是如果工作的,包括:下载、解析、执行的全过程。javascript的这些讨人嫌的地方我们是知道的:

i.需要串行下载

ii.需要解析

iii.需要串行执行

而在chrchromium中,js是这样解析的:(其实第一章末尾已经有了)

至于一些步骤的解释,这里就不再复述了,不懂的请戳:浏览器渲染过程 拉至末尾。

简直就是大魔王有木有?心中可有一万只草泥马奔腾而过?为什么在所有的下载线程中:

i.css加载不会阻塞页面

ii.images加载不会阻塞页面

iii.flash加载不会阻塞页面

iiii.activeX加载不会阻塞页面

iiiii.ajax还有同步异步之分

特么javascript文件就会阻塞页面!!

 

既然如此,我们能回避UI阻塞吗

i.在页面底部(</body>之前)引入js脚本,原因:由于js加载阻塞页面,而HTML是下载多少渲染多少,因此我们把它至于页面底部,让UI线程先执行完再加载js脚本

ii.根据具体情况,通过combo和compress减少请求数(通常在正式生产环境,我们将多个js脚本压缩为一个)

BUT ,这并没有真正回避UI阻塞,在</body>之前存在一个较大的脚本需要加载执行时,UI在ready后,需要较长的时间等待脚本加载和执行,在脚本ready前,UI是处于无事件响应状态的。

iii.defer属性

   HTML4标准中为<script>标签定义的属性,用于告诉浏览器:内容中包含document.write之类破坏DOM的脚本

   浏览器会无阻塞式(延迟)加载脚本,并且按页面中<script>标签顺序串行执行js脚本

   在HTML渲染完毕之后,onload触发之前执行

   支持:IE4.0+ ,FF3.5+

iiii.async属性

   HTML5标准中为<script>标签定义的属性

   对比defer,以下相同:

    无阻塞式加载

   以下不同:

    加载完立即执行

      不保证按照页面中<script>标签顺序执行   

    支持:FF3.6+ ,Chrome ,Opera10.5+ ,Safari ,IE9+

iiiii.不依赖浏览器版本的方式

    Dynamic Script DOM ,比如google分析:

   

    XHR Inject

    XHR Eval

    Script in Iframe 

还有问题吗?当然还有:

i.并行、异步加载脚本也需要保证顺序、同源策略、CDN、缓存等因素的影响

ii.没有通用的解决方案,不过我们可以:

  使用LABjs || requireJS || seaJS 等管理我们的脚本加载

  服务端combo脚本

iii.以上可以相对完美的解决脚本下载问题,但这并不能解决脚本执行阻塞的问题

  异步大法好

 

关于异步

i.你是否认为: 异步 == (方法 + 回调) ? 呵呵 ... 你懂得! 冒泡排序的异步例子:

var innerLoop = function (array, x, y, callback) {
 if (y < array.length - x) {
  compare(array[y], array[y + 1], function (r) {
   if (r > 0) {
    swap(array, y, y + 1, function () {
     innerLoop(array, x, y + 1, callback);
    });
   } else {
    innerLoop(array, x, y + 1, callback);
   }
  });
 } else {
  callback();
 }
}

outerLoop(array, 0, function () {
 console.log("done!");
}
);
var compare = function (x, y, callback) {
 setTimeout(10, function () {
  callback(x - y);
 });
}

var swap = function (a, i, j, callback) {
 var t = a[i]; a[i] = a[j]; a[j] = t;
 repaint(a);

 setTimeout(20, callback);
}

var outerLoop = function (array, x, callback) {
 if (x < array) {
  innerLoop(array, x, 0, function () {
   outerLoop(array, x + 1, callback);
  });
 } else {
 callback();
 }
}

ii.你是否认为: 浏览器是单线程执行的 ?

iii.你是否使用 setTimeout || setInterval 模拟过多线程 ?

iiii.异步编程是有难度的:

   破坏了代码的局部性

   难以应用于需要保持顺序的场景

   难以处理异常及取消

   难以操作异步之间的协作及组合

问题根源:

i.javascript是单线程语言

   不能创建线程

   不能开展并行任务

   不能对线程操作

ii.阻塞UI渲染

如何解决:

i.浏览器并不是单线程的货,我们可以利用如下异步线程:

     资源下载线程(javacript、images、css、object)

     ajax线程

     web worker线程

     setTimeout模拟多线程

 

总结

我们可以使用各种组合方式、现代浏览器的新特性去处理这些问题,总而言之,没有一种方案是通用的。我们需要在对应的场景中找出最合适的方案,而这些方案无非是围绕这些原理做出的变体。

目录
相关文章
|
22天前
|
JavaScript 前端开发 UED
JS:如何获取浏览器窗口尺寸?
JS:如何获取浏览器窗口尺寸?
31 1
|
1月前
|
自然语言处理 JavaScript 前端开发
探索JavaScript中的闭包:理解其原理与实际应用
探索JavaScript中的闭包:理解其原理与实际应用
19 0
|
1月前
|
JavaScript
JS数组增删方法的原理,使用原型定义
JS数组增删方法的原理,使用原型定义
|
1天前
|
JavaScript
浏览器插件crx文件--JS混淆与解密
浏览器插件crx文件--JS混淆与解密
6 0
|
1天前
|
前端开发 JavaScript 编译器
深入解析JavaScript中的异步编程:Promises与async/await的使用与原理
【4月更文挑战第22天】本文深入解析JavaScript异步编程,重点讨论Promises和async/await。Promises用于管理异步操作,有pending、fulfilled和rejected三种状态。通过.then()和.catch()处理结果,但可能导致回调地狱。async/await是ES2017的语法糖,使异步编程更直观,类似同步代码,通过事件循环和微任务队列实现。两者各有优势,适用于不同场景,能有效提升代码可读性和维护性。
|
5天前
|
JavaScript 前端开发
JavaScript如何获得浏览器的宽高
JavaScript如何获得浏览器的宽高
|
8天前
|
JavaScript 前端开发 安全
JavaScript DOM 操作:解释一下浏览器的同源策略。
**同源策略**是浏览器安全基石,它阻止脚本跨不同协议、域名或端口访问资源,防止恶意行为。例如,HTTP页面无法直接用JS获取HTTPS页面内容。**CORS**允许跨域请求,但需服务器配合设置,通过`document.domain`属性可配置,但仍受限于服务器配置。
11 4
|
15天前
|
JavaScript
【归总】原生js操作浏览器hash、url参数参数获取/修改方法合集
【归总】原生js操作浏览器hash、url参数参数获取/修改方法合集
|
20天前
|
存储 JavaScript 前端开发
在浏览器中存储数组和对象(js的问题)
在浏览器中存储数组和对象(js的问题)
|
1月前
|
JavaScript
JS中call()、apply()、bind()改变this指向的原理
JS中call()、apply()、bind()改变this指向的原理