JavaScript异步编程(一):同异步执行原理过程

JavaScript(以下简称js)是单线程语言,啥叫单线程?

一本正经的解释就是:在js代码执行环境中,执行代码的线程只有一个,因为设计初衷就是为了操作DOM元素,假设js是多线程语言,那么如果两个线程任务同时操作一个DOM元素,一个修改一个删除,浏览器将不知道以哪个为准。

假想解释就是:一辆车在路上跑,只能由一个司机开。如果多个司机开,一个司机把方向盘往左扭一个往右扭,一个猛的踩油门一个猛的踩刹车,那么这个车是不是要完犊子了?

既然js是单线程语言,所以有多个任务时(先不考虑异步),只能排队一个个按顺序执行。

优点:安全简单;缺点:一个任务耗时阻塞,后面的任务都会只能在等待,无法执行。

为解决异步请求、文件加载等耗时长的任务阻塞后边任务的问题,js执行模式分为同步模式和异步模式。

同步模式:一个个任务从上到下,按序执行,与代码编写顺序一致。

同步模式执行过程举例:

console.log('global begin')
function bar () {
  console.log('bar task')
}
function foo () {
  console.log('foo task')
  bar()
}
foo()
console.log('global end')

上面的代码执行顺序为:

  1. console.log('global begin') 被压入调用栈,执行完毕后弹出;
  2. 函数声明或变量等声明不会被立即调用,会直接跳过;
  3. foo函数被压入调用栈;
  4. foo函数中, console.log('foo task') 被压入调用栈,执行完毕后弹出;
  5. foo函数中,bar函数被压入调用栈;
  6. bar函数中 console.log('bar task') 被压入调用栈,执行完毕后弹出;
  7. bar函数中任务已执行完毕,bar函数弹出调用栈;
  8. foo函数中任务已执行完完毕,foo函数弹出调用栈;
  9. console.log('global end') 被压入调用栈,执行完毕后弹出;
  10. 所有任务执行完毕。

异步模式:不会等待这个任务结束才开始下一个任务,开启过后不管有没有执行完就立即往下执行下一个任务,异步任务完成后要完成的逻辑通过回调函数的方式定义,异步任务结束后会自动执行回调函数里的逻辑。

异步模式执行过程举例:

console.log('global begin')

setTimeout(function timer1 () {
  console.log('timer1 invoke')
}, 1800)

setTimeout(function timer2 () {
  console.log('timer2 invoke')

  setTimeout(function inner () {
    console.log('inner invoke')
  }, 1000)
}, 1000)

console.log('global end')

上面代码执行顺序为:

  1. console.log('global begin') 被压入调用栈,执行完毕后弹出;
  2. 第一个setTimeout被压入调用栈,随后为其中的timer1函数开启一个1.8秒的倒计时器,倒计时器马上开始倒计时,随后第一个setTimeout弹出;
  3. 第二个setTimeout被压入调用栈,随后为其中的timer2函数开启一个1秒的倒计时器,倒计时器马上开始倒计时,随后第二个setTimeout弹出;
  4. console.log('global end') 被压入调用栈,执行后弹出;
  5. 主线程执行完毕,此时调用栈为空,执行暂时暂停了;
  6. timer2函数的倒计时先完成,timer2被放入消息队列第一位;
  7. timer1函数的倒计时随后完成,timer1被放入消息队列第二位;
  8. 一旦消息队列发生了变化,事件循环(Event loop)就会监听到,事件循环把消息队列的第一位(timer2)压入调用栈;
  9. timer2中console.log('timer2 invoke') 被压入调用栈,执行完后弹出;
  10. timer2为函数inner开启一个倒计时为1秒的倒计时器,然后timer2中任务执行完毕,弹出;
  11. timer1被压入调用栈,然后timer1中 console.log('timer1 invoke') 被压入调用栈,执行完后弹出,最后timer1弹出;
  12. inner函数的倒计时结束后,inner函数被放入消息队列中,事件循环监听到后,把inner压入调用栈中;
  13. console.log('inner invoke') 被压入调用栈,执行完毕后弹出;
  14. 以上代码全部执行完毕;

相关概念:
调用栈:正在执行的工作表;
消息队列:待办的工作表;
事件循环:监听消息队列,一旦有了新任务,便将其压入调用栈中执行;
回调函数:异步任务完成后自动执行函数。

文章内容输出来源:拉勾大前端高薪训练营,以上文章中的内容根据老师讲课的语音和代码,结合自己的理解编辑完成。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值