Js的执行机制

JavaScript语言的一大特点就是单线程,同一个时间只能做一件事,这是js的诞生使命所致,比如对dom元素的添加和删除不能同时进行,应该先进行添加,之后再删除。

为了利用多核CPU的计算能力,HTML5提出Web Worker标准,允许JavaScript脚本创建多个线程,但是子线程完
全受主线程控制,且不得操作DOM。所以,这个新标准并没有改变JavaScript单线程的本质。

单线程会带来相应的缺点,如果有一个任务时间过长,那么后续的任务全都得等待,如果有一个定时器三秒之后执行某函数,那么这三秒,下面的代码就没法运行了,所以要克服单线程的弊端,可以采取cpu调度的那种思想,虽然我只有一个cpu,但是可以在不同的时间内,轮番的执行各个任务,这就诞生了js的异步。

同步和异步

  • 同步:前一个任务结束后再执行后一个任务,比如我必须烧完了水以后再把菜切了。
  • 异步:在做这件事的同时,你还可以去处理其他事情,比如我先烧着水,把菜切了再去使用烧好的水。
  • 同步任务:同步任务都在主线程上执行,形成一个 执行栈
  • 异步任务:JS中的异步是通过回调函数实现的

回调函数

Js语言对异步编程的实现就是回调函数,所谓回调函数,就是把任务的第二段单独写在一个函数里,等重新执行这个任务时便直接调用这个函数,回调函数的英文名为callback,意为重新调用,比如一个3秒的定时器,先执行定时器,然后执行其他任务,3秒后再执行定时器中的回调函数。

异步任务有以下三种类型

  1. 普通事件,如click,resize等
  2. 资源加载,如load,error等
  3. 定时器,包括setInterval,setTimeout等

异步任务相关回调函数添加到任务队列中

Js代码的执行顺序:

  1. 先执行执行栈中的同步任务
  2. 异步任务(回调函数)放入任务队列中
  3. 一旦执行栈中的所有同步任务执行完毕,系统就会按次序读取任务队列中的异步任务,于是被读取的异步任务结束等待状态,进入执行栈,开始执行

用一段代码来解释Js的执行机制:


console.log(1);
setTimeout(function() {
    console.log(3);
},1000);
console.log(2);

//执行的结果和顺序为 1、2、3
console.log(1);
setTimeout(function() {
    console.log(3);
},0);
console.log(2);

// 执行的结果和顺序为 1、2、3

程序从上到下依次执行,同步代码耗时比较短,放在主线程执行栈中,异步代码(回调函数)执行时间比较长,放在任务队列中,把栈中所有同步任务执行完了以后,再依次执行队列中的异步任务。
Js的执行机制(异步)-LMLPHP

多个异步任务的情况
比如下面这段代码,有两个回调函数,一个是单击事件的,还有一个定时器的:

// 3. 第三个问题
console.log(1);
document.onclick = function() {
    console.log('click');
}
console.log(2);
setTimeout(function() {
    console.log(3)
}, 3000)

// 如果是3秒前点击,结果为:1,2,click,3
// 如果是3秒后点击,结果为:1,2,3,click

回调函数交给异步进程处理,如果不点击的话,不会触发单击事件,对应的回调函数就不会放在任务队列中,定时器的回调函数会在3秒后,把回调函数放进队列,所以最后的结果跟单击的时间有关系。(队列是先进先出的)
Js的执行机制(异步)-LMLPHP

主线程不断的获得执行任务这一过程称为事件循环:
Js的执行机制(异步)-LMLPHP

09-29 03:58