您的位置:首页 > Web前端 > JavaScript

对浏览器端javaScript运行机制的理解

2018-01-09 15:24 267 查看
点击有惊喜


浏览器端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的任务队列的任务。

点击有惊喜

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: