文章目录
事件循环(Event Loop)
javascript是一门单线程语言,单线程意味着会依次执行任务,当遇到耗时任务时,则会等待结果。
于是,javascript的设计者想到将那些耗时任务挂起,主线程继续执行。所以将任务分为同步任务与异步任务。
(1)所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)。
(2)主线程之外,还存在一个"任务队列"(task queue)。只要异步任务有了运行结果,就在"任务队列"之中放置一个事件。
(3)一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队列",看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。
(4)主线程不断重复上面的第三步
完整的事件循环(Event Loop)
1)检查(宏)任务(task)队列 取先入队的宏任务,在执行栈中执行
2)宏任务结束,检查微任务(micro task)队列,若存在微任务,将微任务加入到执行栈执行,直至清空微任务
3)渲染页面(如果需要的话)
4) 检查(宏)任务(task)队列,如果存在,重复上面三步,进入下一个事件循环;
若无,则等待;主线程会定时去检查。
宏任务:1. script
2. setTimeout/setInterval
3. UI rendering/UI事件
4. postMessage,MessageChannel
5. setImmediate,I/O(Node.js)
微任务:1. .then() (即async/await相当于期约在函数中的的应用)
6. MutaionObserver
7. Object.observe(已废弃;Proxy 对象替代)
8. process.nextTick(Node.js)
搞懂下面三题 就稳了
console.log(111);
let p1 = new Promise(resolve => {
setTimeout(() => {
console.log(222);
resolve(); // 注意resolve位置的区别
Promise.resolve().then(() => {
console.log(333);
});
}, 0);
});
p1.then(() => {
new Promise(resolve => {
console.log(444);
resolve();
}).then(()=>console.log(555))
}).then(()=>console.log(666))
console.log(777)
111->777->222->444->333->555->666
<script></script>是宏任务
1)先同步执行console.log(111);
2)遇到setTimeout,交给浏览器做计时,当满足条件时,会将其推入宏任务队列;
3)遇到p1,Promise状态未定,浏览器等待执行;
4)执行console.log(777);
5)检查微任务队列,无微任务,检查宏任务队列,执行下一个宏任务(task) setTimeout
6)执行console.log(222);
7)resolve();p1状态落定,执行.then(),处理程序prom1推入微任务队列;
8)接着遇到一个解决的期约,无需等待,直接执行.then(),将处理程序prom2推入任务队列;
9)宏任务执行完毕,检查微任务队列,执行prom1,console.log(444);
10)返回一个被Promise.resolve()包装的undefined。依次触发两个.then() Prom3 Prom4进入微任务队列;prom1执行完毕
11)prom2进入主执行栈执行 console.log(333);完毕
12)prom3、prom4依次进入主执行栈执行console.log(555);console.log(666);
console.log(111);
let p1 = new Promise(resolve => {
setTimeout(() => {
console.log(222);
Promise.resolve().then(() => {
console.log(333);
});
resolve(); // 注意resolve位置的区别
}, 0);
});
p1.then(() => {
new Promise(resolve => {
console.log(444);
resolve();
}).then(()=>console.log(555))
}).then(()=>console.log(666))
console.log(777)
111->777->222->333->444->555->666
async function async1() {
console.log('async1 start');
await async2();
console.log('async1 end');
}
async function async2() {
Promise.resolve().then(() => console.log(2222));
setTimeout(console.log,0,'async2');
}
console.log('script start');
setTimeout(function() {
console.log('setTimeout');
}, 0);
async1();
// setTimeout(console.log,0,'1111')
new Promise(function(resolve) {
console.log('promise1');
resolve();
}).then(function() {
console.log('promise2');
});
console.log('script end');
script start->async1 start->promise1->script end->222->async1 end->promise2->setTimeout->async2
const myPromise = Promise.resolve(Promise.resolve('666!'));
function funcOne() {
myPromise.then(res => res).then(res => console.log(res));
console.log('111');
}
async function funcTwo() {
console.log('222');
const res = await myPromise;
console.log('444');
console.log(await res);
console.log('777');
}
async function funcThree() {
console.log(await myPromise.then(()=> console.log('555')).then(()=>console.log('888')));
}
funcOne();
funcTwo();
funcThree();
console.log('333');
111 --> 222-->333-> 444-->555-->666!-->666!-->777-->888
async function async1() {
await async2()
console.log('2')
}
function async2() {
console.log('3')
return Promise.resolve().then(()=>{
console.log('4')
});
}
async1()
new Promise(resolve => {
console.log('6')
resolve()
})
.then(function() {
console.log('7')
})
.then(function() {
console.log('8')
})
.then(function() {
console.log('9')
})
3 6 4 7 2 8 9
注意: 和上面的区别 有 return 和 没有return
async function async1() {
await async2()
console.log('2')
}
function async2() {
console.log('3')
Promise.resolve().then(()=>{
console.log('4')
});
}
async1()
new Promise(resolve => {
console.log('6')
resolve()
})
.then(function() {
console.log('7')
})
.then(function() {
console.log('8')
})
.then(function() {
console.log('9')
})
3 6 4 2 7 8 9
尽量不要在 async 标识的函数内部返回 Promise ,会导致运行时机的变化(目前还不知道 如何解释)
async function async1() {
return Promise.resolve(2)
}
async1().then(()=>{
console.log(1)
})
new Promise(resolve => {
console.log('6')
resolve()
})
.then(function() {
console.log('7')
})
.then(function() {
console.log('8')
})
.then(function() {
console.log('9')
})
.then(function() {
console.log('10')
})
6 7 8 1 9 10