前言
最开始的时候,没有分析需求,直接开始写。
写到一半发现没法符合异步需要。才发现还需要观察者模式帮忙。
这次从头开始。先分析需求。
一、需求明细
Promise.prototype上的属性
基本点
- Promise是个构造器,接受一个函数作为参数
- 有三种状态:pending/rejected/fulfilled
- Prototype的几种基本方法:then(fulfilled执行)/catch(rejected执行)/finally(非pending执行)
- 链式调用:需要返回 this
- 需要观察者模式——以应对异步的情况
一些方法的细节:就近原则,有 rejectedFn 则不走 catch,无则走 catch
完善点
Promise还有以下方法:all、allSettled、race、any
二、代码
错误代码:没有考虑异步的情况。。。
第一个纯同步函数,执行成功。 第二个异步函数,没有执行成功。(原因是立即执行,这个时候 status => pending)
const PENDING = 'pending'const FULFILLED = 'fulfilled'const REJECTED = 'rejected'function Promise(fn) {this.status = PENDINGthis.result = ''this.reason = ''this.resolve = (value) => {if (this.status === PENDING) {this.status = FULFILLEDthis.result = value}}this.reject = (value) => {if (this.status === PENDING) {this.status = REJECTEDthis.reason = value}}fn(this.resolve, this.reject)}Promise.prototype.then = function(resolveFunc, rejectFunc) {if (typeof resolveFunc === 'function' && this.status === FULFILLED) {resolveFunc(this.result)} else if (typeof rejectFunc === 'function' && this.status === REJECTED) {rejectFunc(this.reason)}return this}Promise.prototype.finally = function(finaFunc) {if (typeof finaFunc === 'function' && this.status !== PENDING) {finaFunc.call(this.result || this.reason)}}let p = new Promise(resolve => {resolve(true)}).then(res => {console.log('无异步', res)}).finally(res => {console.log('finally', res)})let pAsync = new Promise(resolve => {setTimeout(() => {console.log('god')resolve(true)}, 2000)}).then(res => {console.log('异步', res)}).finally(res => {console.log('finally:', res)})
结果
- 同步函数正常执行
- 异步函数,then、finally都没有执行
考虑异步的情况(利用观察者模式,在pending的时候订阅fulfilled-status、rejected-status)
错误代码:使用一个对象来存储“订阅者”的函数,多个 then 方法的情况会有问题
const PENDING = 'pending'const FULFILLED = 'fulfilled'const REJECTED = 'rejected'function Promise(fn) {this.status = PENDINGthis.result = ''this.reason = ''this.resolveObj = nullthis.rejectedObj = nullthis.resolve = (value) => {if (this.status === PENDING) {this.status = FULFILLEDthis.result = valuethis.resolveObj && this.resolveObj(this.result)}}this.reject = (value) => {if (this.status === PENDING) {this.status = REJECTEDthis.reason = valuethis.rejectedObj && this.rejectedObj(this.reason)}}fn(this.resolve, this.reject)}Promise.prototype.then = function(resolveFunc, rejectFunc) {if (this.status === PENDING) {this.resolveObj = resolveFuncthis.rejectedObj = rejectFunc} else if (typeof resolveFunc === 'function' && this.status === FULFILLED) {resolveFunc(this.result)return this} else if (typeof rejectFunc === 'function' && this.status === REJECTED) {rejectFunc(this.reason)return this}}let pDefer = new Promise(resolve => {setTimeout(() => {resolve('pDefer result')}, 1000)})pDefer.then(res => {console.log('第一个', res)})pDefer.then(res => {console.log('第二个', res)})

正确的结果应该是:
正确代码:使用数组来存放“订阅者”函数们
const PENDING = 'pending'const FULFILLED = 'fulfilled'const REJECTED = 'rejected'function Promise(fn) {this.status = PENDINGthis.result = ''this.reason = ''this.resolveFnArr = []this.rejectFnArr = []this.resolve = (value) => {if (this.status === PENDING) {this.status = FULFILLEDthis.result = valuethis.resolveFnArr.forEach(fn => fn(this.result))}}this.reject = (value) => {if (this.status === PENDING) {this.status = REJECTEDthis.reason = valuethis.rejectFnArr.forEach(fn => fn(this.reason))}}try {fn(this.resolve, this.reject)} catch (error) {this.reject(error)}}Promise.prototype.then = function(resolveFunc, rejectFunc) {if (this.status === PENDING) {typeof resolveFunc === 'function' && this.resolveFnArr.push(resolveFunc)typeof rejectFunc === 'function' && this.rejectFnArr.push(rejectFunc)} else if (typeof resolveFunc === 'function' && this.status === FULFILLED) {resolveFunc(this.result)return this} else if (typeof rejectFunc === 'function' && this.status === REJECTED) {rejectFunc(this.reason)return}}Promise.prototype.finally = function(finaFunc) {if (typeof finaFunc === 'function' && this.status !== PENDING) {finaFunc.call(this.result || this.reason)}}let pDefer = new Promise(resolve => {setTimeout(() => {resolve('pDefer result')}, 1000)})pDefer.then(res => {console.log('第一个', res)})pDefer.then(res => {console.log('第二个', res)})

符合需要
