ECMA规范JS
W3C规范浏览器(GUI)
一、前端开发中的同步异步编程
浏览器是多线程的,但是它只分配一个 “JS引擎线程” 用来渲染和解析JS代码,所以JS是单线程的!!
1、浏览器常用线程
- GUI渲染线程
- JS引擎线程
- 事件触发线程
- 定时器触发线程
- 异步HTTP请求线程
- WebWorker
- ...
2、JS中大部分代码都是“同步编程”,例如:循环...
- 千万不要写死循环,一旦遇到死循环,则JS引擎线程会一直被占用,
- 遇到程序抛出异常,后边的代码也不会再执行了(throw new Error:手动抛出异常)
- 我们可以基于( try{ } catch( err ){ //err就是我们捕获到的异常错误 } )进行异常捕获,这样不会影响后续代码的执行。
try {
console.log(a); //Uncaught ReferenceError: a is not defined
// throw new Error('xxx'); //手动抛出异常
} catch (err) {
// err:我们捕获到的异常错误
}
console.log('ok');
2、JS中也存在“同步编程”:
- 原理:依托于浏览器多线程,再次基于EventLoop事件循环机制处理的
- 异步宏任务(macrotask)\
- 定时器 setTimeout/setInterval\
- 事件绑定\
- Ajax/Fetch\
- ...
- 异步微任务(microtask)\
- requestAnimationFrame\
- Promise.then/catch/finally\
- async/await\
- queueMicrotask 基于这个方法可以创建一个异步微任务\
- IntersectionObserver\
- ...
二、EventLoop事件循环机制
- console.time('标识');
//...程序
console.timeEnd('标识');
作用:记录程序执行所需要的时间「预估值」:受电脑此时的性能影响,每一次册数的值都不尽相同。
setTimeout(() => {
console.log(1);
}, 20);
console.log(2);
setTimeout(() => {
console.log(3);
}, 10);
console.log(4);
console.time('AA');
for (let i = 0; i < 90000000; i++) {
// do soming
}
console.timeEnd('AA'); //=>AA: 79ms 左右
console.log(5);
setTimeout(() => {
console.log(6);
}, 8);
console.log(7);
setTimeout(() => {
console.log(8);
}, 15);
console.log(9);
- 定时器到时间后也不一定能执行(设定的事件是其最快执行的时间):如果此时主线程被占用,则必须等到主线程空闲下来,排在EventQueue中的定时器才可以执行!\
- 定时器等待时间不设置或者设置为0,不是立即执行,而是要等待浏览器的最快反应时间【谷歌:5-7ms】\
- 基于JS和定时器实现动画效果\
- 出现卡顿情况:到时间该走了,但是主线程被占用,它走不了\
- 我们设定的时间很难和“屏幕刷新率”保持一致\
- 屏幕刷新率:正常电脑屏幕刷新率60HZ(1秒刷新60次,大概16.66ms刷新一次)\
- 基于window.requestAnimationFrame 实现动画\
- 不需要我们设置时间,默认是按照电脑“屏幕刷新率对应的时间”进行运动的\
- 虽然也会出现“因主线程被占用,它无法立即执行”导致的卡顿,但是比定时器好,因为他是异步微任务,优先于异步宏任务执行!