进程与线程
浏览器打开一个页面就相当于开一个“进程”(程序),在程序中,我们会同时做很多事情,每一个事情都有一个“线程”去处理,所以一个进程中可能会包含多个线程!!
浏览器是多线程的:
* GUI渲染线程:渲染页面 & 绘制图形
* JS引擎线程:渲染和解析JS代码
* 事件触发线程:监听事件触发
* 定时触发器线程:给定时器计时的
* 异步HTTP请求线程:基于HTTP网络从服务器端获取资源和信息
* WebWorker
* ...
JS是单线程的(浏览器只分配一个线程“JS引擎线程”用来渲染和解析JS代码)
* + JS中的大部分操作都是“同步”
* + 有少部分操作,结合EventLoop机制,实现了“异步”处理
* 「异步宏任务:macrotask」
* + 定时器:setTimeout/setInterval
* + 事件绑定/队列
* + 数据请求:Ajax/Fetch
* + MessageChannel
* + setImmediate「NODE」
* + ...
* 「异步微任务:microtask」
* + Promise.then/catch/finally
* + async/awai
* + queueMicrotask
* + MutationObserver
* + IntersectionObserver
* + requestAnimationFrame
* + process.nextTick「NODE」
* + ...
做题秘诀
@1 执行循序 先处理主线任务 其次微任务 然后才是宏任务
@2 从上往下看碰到异步就考虑 定时器/then
- 如果是宏任务就放到Webapi 等到时间到了或者触发了在加到Eventqueue的队列中等待主线任务空闲再执行
- 如果是微任务比如then 如果是promise状态确定了就加到Eventqueue的队列中等待执行
- async function a(){}
- await a();
- @1 先把a()函数执行
- 把 await a()下面的代码存到Eventqueue的队列中等待执行
例题
setTimeout(() => {
console.log(1);
}, 20);
console.log(2);
setTimeout(() => {
console.log(3);
}, 10);
console.log(4);
for (let i = 0; i < 90000000; i++) {}
console.log(5);
setTimeout(() => {
console.log(6);
}, 8);
console.log(7);
setTimeout(() => {
console.log(8);
}, 15);
console.log(9);
//=>2 4 5 7 9 3 1 6 8
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
*/
let body = document.body;
body.addEventListener('click', function () {
Promise.resolve().then(() => {
console.log(1);
});
console.log(2);
});
body.addEventListener('click', function () {
Promise.resolve().then(() => {
console.log(3);
});
console.log(4);
});
/*
2
1
4
3
*/
console.log('start');
let intervalId;
Promise.resolve().then(() => {
console.log('p1');
}).then(() => {
console.log('p2');
});
setTimeout(() => {
Promise.resolve().then(() => {
console.log('p3');
}).then(() => {
console.log('p4');
});
intervalId = setInterval(() => {
console.log('interval');
}, 3000);
console.log('timeout1');
}, 0);
/*
start
p1
p2
timeout1
p3
p4
interval 循环没三秒答应1次
*/
setTimeout(() => {
console.log('a');
});
Promise.resolve().then(() => {
console.log('b');
}).then(() => {
return Promise.resolve('c').then(data => {
setTimeout(() => {
console.log('d')
});
console.log('f');
return data;
});
}).then(data => {
console.log(data);
});
/*
b
f
c
a
d
*/
function func1() {
console.log('func1 start');
return new Promise(resolve => {
resolve('OK');
});
}
function func2() {
console.log('func2 start');
return new Promise(resolve => {
setTimeout(() => {
resolve('OK');
}, 10);
});
}
console.log(1);
setTimeout(async () => {
console.log(2);
await func1();
console.log(3);
}, 20);
for (let i = 0; i < 90000000; i++) {} //循环大约要进行80MS左右
console.log(4);
func1().then(result => {
console.log(5);
});
func2().then(result => {
console.log(6);
});
setTimeout(() => {
console.log(7);
}, 0);
console.log(8);
/*
1
4
func1 start
func2 start
8
5
2
func1 start
3
7
6
*/