`

异步运行

 
阅读更多

一、为什么js是单线程?

所谓单线程,是指在js引擎中负责解释执行js代码的线程只有一个,不妨叫他主线程。

但是实际上还存在其他的线程。例如:处理ajax请求的线程、处理DOM事件的线程、定时器线程、读写文件的线程等等。这些线程可能存在于js引擎之内,或之外。这里统称为工作线程

js的单线程与它的用途有关。作为浏览器脚本语言,js的主要作用就是与用户互动,以及操作DOM。这决定了它只能是单线程,否则会带来很复杂的同步问题。比如,js上有两个线程,一个线程在DOM某节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准?所以为了避免这种复杂性,从一诞生,js就是单线程,将来也不会改变

 

二、一个例子引发问题

for(var i = 1;i<=3;i++){
   setTimeout(function(){
     alert(i);
   },100);
}

js中会弹出三次4,而不是一眼望去的1,2,3。其原因就在于异步运行

 

 三、异步任务

所有任务可以分为两种:同步任务和异步任务。同步任务指的是在主线程上排队执行的任务,异步任务指的是不进入主线程、而进入“任务队列”的任务。

一个异步过程通常是这样的:

主线程发起一个异步请求,相应的工作线程接受请求并告知主线程已收到(异步函数返回);主线程继续执行后面的代码,同时工作线程执行异步任务;工作线程完成工作后,通知主线程;主线程收到通知后,执行一定的动作(调用回调函数)

 

异步函数通常具有以下形式:

A(args...,callback)

从主线程角度看,一个异步过程包括两个要素:发起函数A和回调函数callback

它们都是在主线程上调用,其中注册函数用来发起异步过程,回调函数用来处理结果。当然不一定是这种格式比如:

var xhr = new XMLHttpRequest();
xhr.onreadystatechange = xxx;//回调函数
xhr.open('GET',url);
xhr.send();//发起函数

 

四、消息队列和事件循环

异步过程中,工作线程在完成异步操作后需通知主线程。那么这个通知机制时怎样实现的呢?答案就是消息队列和事件循环。

一句话就是:

工作线程将消息放到消息队列中,主线程处理完同步任务后通过事件循环去消息队列上取消息并处理

消息队列:FIFO

事件循环:指主线程重复从消息队列中取消息、执行的过程

主线程只有将当前的消息执行完成后,才会去取下一个消息。这种机制就叫事件循环机制,取一个消息并执行的过程叫做一次循环。而所谓的事件举个例子

var button = document.getElement('#btn');
button.addEventListener('click', function(e) {
    console.log();
});

 

这里的addEventListener就是发起函数,当鼠标点击该button时工作线程任务完成,将回调函数加入消息队列并通知主线程

 

异步过程如下图: 


 五、例子解释

setTimeout的真正含义是:在指定的毫秒数后,将定时任务处理的函数添加到执行队列的队尾。

这段函数的过程大致是:在执行到setTimeout函数时,异步线程返回继续执行for循环,当主线程上代码走完时而且时间到了100毫秒时,会有三个回调函数进入到消息队列等待执行,这时i===4,事件循环的结果就是弹出三个4

  • 大小: 22.4 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics