引入
在理解promise之前应当先理解一下基础部分,分为计算机原理,浏览器原理以及JS执行原理
计算机原理
进程
定义:进程是CPU资源分配的最小单位 —— 独立的资源
线程
定义:线程是CPU调度的最小单位 —— 共享资源
相关问题
- chrome新开一个窗口,tab页是进程还是线程? 答:进程
- 进程间如何通信(窗口间如何通信)? 答:存储(localStorage,sessionStorage,cookie)
- 各种存储之间的区别?
- 浏览器原理(中高级管理居多) 浏览器在一个进程中有多个线程
浏览器原理
GUI渲染引擎
- 解析html,css,构建dom树 => 布局 => 绘制
- 与js引擎互斥,当执行JS引擎线程时,GUI会是pending,当任务队列空闲时才会继续执行GUI
JS引擎线程
- 处理JS,解析执行脚本
- 分配、处理、执行待执行的的事件,event队列
- 阻塞GUI渲染
定时器触发引擎
- setTimeout,setInterval
- 接收js引擎分配的定时器任务,并计数
- 处理完成后交给事件触发线程触发
异步HTTP请求线程
- 异步执行请求类处理,promise/ajax等
- 接收JS引擎分配异步HTTP请求
- 监听回调,交给事件触发线程触发
事件触发引擎
- 接收来源:定时器,异步,用户操作
- 将回调过来的事件依次接入到任务队列的队尾,还给引擎
JS执行原理
分配内存
执行栈
面试题1:js堆栈的执行顺序,堆栈溢出(爆栈) => 性能优化
面试题2:数组操作返回值问题 splice split... promise.all promise.race
任务队列
宏任务:macro:script,setTimeout,setInterval,I/O
微任务:new promise{}.then()
有微则微,无微则宏 宏任务永远在微任务之前
1. 深入理解promise
promise规范
promise是一个有then方法的对象或者函数,promise有三种状态
状态
- pending: 初始状态 - 可改变
- fulfilled:最终状态 - 不可改变
- rejected:最终状态 - 不可改变
状态变化
- pending -> reslove(value) -> fulfilled
- pending -> reject(reason) -> rejected
then方法
- 参数:
onFulfilled
和onRejected
(两个参数必须是函数,如果不是函数,应该被忽略) onFulfilled
和onReject
是微任务 (js是单线程,分为了同步任务和异步任务,而异步任务中也有优先级,微任务即表示优先级高的)- then方法可以调用多次,用数组来存放多个onFulfilled的回调和onRejected的回调
- then方法的返回值是一个新的promise
将onFulfilled或onrejected的返回结果为x,通过
resolvePromise
来解析promisethis.resolvePromise(promise2, x, resolve, reject);
2.一步步实现一个promise
- class对象并定义三种状态
- 在
constructor
中设置初始状态以及定义value和reason - 实现resolve和reject方法,在状态为pending时改变状态
- 在
constructor
中传一个入参fn,fn接收resolve和reject,若报错则通过reject抛出去 - 实现then方法,接收两个参数:
then(onFulfilled, onRejected) {}
- 检查处理then参数,判断onFulfilled和onRejected是否为函数,若不是函数,则返回value或reason
- 定义返回值(promise2)并根据当前promise的状态调用不同的函数
- 设置一个状态的监听机制, 当状态变成fulfilled或者rejected后, 再去执行callback
- 新建两个数组, 来分别存储成功和失败的回调, 调用then的时候, 如果还是pending就存入数组
- 实现getter和setter函数,在给status赋值后, 下面再加一行forEach
- 当 onFulfilled 或者 onRejected 抛出异常 e ,则 promise2 拒绝执行,并返回拒因 e。(这样的话, 我们就需要手动catch代码,遇到报错就reject)
- 当onFulfilled 或者 onRejected 返回一个值 x ,则运行
resolvePromise
方法。将realOnFulfilled(this.value)
赋值给x,this.resolvePromise(promise2, x, resolve, reject);
- 实现resolvePromise方法
- onFulfilled 和 onRejected 是微任务,使用queueMicrotask包裹执行函数
- 实现catch方法
3.Iterator,Generator和async的理解
Interator迭代器
- 是一种的特殊的对象,每一个迭代器对象都有一个next方法,
- 每次调用都会返回一个劫夺对象,结果对象中包含两个值:
value: 当前属性的值;
done: 判断是否遍历结束
Generator生成器
- 生成器时一种返回迭代器的函数,函数中会用到新的关键字
yield
,使用function*来创建
function* generator() {
const list = [1, 2, 3];
for (let i of list) {
yield i;
}
}
let g = generator();
console.log(g.next()); // {value: 1, done: false}
console.log(g.next()); // {value: 2, done: false}
console.log(g.next()); // {value: 3, done: false}
console.log(g.next()); // {value: undefined, done: true}
- 注意
- 每当执行完一条yield语句后函数就会自动停止执行, 直到再次调用next();
- yield关键字只可在生成器内部使用,在其他地方使用会导致程序抛出错误;
- 可以通过函数表达式来创建生成器, 但是不能使用箭头函数
let generator = function *(){}
4.面试中可能会遇到的问题
- 为什么promise resolve了一个value, 最后输出的value值确是undefined
const test = new MPromise((resolve, reject) => {
setTimeout(() => {
resolve(111);
}, 1000);
}).then((value) => {
console.log('then');
});
setTimeout(() => {
console.log(test);
}, 3000)
答:因为在.then中没有return则相当于return undefined,所以value是undefined
- 为什么在catch的回调里, 打印promise, 显示状态是pending
const test = new MPromise((resolve, reject) => {
setTimeout(() => {
reject(111);
}, 1000);
}).catch((reason) => {
console.log('报错' + reason);
console.log(test)
});
setTimeout(() => {
console.log(test);
}, 3000)
答:catch函数会返回一个新的名为test的promise函数,在catch中还没有执行完成,所以是pending