浏览器端javaScript运行机制的理解
- 线程
- 同步异步
- Event-Loop
线程
Javascript语言的执行环境是"单线程"(single thread)。
所谓"单线程",就是指一次只能完成一件任务。如果有多个任务,就必须排队,前面一个任务完成,再执行后面一个任务,以此类推。而Javascript运行在浏览器上,然而浏览器内核是多线程的,它包含以下几个线程:
- GUI 渲染线程
- JavaScript引擎线程
- 定时触发器线程
- 事件触发线程
- 异步http请求线程
我们平时使用到最多的就是GUI 渲染线程,JavaScript引擎线程,异步http请求线程。
同步异步
浏览器端能够异步主要还是因为Event-Loop这个默默的在幕后执行。
1.同步
同步,也就是JavaScript在执行的时候是按照顺序执行,前一个任务执行完毕之后才会执行下一个任务。因此当遇到比较耗时的任务时,就是使得后边的任务长时间的等待,例如当浏览器端执行一段耗时js代码,就会使得浏览器假死。因此对于这种情况就需要将耗时的任务异步执行,不阻塞其他非耗时任务的执行。
2.异步
异步,简单说就是,将耗时任务放入其他线程执行,主线成会在将来的某个时刻收到回调通知。
浏览器端的异步方式:
- 回调函数
这是异步编程最基本的方法。
假定有两个函数f1和f2,后者等待前者的执行结果。
f1(); f2();
如果f1是一个很耗时的任务,可以考虑改写f1,把f2写成f1的回调函数。
function f1(callback){ setTimeout(function () { // f1的任务代码 callback(); }, 1000); }
执行代码就变成下面这样:
f1(f2);
采用这种方式,我们把同步操作变成了异步操作,f1不会堵塞程序运行,相当于先执行程序的主要逻辑,将耗时的操作推迟执行。
回调函数的优点是简单、容易理解和部署,缺点是不利于代码的阅读和维护,各个部分之间高度耦合(Coupling),流程会很混乱,而且每个任务只能指定一个回调函数。
- 事件监听
另一种思路是采用事件驱动模式。任务的执行不取决于代码的顺序,而取决于某个事件是否发生。
还是以f1和f2为例。首先,为f1绑定一个事件(这里采用的jQuery的写法)。
f1.on('done', f2);
上面这行代码的意思是,当f1发生done事件,就执行f2。然后,对f1进行改写:
function f1(){ setTimeout(function () { // f1的任务代码 f1.trigger('done'); }, 1000); }
f1.trigger('done')表示,执行完成后,立即触发done事件,从而开始执行f2。
这种方法的优点是比较容易理解,可以绑定多个事件,每个事件可以指定多个回调函数,而且可以"去耦合"(Decoupling),有利于实现模块化。缺点是整个程序都要变成事件驱动型,运行流程会变得很不清晰
- Promises对象
Promises对象是CommonJS工作组提出的一种规范,目的是为异步编程提供统一接口。
简单说,它的思想是,每一个异步任务返回一个Promise对象,该对象有一个then方法,允许指定回调函数。
function Client() { } Client.prototype.cancel = function (options) { options.cancelFlag = true; }; Client.prototype.operation = function (options) { var options = options || {}; options.cancelFlag = false; return new Promise(function (resolve, reject) { //异步请求开始 setTimeout(function () { if(!options.cancelFlag){ resolve('task finish'); } else { reject(new Error('cancel')); } }, 1000); }); }; var client1 = new Client(); var multipartOptions = { cancelFlag: false } client1.operation(multipartOptions).then(function (value) { console.log(value); }).catch(function (err) { console.log(err); }); client1.cancel(multipartOptions); console.log('cancel');
但是Promise一旦执行,不可取消。
Event-Loop
一张图来看一下

JavaScript引擎的内部运行机制跟Event loop没有任何的关系。
event loops隐藏得比较深,很多人对它很陌生。但提起异步,相信每个人都知道。异步背后的“靠山”就是event loops。这里的异步准确的说应该叫浏览器的event loops或者说是javaScript运行环境的event loops,因为ECMAScript中没有event loops,event loops是在HTML Standard定义的。
总结一点就是,除了js引擎线程外的其他线程在执行完任务后都会将结果加入到Event-Loop的任务队列中,只有当js引擎线程将当前任务执行完后才会去继续执行Event-Loop的任务队列的任务。
注:本文内容来自互联网,旨在为开发者提供分享、交流的平台。如有涉及文章版权等事宜,请你联系站长进行处理。