虽然javascript是单线程的,但是可以创建多个子线程去执行一些操作(DOM操作除外),javascript的事件循环机制来调度事件执行。
function a1() {console.log('a1') setTimeout(function(){console.log('a2')},6000)} function b1(){ console.log('b1') setTimeout(function(){console.log('b2')},3000)} function c1(){console.log('c1')} a1() b1() c1()
上面的代码使用setTimeout模拟异步操作(因为有延时)
整个代码执行流程:
首先是将代码全部加载进内存并“逐行扫描”,发现前面3个都是函数声明,直到出现a1函数的调用。
读到a1()方法:
console.log('a1'):同步任务=> 输出a1
setTimeout(function(){console.log('a2')},6000):异步任务,不立即执行,丢到宏任务队列等待,这个任务队列专门是用来给异步任务排队的
开始读b1()方法(和a1()同理):
console.log('b1'):同步任务=> 输出b1
setTimeout(function(){console.log('b2')},3000):异步任务,不立即执行,丢到宏任务队列等待,这个时候任务队列里面已经有两个异步在等待执行了。
开始读c1()方法:
console.log('c1'):同步任务=> 输出c1
以上三个同步任务执行完毕,而且整个当前上下文环境(当前是全局作用域环境)的同步任务都执行完毕了,接着,会进入任务队列调取异步任务,将异步任务放入执行栈进行任务执行。
这时需要注意的是,两个异步任务(setTimeout)都有一个等待一定时间之后再执行的设定,第一个等待3秒,第二个等待6秒。也就是说,当前上下文环境下,全部同步任务完成之后,前往任务队列(这里等待的都是异步任务),发现第一个异步任务,我们称作A,要等6秒之后再拿到执行栈去执行,第二个异步,我们称作B,要等3秒之后拿去执行。虽然A在任务队列里排队在B的前面,但是B要先于A被拿到调用栈,所以执行顺序就变成了:先console.log('b2')再console.log('a2').最终的输出顺序是
a1 b1 c1 b2 a2