JS中的同步与异步笔记

JS中的同步与异步

个人笔记,欢迎友好交流讨论。关于同步、异步、微任务、宏任务、事件轮询、如何实现异步编程,内容较多,目前只学习了一小部分,继续gogogo!!!

单线程与多线程

单线程

JS是一门单线程的语言。单线程:如果在同一时间有多个任务,这些任务就需要排队执行,前一个任务执行完,才会执行下一个任务。

为什么 JS 是单线程的语言?

JS 是浏览器的脚本语言,主要用于实现和用户的交互。
前端主要使用 JS 实现对 DOM 的各种各样的操作,如果 JS 是多线程的语言,
那么一个线程 要对一个DOM节点中增加内容,另一个线程 要对这个 DOM 节点进行删除操作,
那么这个DOM节点执行哪一个线程的操作呢???这会带来复杂的同步问题。
所以,从用途分析,JS 是单线程的语言
// 同步代码
function fun1() {
  console.log(1);
}

function fun2() {
  console.log(2);
}

fun1();
fun2();

// 输出
1
2

代码解析:依次输出 1,2,因为这段代码是从上到下依次执行,执行完 fun1() ,才继续执行 fun2()。

问题分析:如果,在 fun1() 函数中添加一个延时器,让其延迟一段时间后再执行,那么后面的代码 fun2() 要等到 fun1() 完全执行完才会执行吗???为了解决这一问题,需要理解 JS 中的 同步和异步。

同步任务和异步任务

  1. 为什么会有同步和异步?

    在前文中,我们知道 JavaScript 是单线程语言,因此在同一时间只能处理一个任务,所有的任务都需要排队,前一个任务完成之后,才会执行下一个任务。

    问题:当前一个任务的执行时间很长,比如延时器或 ajax 操作,此时主线程处于等待状态,并没有处理任务,而是可能在等待请求完成拿到响应的结果,此时,该任务之后的其他任务全部处于等待状态。对页面来说,此时页面的 js 部分没有继续加载,不利于用户体验。。。

    为了解决这一问题,JS 设计了同步任务和异步任务,当一个任务耗时很长时,主线程可以不用等待它执行完成,可以先执行其后的任务,再回过来执行这个耗时很长的任务。因此,JS中将任务分为 同步任务异步任务

  2. 同步任务

    同步任务指 主线程 上排队执行的任务,只有前一个任务执行完毕,才能继续执行下一个任务

    理解:让代码按照从上往下正常流程执行的,就是同步

  3. 异步任务

    异步任务指 不进入主线程,而进入任务队列的任务,只有任务队列通知主线程,某个异步任务可以执行了,该任务才会进入主线程

    理解:改变程序正常执行顺序的操作,就是异步操作。最基础的异步是 **setTimeotsetInterval**函数。

异步机制

JS 将任务执行分为同步任务和异步任务,按照正常代码执行流程,可以实现同步任务的执行,那么如何实现异步呢?

主线程:JS 的代码在执行时,只启动一个单线程,就是代码执行的主线程。进入主线程的任务才会被执行。

任务队列:当代码读取到 异步任务 时(如:ajax操作、延时器等),会将异步任务 放到任务队列中,队列的特点是 先进先出,先进入的任务会先执行。

在代码按照流程顺序执行时,遇到同步任务会将任务添加到主线程中,进入执行栈中执行;遇到异步任务,会将异步任务添加到任务队列中。当执行栈中的任务清空完成之后,主线程才会去读取任务队列,将任务队列中的任务放到执行栈中去执行。

事件循环:单线程从任务队列中不断读取任务,放入执行栈中,每次执行栈被清空,又去执行栈中读取新的任务,这一重复的过程叫做事件循环

综上:

总结异步机制为:

  • 所有同步任务都在主线程上执行,形成一个执行栈
  • 主线程之外,存在一个任务队列。只要异步任务有了结果,就会在任务队列中放置一个事件
  • 一旦执行栈中的所有同步任务执行完成,主线程就会读取任务队列,看看还有哪些事件,那些对应的异步任务,结束等待状态,进入执行栈,开始执行
  • 主线程不断重复上面三步

完整的事件循环(参考简书)

微任务与宏任务

异步任务中分为微任务宏任务微任务组成微队列宏任务组成了宏队列微任务宏任务组成了任务队列

宏任务包括:
1. setTimeout
2. setInterval
3. setImmediate (Node独有)
4. requestAnimationFrame (浏览器独有)
5. I/O
6. UI rendering (浏览器独有)
微任务包括:
1. process.nextTick (Node独有)
2. Promise
3. Object.observe
4. MutationObserver

完整的事件循环

  1. 执行全局Script同步代码,这些同步代码有一些是同步语句,有一些是异步语句(比如setTimeout等);

  2. 全局Script代码执行完毕后,执行栈Stack会清空;

  3. 微队列中取出位于队首的回调任务,放入执行栈Stack中执行,执行完后微队列长度减1;

  4. 继续循环取出位于微队列的任务,放入执行栈Stack中执行,以此类推,直到直到把微任务执行完毕。注意,如果在执行微任务的过程中,又产生了微任务,那么会加入到微队列的末尾,也会在这个周期被调用执行;

  5. 微队列中的所有微任务都执行完毕,此时微队列为空队列,执行栈Stack也为空;

  6. 取出宏队列中的任务,放入执行栈Stack中执行;

  7. 执行完毕后,执行栈Stack为空;

  8. 重复第3-7个步骤;

作者:行动派巨人
链接:https://www.jianshu.com/p/62c7d633a879
来源:简书

简单题目

console.log("a")
setTimeout(()=>console.log("b"), 1000)
setTimeout(()=>console.log("c"), 500)
console.log("d")

// a d c b
console.log( "1" );
setTimeout(function() {
    console.log( "2" )
}, 0 );
setTimeout(function() {
    console.log( "3" )
}, 0 );
setTimeout(function() {
    console.log( "4" )
}, 0 );
console.log( "5" );

// 1  5  2  3  4

上一个台阶的题目参考资料中,关于异步专项练习

参考资料

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值