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')
上面的代码执行顺序为:
console.log('global begin')
被压入调用栈,执行完毕后弹出;- 函数声明或变量等声明不会被立即调用,会直接跳过;
- foo函数被压入调用栈;
- foo函数中,
console.log('foo task')
被压入调用栈,执行完毕后弹出; - foo函数中,bar函数被压入调用栈;
- bar函数中
console.log('bar task')
被压入调用栈,执行完毕后弹出; - bar函数中任务已执行完毕,bar函数弹出调用栈;
- foo函数中任务已执行完完毕,foo函数弹出调用栈;
console.log('global end')
被压入调用栈,执行完毕后弹出;- 所有任务执行完毕。
异步模式:不会等待这个任务结束才开始下一个任务,开启过后不管有没有执行完就立即往下执行下一个任务,异步任务完成后要完成的逻辑通过回调函数的方式定义,异步任务结束后会自动执行回调函数里的逻辑。
异步模式执行过程举例:
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')
上面代码执行顺序为:
console.log('global begin')
被压入调用栈,执行完毕后弹出;- 第一个setTimeout被压入调用栈,随后为其中的timer1函数开启一个1.8秒的倒计时器,倒计时器马上开始倒计时,随后第一个setTimeout弹出;
- 第二个setTimeout被压入调用栈,随后为其中的timer2函数开启一个1秒的倒计时器,倒计时器马上开始倒计时,随后第二个setTimeout弹出;
console.log('global end')
被压入调用栈,执行后弹出;- 主线程执行完毕,此时调用栈为空,执行暂时暂停了;
- timer2函数的倒计时先完成,timer2被放入消息队列第一位;
- timer1函数的倒计时随后完成,timer1被放入消息队列第二位;
- 一旦消息队列发生了变化,事件循环(Event loop)就会监听到,事件循环把消息队列的第一位(timer2)压入调用栈;
- timer2中
console.log('timer2 invoke')
被压入调用栈,执行完后弹出; - timer2为函数inner开启一个倒计时为1秒的倒计时器,然后timer2中任务执行完毕,弹出;
- timer1被压入调用栈,然后timer1中
console.log('timer1 invoke')
被压入调用栈,执行完后弹出,最后timer1弹出; - inner函数的倒计时结束后,inner函数被放入消息队列中,事件循环监听到后,把inner压入调用栈中;
console.log('inner invoke')
被压入调用栈,执行完毕后弹出;- 以上代码全部执行完毕;
相关概念:
调用栈:正在执行的工作表;
消息队列:待办的工作表;
事件循环:监听消息队列,一旦有了新任务,便将其压入调用栈中执行;
回调函数:异步任务完成后自动执行函数。
文章内容输出来源:拉勾大前端高薪训练营,以上文章中的内容根据老师讲课的语音和代码,结合自己的理解编辑完成。