JavaScript单线程与异步

单线程和异步 Event Loop

1.单线程

什么是单线程?和异步有什么关系

单线程:就是在同一时间只能做一件事情。

为什么使用单线程?

为了避免DOM渲染的冲突。(因为浏览器需要渲染DOM,JS也可以修改DOM,一个渲染节点另一个把节点删除了,那到底怎么弄)

HTML5 提出 websorker支持多线程,但是也不能访问DOM从这方面来说也验证了这个说法。

(JS执行浏览器DOM渲染暂停)也就是说JS执行的优先级高于浏览器渲染
两个JS不能同时执行(都修改DOM就冲突了)

单线程的问题

单线程意味这所有的任务都需要排队,执行完一个才能继续执行下一个,但是如果前一个执行很长,后一个任务就需要一直等待。

下面的例子就是单线程 同步的操作:必须从头到尾执行

//循环太多 卡顿
var i,sum = 0;
for(i = 0; i < 100000000; i++){
  sum += 1;
}
console.log(sum)
//alert
alert(1);
console.log(2);
alert(3)

如果排队是因为计算量大,CPU忙不过来,倒也算了,但是很多时候CPU是闲着的,因为IO设备(输入输出设备)很慢(比如Ajax操作从网络读取数据),不得不等着结果出来,再往下执行。

2.解决方案 - 异步

先看看异步:我们常用的setTimeout,setInterval,ajax请求都属于异步操作

主线程完全可以不管I/O设备,挂起处于等待中的任务,先运行排在后面的任务。等到IO设备返回了结果,再回过头,把挂起的任务继续执行下

console.log(100)
setTimeout(function(){
    console.log(200)
  },1000)
$.ajax({
  url:'./demo.js',
  success: function(result){
    console.log(result)
  }
})
console.log(300)
//100
//300
//200或请求的数据
异步是如何实现的?

JS中所有的任务我们可以把他分为两种,一种是同步任务,一种是异步任务。

整个任务的执行机制是:

  1. 将所有的同步任务放在主线程上,形成一个执行栈
  2. 将所有的异步任务都挂起,当达到条件的时候就会放在‘任务队列’中(监听事件,触发事件)
  3. 执行主线程上的所有同步任务,系统就会在’任务队列’中查看还有那些任务,异步任务结束等待状态,进入执行栈,开始执行
  4. 系统不断的在主线程和任务列队之间轮询重复上面的第3步奏

3.Event Loop

主线程从‘任务队列’中读取事件,整个不断循环的过程叫 Event Loop (事件轮询)

就上上面所说的步奏3:

主线程上的所有同步任务执行完后,系统就会在,异步任务结束等待状态,进入执行栈,开始执行.(栈中的代码调用各种外部API,它们在"任务队列"中加入各种事件(click,load,done)。只要栈中的代码执行完毕,主线程就会去读取"任务队列",依次执行那些事件所对应的回调函数)

console.log(100)
setTimeout(function(){
    console.log(200)
  },1000)
console.log(300)

还是这个例子:setTimeout会在1秒的时候(达到条件)放入任务队列中,在被系统轮询到,在丢到主线程中然后执行打印

说说异步的缺点
  1. 没有按照书写方式执行,可读性差

  2. callback 不容易模块化

这也就有了后面的ES6标准正式提出的Promise做了铺垫

延伸阅读:[阮一峰老师的 JavaScript 运行机制详解:再谈Event Loop]http://www.ruanyifeng.com/blog/2014/10/event-loop.html

猜你喜欢

转载自blog.csdn.net/qq_41463701/article/details/86559230