JavaScript的单线程执行及其异步机制矛盾否?

对线程与进程、同步与异步了解不深,有了这样的困惑。翻了一些帖子,看了大牛的文章,按自己的理解总结一下。



1. JavaScript单线程


JavaScript是单线程的,指浏览器进程中只有一个js的执行线程,也就是同一时间内只有一段js代码(或者说一个任务)在执行。但如我们所想,多线程的执行效率会更高些,那为什么js不能有多线程呢?

JavaScript作为浏览器的脚本语言,用于与用户的交互和dom的操作,设想如果有两个线程同时操作一个dom,难免会有冲突发生。所以单线程是JavaScript语言本身的特性。


2. JavaScript异步机制

 

JavaScript是单线程执行的,但浏览器是多线程的,所以JavaScript异步机制是由浏览器的两个及以上常驻线程:js执行线程 和 事件触发线程等共同实现的。js执行线程作为主线程执行js代码,遇到异步执行语句时会向浏览器发送一个异步请求并告知回调函数。浏览器开一个新的线程来处理请求,js执行线程继续处理其他任务。事件触发线程监听这个请求,当请求完成时就将事件压入任务队列中,等待进入到主线程中执行。



说到这,得详细说说JavaScript的运行机制了。


js执行的任务分为两种:同步任务(synchronous) 和 异步任务(asynchronous)。同步任务指排列在主线程中等待执行的任务,这些任务形成了一个执行栈(execution content stack),只有前一个任务执行完,后一个任务才能执行。异步任务指不进入主线程而进入任务队列(task queue)的任务,当执行栈任务执行完后,任务队列中的任务才会进入到主线程中执行。

任务队列是一个事件的队列,包括I/O事件、定时器、用户事件(点击事件、滚屏事件等)。异步请求一定会指定回调函数,回调函数在异步请求执行期间被主线程挂起,当主线程执行异步任务时就是在执行回调函数。

主线程从任务队列中读取任务的过程是不断循环的,称作 Event Loop(事件循环),当执行栈(同步任务)一空就去读取任务队列(异步任务)。



举例

1. Ajax发送异步请求时的代码:

    var req = new XMLHttpRequest();
    req.open('GET', url);    
    req.onload = function (){};    
    req.onerror = function (){};    
    req.send();
与下面等价:
    var req = new XMLHttpRequest();
    req.open('GET', url);
    req.send();
    req.onload = function (){};    
    req.onerror = function (){}; 
因为req.send()方法属于异步任务,而指定回调函数是执行栈的一部分,属于同步任务。不管send()放在前还是后,都会先处理执行栈中的任务,再读取任务队列中的任务,所以指定回调函数的语句总是先执行,与send()位置无关。


2. 定时器

定时器功能主要由setTimeout()和setInterval()实现。由浏览器的定时线程执行计数,事件触发线程监听到计数完毕后,将事件压入到任务队列的尾部等待执行。如setTimeout(fn,0) 会在当前执行栈任务和任务队列前排的任务都执行完毕后立即执行fn函数。


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值