19.1 进程和线程
161.PNG 162.PNG 163.PNG19.2 浏览器中的Javascript线程
浏览器的每一个tab页面就会开启一个新的进程,这个进程里面有包括执行js代码的单线程,也有执行其他操作的线程。比如网络请求,定时器什么的都是其他线程执行的。js单线程就是指同一时刻只能执行一段,一行js代码。不能同时执行不同行的js代码。
164.PNG19.3 浏览器的事件循环
165.PNG 167.PNGconsole.log("script start")
// 业务代码
setTimeout(function() {
}, 1000)
//定时器函数,是全局函数,这个函数本身不是异步操作,是同步,像foo函数被调用一样
//是同步调用,但是setTimeout需要传进去一个回调函数,一般说的异步函数,是指的是传进去的这个函数
/*
传进去的这个函数不是立即执行,1s之后执行,
浏览器的其他线程帮助我们开始计时操作,
js线程是单线程的,如果计时的话,其他就不能操作了。
这个回调函数会保存到js的其他线程,
js线程不用管你,开始执行其他行的代码
等到1s中的时候,开始执行回调函数
这个时候是有一个队列的,浏览器本身维护着一个队列queue(事件队列)
队列是一种数据结构,是先进先出。跟栈结构相反,
队列默认没有东西,当计时器达到1s后,会将回调函数放到队列里面
当js引擎发现队列有东西,就会从队列里面取出我们要执行的回调函数
开始做执行
网络请求,settimeout,dom操作都可以依次加到队列里面
加到队列后,从队列里面挨个取出函数并且调用,在js里面执行,
真正执行的位置还是js的线程。
一般情况下,
js线程,浏览器的其他线程,浏览器维护的事件队列
这三个东西形成了一个闭环。
回调函数之类的放到浏览器的其他地方做一些耗时操作,
耗时操作结束之后,会将回调函数加入到队列里面
js线程再从队列里面获取到要执行的回调函数,开始进行执行
这个闭环,就被我们成为事件循环
无论是网络请求,还是settimeout都是由js线程发起的,
然后再js的其他线程做耗时操作,并且加到队列里面,最后再返回js线程执行
*/
console.log("后续代码~")
console.log("script end")
19.4 宏任务和微任务
166.PNGsetTimeout(() => {
console.log("setTimeout")
}, 1000)
//setTimeout是先放到浏览器的其他线程,等到时间之后,加入到队列里面
queueMicrotask(() => {
console.log("queueMicrotask")
})
//queueMicrotask是直接加入到队列里面,并且和settimeout加入的是不同的队列
/*
宏任务队列(macrotask queue):ajax、setTimeout、setInterval、DOM监听、UI Rendering等
微任务队列(microtask queue):Promise的then回调、 Mutation Observer API、queueMicrotask()等
规范:
当两个队列里面都有任务的时候,
在执行任何的宏任务之前,都需要先保证微任务队列已经被清空
*/
Promise.resolve().then(() => {
console.log("Promise then")
})
//以下是main script 全局代码,优先执行
function foo() {
console.log("foo")
}
function bar() {
console.log("bar")
foo()
}
bar()
console.log("其他代码")
19.5 面试题
1.面试题1
setTimeout(function () {
console.log("setTimeout1");
new Promise(function (resolve) {
resolve();
}).then(function () {
new Promise(function (resolve) {
resolve();
}).then(function () {
console.log("then4");
});
console.log("then2");
});
});
new Promise(function (resolve) {
console.log("promise1");
resolve();
}).then(function () {
console.log("then1");
});
setTimeout(function () {
console.log("setTimeout2");
});
console.log(2);
queueMicrotask(() => {
console.log("queueMicrotask1")
});
new Promise(function (resolve) {
resolve();
}).then(function () {
console.log("then3");
});
/*
new Promise((resolve, reject) => {
...
})
在这里,
(resolve, reject) => {
...
}
这个回调函数是不会被加进任务队列的,是会直接执行的
相当于里面代码...在main script里面执行的
后面的then里面的回调是会被加入进微任务队列的
等到下面单线程的代码运行完之后才能够执行
*/
/*
"promise1"
2
then1
queueMicrotask1
then3
setTimeout1
"then2"
then4
setTimeout2
*/
/*
执行完微任务之后,执行
setTimeout(function () {
console.log("setTimeout1");
new Promise(function (resolve) {
resolve();
}).then(function () {
new Promise(function (resolve) {
resolve();
}).then(function () {
console.log("then4");
});
console.log("then2");
});
});
先输出"setTimeout1",之后,直接执行function (resolve) {
resolve();
}
然后,把这个回调函数
function () {
new Promise(function (resolve) {
resolve();
}).then(function () {
console.log("then4");
});
console.log("then2");
}
加入到微任务中
这时候,就剩下了微任务中的这个,还有宏任务中的setTimeout2
在执行宏任务之前,要保证微任务里面没有东西,
所以需要先执行上面的回调
执行resolve(),然后再把then4加入到微任务
然后再继续往后,执行then2
接下来再执行then4,后面执行settimeout2
*/
[图片上传失败...(image-f5de6d-1664549933477)]
2.面试题2
async function bar() {
console.log("22222")
return new Promise((resolve) => {
resolve()
})
}
async function foo() {
console.log("111111")
await bar()
console.log("33333")
}
foo()
console.log("444444")
/*
111111
test2.html:15 22222
test2.html:30 444444
test2.html:26 33333
*/
async function async1 () {
console.log('async1 start')
await async2();
console.log('async1 end')
}
async function async2 () {
console.log('async2')
}
console.log('script start')
setTimeout(function () {
console.log('setTimeout')
}, 0)
async1();
new Promise (function (resolve) {
console.log('promise1')
resolve();
}).then (function () {
console.log('promise2')
})
console.log('script end')
/*
script start
'async1 start'
async2
'promise1'
'script end
async1 end
promise2
setTimeout
*/
3.面试题3
Promise.resolve().then(() => {
console.log(0);
// 1.直接return一个值 相当于resolve(4)
return 4
}).then((res) => {
console.log(res)
})
Promise.resolve().then(() => {
console.log(1);
}).then(() => {
console.log(2);
}).then(() => {
console.log(3);
}).then(() => {
console.log(5);
}).then(() =>{
console.log(6);
})
/*
0
1
4
2
3
5
6
*/
Promise.resolve().then(() => {
console.log(0);
// 2.return thenable的值
return {
then: function(resolve, reject){
resolve(4)
}
}
//,本来是直接resolve(4)的,但是因为是thenable,执行这个then函数被放到了下一次的为任务中
}).then((res) => {
console.log(res)
})
Promise.resolve().then(() => {
console.log(1);
}).then(() => {
console.log(2);
}).then(() => {
console.log(3);
}).then(() => {
console.log(5);
}).then(() =>{
console.log(6);
})
/*
0
1
2
4
3
5
6
*/
Promise.resolve().then(() => {
console.log(0);
// 3.return Promise
// 不是普通的值, 多加一次微任务
// Promise.resolve(4), 多加一次微任务
// 一共多加两次微任务
return Promise.resolve(4)
}).then((res) => {
console.log(res)
})
Promise.resolve().then(() => {
console.log(1);
}).then(() => {
console.log(2);
}).then(() => {
console.log(3);
}).then(() => {
console.log(5);
}).then(() =>{
console.log(6);
})
/*
0
1
2
3
4
5
6
*/
19.6 Node中的事件循环
169.PNG 170.PNG19.7 Node事件循环的阶段
171.PNG 172.PNG173.PNG 174.PNG
网友评论