setTimeout(function(){
console.log('定时器开始啦')
});
new Promise(function(resolve){
console.log('立刻执行for循环啦');
for(var i = 0; i < 10000; i++){
if(i == 99) resolve();
}
}).then(function(){
console.log('执行then函数啦');
});
console.log('代码执行结束');
// 立刻执行for循环啦
// 代码执行结束
// 执行then函数啦
// 定时器开始啦
// 若是没有执行对,请往下看
复制代码
为何
JS
是单线程的?做为浏览器脚本语言,JavaScript 的主要用途是与用户互动,以及操做 DOM 。这决定了它只能是单线程,不然会带来很复杂的同步问题。好比,假定 JavaScript 同时有两个线程,一个线程在某个DOM
节点上添加内容,另外一个线程删除了这个节点,这时浏览器应该以哪一个线程为准?javascript
单线程就意味着,全部任务都须要排队,前一个任务结束,才能执行后一个任务。若是前一个任务耗时很长,那么后一个任务就不得不一直等待 因而乎,
JS
设计者们把全部任务分红两类,同步和异步前端
WebAPI
时,就会触发异步操做,此时浏览器会单独开线程去处理这些异步任务。
WebAPI
是啥?浏览器事件、定时器、ajax
,这些操做不会阻塞 JS 的执行,JS 会跳过当前代码,执行后续代码java
如何知道主线程执行执行完毕?JS引擎存在 monitoring process 进程,会持续不断的检查主线程执行为空,一旦为空,就会去 callback queue 中检查是否有等待被调用的函数。node
console.log('1');
setTimeout(function() {
console.log('2');
}, 0);
console.log('3');
复制代码
执行结果以下:ajax
setTimeout
) ,浏览器新开定时器线程处理,执行完成后把回调函数存放到回调队列中。专业一点的说发: JS
引擎遇到异步任务后不会一直等待其返回结果,而是将这个任务挂起交給其余浏览器线程处理,本身继续执行主线程中的其余任务。这个异步任务执行完毕后,把结果返回给回调队列。被放入的代码不会被当即执行。而是当主线程全部同步任务执行完毕, monitoring process 进程就会把 "回调队列" 中的第一个回调代码放入主线程。而后主线程执行代码。如此反复setTimeout
不会阻塞同步代码,所以会首先打印3异步任务的执行优先级并不相同,它们被分为两类:微任务( micro task ) 和 宏任务( macro task ) 根据异步事件的类型,这些事件实际上会被派发对应的宏任务和微任务中,在当前主线程执行完毕后,promise
- 会先查看微任务中是否有事件存在,若是不存在,则再去找宏任务
- 若是存在,则会依次执行队列中的参数,直到微任务列表为空,让后去宏任务中一次读取事件到主线程中执行,如此反复 当前主线程执行完毕后,会首先处理微任务队列中的事件,让后再去读取宏任务队列的事件。在同一次事件循环中,微任务永远在宏任务以前执行。
script
、setTimeout
、setInterval
、UI交互事件
、I/O
process.nextTick
、Promise
、MutaionObserver
总体script自己就是一次宏任务浏览器
(function test() {
setTimeout(function() {console.log(4)}, 0);
new Promise(function (resolve, reject) {
console.log(1);
for( var i=0 ; i<10000 ; i++ ) {
i == 9999 && resolve();
}
console.log(2);
}).then(function() {
console.log(5);
});
console.log(3);
})()
1. setTimeout:宏任务:存入宏任务队列
2. Promise:函数自己是同步执行的( **Promise** 只有一个参数,默认new的时候就会同步执行), `.then` 是异步,所以依次打印1、2 `.then` 存入微任务中
3. 打印3( 第一次主线程执行完毕 )
4. 执行微任务中的回调函数:5, 让后执行宏任务中的 `setTimeout` 4
// 最终结果1,2,3,5,4
复制代码
console.log(1)
setTimeout(() => {
console.log(2)
new Promise(resolve => {
console.log(4)
resolve()
}).then(() => {
console.log(5)
})
})
new Promise(resolve => {
console.log(7)
resolve()
}).then(() => {
console.log(8)
})
setTimeout(() => {
console.log(9)
new Promise(resolve => {
console.log(11)
resolve()
}).then(() => {
console.log(12)
})
})
第一次同步执行:1,7,8
宏任务:setTimeout
2,4,5
9,11,12
复制代码
console.log('先执行这里');
setTimeout(() => {
console.log('再执行啦');
}, 0);
复制代码
- 在工做中,常常会遇到上述的代码,含义:只要主线程执行完成,就立马执行
setTimeout
中的回调代码- micro-task 优先于 macro-task 执行,在浏览器中高优先级的代码能够在
promise
或setTimeout(()=>{}, 0)
中执行- 认知尚浅,只能想到这些应用场景
这些概念是中级以上前端开发必知必会内容,其实实际的落地场景不多异步
- 为何
new Promise
第一个参数是同步执行的 ?学习Promise && 简易实现Promisenode
中的 JS 执行机制是什么样子的?从一道执行题,了解Node中JS执行机制
附:这篇博客 也许 想表达 浏览器环境中JS同步和异步的执行过程 (⊙﹏⊙)b函数