'单线程'的浏览器

之前一直会有疑问,js是单线程的,那如何实现的前端向后台发送多个http请求,还同时维护这么多请求的会话,今天就来深入探寻下浏览器线程和js线程

首先,js的单线程是指浏览器的js引擎是单线程的,不过浏览器还包含了其他的线程:

  • js引擎线程
  • 页面渲染线程
  • http请求线程
  • 事件触发线程
  • EventLoop轮询的处理线程

这几个线程的主要作用:

页面渲染线程:就是负责渲染页面的,因为js会影响页面的渲染,所以页面渲染线程和js引擎是互斥的

js引擎线程:js引擎线程也不是单线程的,而是包含主线程和其他线程,主线程是主要处理js任务的,是从消息队列里去拿任务进行单线程处理,那就需要一个线程负责把js任务放入到消息队列中,这就需要Eventloop的轮询,查看页面交互,点击事件,异步的http线程返回的结果,之后要处理,就会放到消息队列中

setTimeout(function () { while (true) { } }, 1000);
    setTimeout(function () { console.log('end 2'); }, 2000);
    setTimeout(function () { console.log('end 1'); }, 100);
    console.log('end');

这段代码中,会输出 end,end1,然后浏览器假死,为什么按照时间,console.log(‘end 2’);这个方法是在消息队列中排在while (true) { } 执行的后面,不过while (true) { }这个同步任务js的引擎线程会一直执行,所以永远执行不到console.log(‘end 2’),除非中间跳出任务,才会执行到下个任务

html5也推出了多线程功能,Worker类

//主线程
worker.addEventListener('message', function(e){
    //e.data为从worker线程得到的数据
});
worker.possMessage(...);//向worker线程发送数据


//工作线程
addEventListener('message', function(e){
    //e.data为从主线程得到的数据
});
possMessage(...);//向主线程发送数据

例如:

//worker.js
function calculate(){
  var ret = 0;
  for(var i = 1; i <= 1e9; i++){
    ret += i;
  }
  return ret;
}
postMessage(calculate());


//demo.js
var worker = new Worker('scripts/worker.js');
worker.addEventListener('message', function(e){
  console.log(e.data); //500000000067109000
}, false);