单线程
JavaScript是单线程。
JavaScript被定义成单线程,是和它起初功能有关,主要用于操作DOM。比如我们不可能同时删除一个元素,同时给这个元素添加子元素。
所谓单线程,是指JS执行环境中执行代码的线程只有一个。线程下执行代码过程中,会一步一步执行代码,但是如果碰到耗时任务,如果一直等待此行代码执行完毕,肯定会出现“假死”情况。因此,在代码执行过程中,我们能否遇到耗时代码交给相应的API去执行,而不影响我们的主线程?因此在程序运行中,出现了两种模式:同步模式和异步模式。
代码运行的模式是指:运行环境提供的API是以同步或异步模式的方式去工作。
同步模式
在同步模式下,首先当前工作的所有代码会被以匿名函数的方式压入调用栈(程序工作表),在执行时,遇到函数时,会依次将函数压入调用栈,当函数调用完毕,弹出调用栈。直至当前工作的代码执行完毕。
同步模式虽然简单,但是如果遇到耗时操作,就会出现页面卡顿,给用户留下特别差的体验。如果仅仅有同步模式,单线程的JS无法同时处理大量的耗时任务。因此异步模式横空出世
异步模式
相比较同步模式,异步模式不会等待这个任务结束才开始下一个任务,对于耗时任务,开启之后立即执行下一个任务,后续逻辑一般会通过回调函数的方式去定义,在内部耗时任务完成后,就会自动执行我们传入的回调函数。
console.log("program begin")
setTimeout(function async1() {
console.log("我是第一个异步任务-asyncCallback1")
}, 3000)
setTimeout(function async2() {
console.log("我是第二个异步任务-asyncCallback2")
setTimeout(function async3() {
console.log("我是第三个异步任务-asyncCallback3")
}, 1000)
console.log("我是第二个异步任务-我还有其他操作")
}, 1000)
console.log("program end")
Event Lop 是同时监听调用栈和消息队列。
下图所示是上述程序执行过程中的大概流程,具体流程就不再唠了
看到这个里有没有大佬会说,JS不是单线程吗?
可以负责任的说,JS确实是单线程。但是浏览器不是单线程,浏览器所提供的的有些API是异步的,这些异步API会有其他线程去执行。执行JS代码的线程永远是单线程。
回调函数
那异步模式是怎样实现的?
回调函数是所有异步方案的根基。
回调函数在我们编程中随处可见,比如我们需要向服务器请求数据,但是我们不知道何时才能拿到数据,去做页面逻辑?那我们(调用者)通过ajax(执行者)去请求数据,然后将拿到数据后的逻辑写到一个函数传递给执行者(ajax),成功拿到数据后,调用此函数,去做页面逻辑。
比如我们使用setimeout模仿ajax请求
function ajax(callback){
setTimeout(()=>{
callback();
}, 1000)
}
ajax(()=>{
console.log("我已经拿到数据了,我要一系列操作了")
})
参考资料