Promise学习-手写一个promise

学习了Promise的A+规范,以及手写一个Promise后,我对Promise学到的结果。

平常也有用到过promise来处理异步,先回顾下promise的用法

new Promise((resolve,reject) => {异步操作并改变状态}).then(onfullfilled, onrejected)

const myPromise = new Promise((resolve,reject) => {
   
	//写一些异步操作,比如ajax请求
	if(window.onError){
   
		reject('页面加载失败');
	}
	setTimeout(() => {
   
		resolve('异步返回结果'); 
	}, 1000)
}).then((data) => {
   
	console.log(data);    // 异步返回结果
}).catch((reason)=>{
   
	console.log(reason);  // 页面加载失败
})

这个promise其实就是处理一件一段时间之后才能得到结果的事件,promise将将要执行的事件作为函数传入,并在得到结果时,resolve或者reject改变promise的状态并且改变结果,然后通过then或catch执行得到结果之后的事情。

一、每个promise都有三个状态

pending 初始化,可改变
fullfilled 成功,不可改变
rejected 失败,不可改变

promise的状态改变流程
在这里插入图片描述

二、resolve和reject函数

resolve:实参是定义在构造函数中的函数,
作用:
改变状态pending => fullfilled
改变结果 value = data
reject:实参是定义在构造函数中的函数,
作用:
改变状态pending => rejected,
改变结果 reason= reason

三、then:作为promise提供的一个方法, 用来访问最终的结果, 无论是value还是reason.

promise.then(onFulfilled, onRejected)

1.onFulfilled和onRejected,必须传入函数,如果不是函数,则改变为直接返回value或者reason的函数。
2.onFulfilled和onRejected只有当状态改变为相应的值后才可以执行,并将value和reason作为参数,且只可以执行一次
3.onFulfilled 和 onRejected 应该是微任务,这里用queueMicrotask来实现微任务的调用
4.then方法可以被调用多次
4.1promise状态变成 fulfilled 后,所有的 onFulfilled 回调都需要按照then的顺序执行, 也就是按照注册顺序执行(所以在实现的时候需要一个数组来存放多个onFulfilled的回调)
4.2promise状态变成 rejected 后,所有的 onRejected 回调都需要按照then的顺序执行, 也就是按照注册顺序执行(所以在实现的时候需要一个数组来存放多个onRejected的回调)
5.then 应该返回一个promise

 promise2 = promise1.then(onFulfilled, onRejected);
5.1 onFulfilled 或 onRejected 执行的结果为x, 调用 resolvePromise
5.2 如果 onFulfilled 或者 onRejected 执行时抛出异常e, promise2需要被reject
5.3 如果 onFulfilled 不是一个函数, promise2 以promise1的value 触发fulfilled
5.4 如果 onRejected 不是一个函数, promise2 以promise1的reason 触发rejected

不管是new Promise((resolve,reject)=> {})还是then((data) => {}),传入的函数都是在构造函数内执行的,所以实参是在构造函数内定义赋值的,所以我们再手写一个promise时,需要定义resolve和reject函数,以及得到的value,作为函数的实参

四、resolvePromise 就是处理then中onFulfilled 或 onRejected 返回的数据,并最终resolve或者reject掉promise2,改变promise2的状态,只有改变了状态,才能继续.then链式操作。

代码主要实现了A+规范里的内容:
如果 promise2 和 x 相等,那么 reject TypeError
如果 x 是一个 promsie
如果x是pending态,那么promise必须要在pending,直到 x 变成 fulfilled or rejected.
如果 x 被 fulfilled, fulfill promise with the same value.
如果 x 被 rejected, reject promise with the same reason.
如果 x 是一个 object 或者 是一个 function
let then = x.then.
如果 x.then 这步出错,那么 reject promise with e as the reason.
如果 then 是一个函数,then.call(x, resolvePromiseFn, rejectPromise)
resolvePromiseFn 的 入参是 y, 执行 resolvePromise(promise2, y, resolve, reject);
rejectPromise 的 入参是 r, reject promise with r.
如果 resolvePromise 和 rejectPromise 都调用了,那么第一个调用优先,后面的调用忽略。
如果调用then抛出异常e
如果 resolvePromise 或 rejectPromise 已经被调用,那么忽略
则,reject promise with e as the reason

五、手写一个promise

new MyPromise((resolve,reject) => {
   }).then(() => {
   }, () => {
   })
new MyPromise((resolve,reject) => {
   }).then(() => {
   }).catch(() => {
   })

从用法可以看出我们需要做的功能有
1.实现一个构造函数
2.构造函数接收一个函数作为参数
3.我们要再构造函数里面执行传进来的参数,并且传递实参resolve,reject, 作为提供给用户更改promise状态的方法
4.实现resolve,reject
5.实现then:
接收两个函数参数,分别在状态改变成对应值时触发
为了实现链式操作,继续让then返回一个promise
6.从promiseA+规范得知,我们还要实现一个resolvePromise去处理then返回的数据

1. promise是通过实例化的形式使用的,所以我们使用class写一个构造函数的方式实现。

class MyPromise {
   
	construcor() {
   }
}

2.promise始终是围绕三个状态状态实现异步的,所以我们定义下三个状态,并且给实例的promise状态、resolve结果值和reject原因赋初始值值。

const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
class MyPromise {
   
	construcor() {
   
        this.status = PENDING; // 初始状态为pending
        this.value = null;
        this.reason = null;
	}
}

3.我们调用的resolve和reject方法去改变promise状态并且将他的参数赋值。

class MPromise {
   
    constructor() {
   
        // 初始状态为pending
        this.status = PENDING;
        this.value = null;
        this.reason = null;
    }

    resolve(value) {
   
        if (this.status === PENDING) {
   
            this.value = value;
            this.status = FULFILLED;
        }
    }

    reject(reason) {
   
        if (this.status === PENDING) {
   
            this.reason = reason;
            this.status = REJECTED;
        }
    }
}

4.这个Promise类应该接收一个函数作为promise的入参,默认一进来就执行这个函数,并且把resolve和reject作为这个函数的入参抛出去,让使用的promise的人可以控制promise状态的改变。

class MPromise {
   
    constructor(fn) {
   
        // 初始状态为pending
        this.status = PENDING;
        this.value = null;
        this.reason = null;
        // 对用户自己传进来执行的代码块一般都做下try-catch
        try {
   
            // 这里绑定this是因为resolve执行的时候this的指向不一定是这个promise了,而我们要让他指向这里才能使用this.status...
        	fn(this.resolve.bind(this),this.reject.bind(this))
        } catch(e) {
   
			this.reject(e)
		}
    }
    
    resolve(value) {
   
        if (this.status === PENDING) {
   
            this.value = value;
            this.status = FULFILLED;
        }
    }

    reject(reason) {
   
        if (this.status === PENDING) {
   
            this.reason = reason;
            this.status = REJECTED;
        }
    }
}

5.接下来实现一下请求状态改变后的方法,then()

a.接收两个函数参数,分别在状态改变成对应值时触发
为了实现链式操作,继续让then返回一个promise

 then(onFulfilled, onRejected) {
   
    const realOnFulfilled = this.isFunction(onFulfilled)
      ? onFulfilled
      : (value) => {
   
          return value;
        };
    const realOnRejected = this.isFunction(onRejected)
      ? onRejected
      : (value) => {
   
          return value;
        };
    const promise2 = new MPromise((resolve, reject) => {
   
      switch (this.status) {
   
        case FULFILLED: {
   
          realOnFulfilled(value);
        }
        case REJECTED: {
   
          realOnRejected(value);
        }
      }
    
  • 7
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值