promise的理解以及手写promsie

引入

在理解promise之前应当先理解一下基础部分,分为计算机原理,浏览器原理以及JS执行原理

计算机原理

进程

定义:进程是CPU资源分配的最小单位 —— 独立的资源

线程

定义:线程是CPU调度的最小单位 —— 共享资源

相关问题

  1. chrome新开一个窗口,tab页是进程还是线程? 答:进程
  2. 进程间如何通信(窗口间如何通信)? 答:存储(localStorage,sessionStorage,cookie)
  3. 各种存储之间的区别?
  4. 浏览器原理(中高级管理居多) 浏览器在一个进程中有多个线程

浏览器原理

GUI渲染引擎

  1. 解析html,css,构建dom树 => 布局 => 绘制
  2. 与js引擎互斥,当执行JS引擎线程时,GUI会是pending,当任务队列空闲时才会继续执行GUI

JS引擎线程

  1. 处理JS,解析执行脚本
  2. 分配、处理、执行待执行的的事件,event队列
  3. 阻塞GUI渲染

定时器触发引擎

  1. setTimeout,setInterval
  2. 接收js引擎分配的定时器任务,并计数
  3. 处理完成后交给事件触发线程触发

异步HTTP请求线程

  1. 异步执行请求类处理,promise/ajax等
  2. 接收JS引擎分配异步HTTP请求
  3. 监听回调,交给事件触发线程触发

事件触发引擎

  1. 接收来源:定时器,异步,用户操作
  2. 将回调过来的事件依次接入到任务队列的队尾,还给引擎

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有三种状态

状态
  1. pending: 初始状态 - 可改变
  2. fulfilled:最终状态 - 不可改变
  3. rejected:最终状态 - 不可改变
状态变化
  1. pending -> reslove(value) -> fulfilled
  2. pending -> reject(reason) -> rejected
then方法
  1. 参数:onFulfilledonRejected(两个参数必须是函数,如果不是函数,应该被忽略)
  2. onFulfilledonReject是微任务 (js是单线程,分为了同步任务和异步任务,而异步任务中也有优先级,微任务即表示优先级高的)
  3. then方法可以调用多次,用数组来存放多个onFulfilled的回调和onRejected的回调
  4. then方法的返回值是一个新的promise 将onFulfilled或onrejected的返回结果为x,通过resolvePromise来解析promise this.resolvePromise(promise2, x, resolve, reject);

2.一步步实现一个promise

  1. class对象并定义三种状态
  2. constructor中设置初始状态以及定义value和reason
  3. 实现resolve和reject方法,在状态为pending时改变状态
  4. constructor中传一个入参fn,fn接收resolve和reject,若报错则通过reject抛出去
  5. 实现then方法,接收两个参数:then(onFulfilled, onRejected) {}
  6. 检查处理then参数,判断onFulfilled和onRejected是否为函数,若不是函数,则返回value或reason
  7. 定义返回值(promise2)并根据当前promise的状态调用不同的函数
  8. 设置一个状态的监听机制, 当状态变成fulfilled或者rejected后, 再去执行callback
  9. 新建两个数组, 来分别存储成功和失败的回调, 调用then的时候, 如果还是pending就存入数组
  10. 实现getter和setter函数,在给status赋值后, 下面再加一行forEach
  11. 当 onFulfilled 或者 onRejected 抛出异常 e ,则 promise2 拒绝执行,并返回拒因 e。(这样的话, 我们就需要手动catch代码,遇到报错就reject)
  12. 当onFulfilled 或者 onRejected 返回一个值 x ,则运行resolvePromise方法。将realOnFulfilled(this.value)赋值给x,this.resolvePromise(promise2, x, resolve, reject);
  13. 实现resolvePromise方法
  14. onFulfilled 和 onRejected 是微任务,使用queueMicrotask包裹执行函数
  15. 实现catch方法

3.Iterator,Generator和async的理解

Interator迭代器
  1. 是一种的特殊的对象,每一个迭代器对象都有一个next方法,
  2. 每次调用都会返回一个劫夺对象,结果对象中包含两个值:
    value: 当前属性的值;
    done: 判断是否遍历结束
Generator生成器
  1. 生成器时一种返回迭代器的函数,函数中会用到新的关键字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}
复制代码
  1. 注意
  • 每当执行完一条yield语句后函数就会自动停止执行, 直到再次调用next();
  • yield关键字只可在生成器内部使用,在其他地方使用会导致程序抛出错误;
  • 可以通过函数表达式来创建生成器, 但是不能使用箭头函数
    let generator = function *(){}

4.面试中可能会遇到的问题

  1. 为什么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

  1. 为什么在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

猜你喜欢

转载自juejin.im/post/7080141138232868901
今日推荐