js代码是单线程的,同一时间不可能同时运行两个js代码,js中的异步不是js的异步而是浏览器的异步。一些i/o操作 定时器额计时和事件监听等都是由浏览器提供的其他线程来完成的。
执行过程:
1 所有的同步任务都在主线程上执行,形成一个执行栈。
2 主线程之外,还存在一个‘任务队列’,只要异步任务有了运行结果,就在任务队列之中放置一个事件。
3 一旦"执行栈"中的所有同步任务执行完毕,系统就会读取‘任务队列’,看看里面有哪些事件。那些对应的异步任务。于是结束等待状态,进入执行栈,开始执行。
4 主线程不断重复上面的第三步
事件队列会将处理事件的优先级进行排序,在通过执行栈来执行事件
其实同步和异步,无论如何,做事情的时候都是只有一条流水线(单线程)
浏览器线程
浏览器异步:
事件监听-addEventListener
定时器-setTimeout、setInterval
ajax-异步请求
GUI渲染也是在引擎线程中执行的,脚本中执行对界面进行更新操作,如添加节点,删除节点或改变节点的外观等更新并不会立即体现出来,这些操作将保存在一个队列中,待js引擎空闲时才有机会渲染出来。
异步操作,触发来源于js代码,执行在浏览器的其他线程,回调函数又加入js队列。
宏任务和微任务
-
同步和异步任务分别进入不同的执行“场所”,同步的进入主线程,异步的进入Event Table 并注册函数
-
当指定的事情完成时,Event Table 会将这个函数移入Event Queue
-
主线程内的任务执行完毕为空,会去Event Queue读取对应的函数,进入主线程执行
-
上述过程会不断重复,也就是常说的Event Loop(事件循环)
-
setTimeout这个函数,是经过指定时间后,把要执行的任务加入到Event Queue中,又因为是单线程任务要一个个执行,如果前面的任务需要的时间太长,那么只能等着。
广义的同步任务和异步任务
-
宏任务:包括整体代码 script,setTimeout,setIntervcal
-
微任务:Promise,process.nextTick
不同类型的任务会进入对应的Event Queue,比如setTimeout和setInterval会进入相同的Event Queue
事件循环的顺序,决定js代码的执行顺序。进入整体代码后,开始第一次循环。接着执行所有的微任务
然后再次从宏任务开始,找到其中一个任务队列执行完毕,在执行所有的微任务
js执行顺序
第一步:检查语法错误
第二步:预编译
var a=1; console.log(a);//1 //但实际上拆分成了两步,真正执行时这样的 var a; a=1; console.log(a);//变量声明提升
console.log(a);//undefined var a=1; 实际上执行的代码://变量声明提升,赋值并不会提升 var a; console.log(a); a=1;
预编译步骤:
具体的步骤:
0:函数的在运行的瞬间,生成一个活动对象(Active Object)就是所谓的AO
1:分析参数
1-1:函数接收参数,添加到AO的属性上面,值全部都是undefine,如AO.age=undefine
1-2:接收实参,形成AO对应的属性值
2:分析变量声明,如var age,
2-1:如果AO上还没有age属性,则添加AO 属性,值是undefine
2-2:如果AO 上面已经有了age属性,则不做任何操作。
3:分析函数的声明,如果funcion foo(){},
3-1: 则把函数赋给AO.fooo,如果数据属性已经存在,则要被现在的新的值覆盖
最后开始按优先级赋值
function fn(a){ var a=10; console.log(a); } fn(11);//10 fn(11)实际执行代码: a=11; var a=10; console.log(a);
demo2:
function fn(a){ console.log(a); var a=11; function a(){console.log('我优先级最高')} } fn(10);//[funciton:a] //函数声明的优先级最高 实际执行代码:
a=10; function a(){console.log('我优先级最高')} console.log(a);var a=11;
demo3:
function fn(a){: var a=11; function a(){console.log('我优先级最高')} console.log(a); } fn(10);//11
// 注意,与上一段代码不同的是,在a被打印出来之前,
// a 经历的成长是:
// 1.形参a传过来,AO对象创造属性 AO.a = undefinded
// 2.结合实参,AO.a = 10
// 3.变量声明,它本应该在AO对象内创造 a 属性并赋值为undefinded,但a属性已经存在,不做改动
// 4.遇到函数声明,a 被赋值为一个函数体,即由 a = 10 变为 a = Function
// 5.开始执行函数,遇到 var a = 11 这一句,a 被赋值为 11,即 a = Function 变为 a = 11
function fn(a){ console.log(a); var a=11; console.log(a); function a(){console.log('我优先级最高')} } fn(10);//[funciton:a] 11
参考1:https://www.cnblogs.com/wangziye/p/9566454.html
参考2:https://www.jianshu.com/p/2a5954b78ff5
参考3:https://blog.csdn.net/guolinengineer/java/article/details/84984498