JS的主线程及执行栈

前言

JS是一门单线程语言,那为何能够实现异步操作呢?

单线程和异步操作确实不能同时成为一个语言的特性。JS本身不能实现异步,但是JS的宿主环境(浏览器,Node)是多线程的,宿主环境通过某种方式,使得JS具备了异步的特性。

浏览器

JS是单线程语言,浏览器只分配给JS一个主线程,用来执行任务(函数),但一次只能执行一个任务,这些任务形成一个任务队列排队等候执行,但前端的某些任务是非常耗时的,比如网络请求,定时器和事件监听,如果让他们和别的任务一样,都老老实实的排队等待执行的话,执行效率会非常的低,甚至导致页面的假死。

浏览器为这些耗时任务开辟了另外的线程,主要包括http请求线程浏览器定时触发器浏览器事件触发线程,这些任务是异步的。

任务队列

浏览器为这些异步任务单独开了一个线程,那么主线程是如何知道异步任务是否已经完成呢?这就需要依赖回调函数了,整个程序是靠事件驱动的,每个事件都有相应的回调函数。

setTimeout(function(){
    console.log('time up);
},50)

主线程

JS一直在做一个工作,就是从任务队列里提取任务,放到主线程里执行。

在这里插入图片描述

  • 浏览器为异步任务开启的线程序=>WebAPIs
  • 任务队列=>callback queue
  • 主线程
    • 堆和栈
    • 函数的执行就是通过进栈和出栈实现
    • 栈stack清空时,说明一个任务已经执行完成,这时会从callback queue中寻找下一个任务推入栈中

容易困惑的问题

setTimeout(f1,0)是否立即执行

setTimeout(()=>{
    console.log(1)
},0)
console.log(2)

// output => 2,1

当执行setTimeout后,浏览器会立即把匿名函数放入callback queue中,等待主线程的召唤,因为此时的stack还有console.log(2)尚未执行。等console.log(2)执行完毕后,才通过event loop把匿名函数放到stack中执行。

  • 结论:

    • setTimeout(f1,0)并非无意义,若f1是比较耗时的任务,又不在WebAPIs中,那就可以把它放到callback queue,等待主线程执行完毕后再执行。
    • 若当前代码执行时间很长,没有办法保证回调函数一定会在setTimeout指定的时间内完成。
  • 补充说明:

    • HTML5标准规定了setTimeout()的第二个参数的最小值(最短间隔),不得低于4毫秒,如果低于这个值,就会自动增加。在此之前,老版本的浏览器都将最短间隔设为10毫秒。
    • DOM的变动(尤其是涉及页面重新渲染的部分),通常不会立即执行,而是每16毫秒执行一次。这时使用requestAnimationFrame()的效果要好于setTimeout()

浏览器异步机制的使用

  • 当我们自己需要写的程序中也有比较耗时的函数。可以通过浏览器提供给我们的浏览器定时事件事件触发线程

异步的好处和使用场景

  • 同步
    在这里插入图片描述

  • 异步
    在这里插入图片描述

  • 使用场景

程序需要大量I/O操作和用户请求时

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值