Promise A+规范
promise基础:promise是一个构造函数,参数为一个,是一个要执行的函数,称为executor
let promise = new Promise((resolved,rejected)=>{})//executor
一、基础定义
1.promise是一个带有then方法的object或function
2.then是一个function
3.value是一个合法的JavaScript变量
4.exception 是一个抛出的错误
5.reason 是一个说明promise变成rejected的原因
二、要求
promise 状态
promise有三个状态:pending 、fulfilled、rejected
1.promise初始状态为pending
2.promise状态为fulfilled时,状态不能再更改,且一定要有一个value,也是不能再更改的
3.promise状态为rejected时,状态不能再更改,且一定要有一个reason,也是不能再更改的
关于then方法
promise必须提供一个then方法,去接收后续操作
promise.then(onFulfilled,onRejected)
1.onFulfilled和onRejected都是可选的,若不是函数,则会被忽略
2.onFulfilled是一个函数且当promise状态变为fulfilled的时候就会执行,且传入一个参数为value,每个then里面的onFulfilled只能被调用一次
3.onRejected是一个函数且当promise状态变为rejected一个参数为reason,每个then里面的onRejected只能被调用一次
4.onFulfilled和onRejected必须作为函数被调用,且里面不能有this
5.一个promise的then是可以有多个的,但是其中的onFulfilled和onRejected都必须按照顺序来调用
let promise = new Promise(()=>{})// 按照1 2 3的顺序来promise.then(()=>{console.log(1)})promise.then(()=>{console.log(2)})promise.then(()=>{console.log(1)})promise.then(()=>{console.log(3)})
简单实现一个Promise
由上面要求可得知,promise一共有三个状态,分别是PENDING、FULFILLED、REJECTED
当promise状态只有为PENDING时,才能改变状态,同时赋值
当执行then方法时,入参为两个函数,分别为onFulfilled和onRejected
故有如下代码
const PENDING = "PENDING",FULFILLED = "FULFILLED",REJECTED = "REJECTED"class MyPromise {constructor(executor) {this.state = PENDING,this.value = undefined,this.reason = undefined;const resolve = (value) => {if (this.state === "PENDING") {this.state = FULFILLED;this.value = value}}const rejecte = (reason) => {if (this.state === "PENDING") {this.state = REJECTEDthis.reason = reason}}try {executor(resolve, rejecte)} catch (e) {rejecte(e)}}then(onFulfilled, onRejected) {if (this.state === "FULFILLED") {onFulfilled(this.value)}if (this.state === "REJECTED") {onRejected(this.reason)}}}module.exports = MyPromise
这样就可以简单实现promise的基础功能的
但此时还不能实现异步及多个then的依次调用,所以我们下面要用到发布-订阅的模式
const PENDING = "PENDING",
FULFILLED = "FULFILLED",
REJECTED = "REJECTED"
class MyPromise {
constructor(executor) {
this.state = PENDING,
this.value = undefined,
this.reason = undefined;
// 添加两个容器保存对应的事件
this.onFulfilledCallbacks = []
this.onRejectedCallbacks = []
const resolve = (value) => {
if (this.state === "PENDING") {
this.state = FULFILLED;
this.value = value
// 执行等待事件
this.onFulfilledCallbacks.forEach(item => {
item()
})
}
}
const rejecte = (reason) => {
if (this.state === "PENDING") {
this.state = REJECTED
this.reason = reason
// 执行等待事件
this.onRejectedCallbacks.forEach(item => {
item()
})
}
}
try {
executor(resolve, rejecte)
} catch (e) {
rejecte(e)
}
}
then(onFulfilled, onRejected) {
if (this.state === "FULFILLED") {
onFulfilled(this.value)
}
if (this.state === "REJECTED") {
onRejected(this.reason)
}
// 异步时 将事件添加到等待队列里面等待执行
if (this.state === "PENDING") {
if (typeof onFulfilled === "function") {
this.onFulfilledCallbacks.push(() => {
onFulfilled(this.value)
})
}
if (typeof onRejected === "function") {
this.onRejectedCallbacks.push(() => {
onRejected(this.reason)
})
}
}
}
}
module.exports = MyPromise
扩展要求-链式调用
promiseA+规范里面要求then要返回一个新的promise,且要求不管是onFulfilled还是onRejected都要返回一个x并且当抛出异常的时候都需要拿到这个异常返回e,并且对于onFulfilled和onRejected要做异步,所以下面要将then方法改造
// 如果FulFilled和Rejected的时候没有setTimeout的话会报错,因为此时promise2还没构造出来
//resolvePromise是针对 onFulfilled 和 onrejectd里的返回值做判断,是否为一个promise
// 判断x是否一个promise
// 都是根据promiseA+规范中的2.3.x 的要求去设定的
function resolvePromise(promise2, x, resolve, reject) {
// 规范2.3.1 当promise2 与 x为同一个引用时,需要抛出 TypeError
// let p2 = p.then((res) => {
// return p2
// })
if (promise2 === x) {
return reject(new TypeError('Chaining cycle detected for promise #<MyPromise>'))
}
// 这样就可能是个Promise
if ((typeof x === "object" && x != null) || typeof x === "function") {
try {
let then = x.then;
let called = false
// 如果then是function,就认为他是个Promise
if (typeof then === "function") {
// 规范定义,如果被调用过,就不能重复调用
then.call(x, (y) => {
if (called) return
called = true
resolve(y)
}, (r) => {
if (called) return
called = true
reject(r)
})
} else {
// 不是Promise就返回x
resolve(x)
}
} catch (e) {
reject(e)
}
} else {
resolve(x)
}
}
then(onFulfilled, onRejectd) {
//每一个都加上try catch
let promise2 = new MyPromise((resolve, reject) => {
// 返回一个x
let x;
if (this.state === "FULFILLED") {
setTimeout(() => {
try {
x = onFulfilled(this.value)
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
})
}
if (this.state === "REJECTED") {
setTimeout(() => {
try {
x = onRejectd(this.reason)
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
})
}
// 异步时 将事件添加到等待队列里面等待执行
if (this.state === "PENDING") {
if (typeof onFulfilled === "function") {
this.onFulfilledCallbacks.push(() => {
try {
x = onFulfilled(this.value)
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
})
}
if (typeof onRejectd === "function") {
this.onRejectdCallbacks.push(() => {
try {
x = onRejectd(this.reason)
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
})
}
}
// return promise2
})
return promise2
}
然后我们运行一下结果,以下基本上都和Promise一致了,除了一些情况
const MyPromise = require("./myPromise3")
let promise1 = new MyPromise((resolve, reject) => {
// console.log(3);
//setTimeout(() => {
resolve("promise1");
//}, 1000)
// console.log(a);
// console.log(4);
//reject(100)
})
let promise2 = promise1.then(() => {
// return 1
// return new Error("error") // error
// return Promise.resolve("Promise resolve") // Promise resolve
return new MyPromise((resolve, reject) => {
// resolve("new MyPromise") // new MyPromise
// setTimeout(() => {
// resolve("setTimeout new MyPromise") //setTimeout new MyPromise
// })
// 异步 + 多层嵌套
setTimeout(() => {
resolve(new MyPromise((resolve, reject) => {
resolve("setTimeout resolve new MyPromise") // 此时这里打印出一个MyPromise的实例
})) //setTimeout new MyPromise
})
})
}, (reason) => {
console.log(reason);
return reason
})
promise2.then((res) => {
console.log("res", res);
}, (reason) => {
console.log(reason);
return reason
})
继续优化,这里主要是一个递归的问题
function resolvePromise(promise2, x, resolve, reject) {
...
// 将这里的resolve改为递归调用resolvePromise,如果是Promise就继续执行,这样就不怕嵌套问题了
if (typeof then === "function") {
// 规范定义,如果被调用过,就不能重复调用
then.call(x, (y) => {
if (called) return
called = true
resolvePromise(promise2, y, resolve, reject)
}, (r) => {
if (called) return
called = true
reject(r)
})
} else {
// 不是Promise就返回x
resolve(x)
}
...
}
当链式调用时,这时没有东西打印出来,因为在规范中规定,onFulfilled和onRejected是可选的,且当他们为非函数时则要忽略,所以当它们不存在时,则默认将参数传递下去。
promise2.then().then().then().then((res) => {
console.log("res", res);
}, (reason) => {
console.log(reason);
return reason
})
所以要修改一下then方法
then(onFulfilled, onRejectd) {
onFulfilled = typeof onFulfilled === "function" ? onFulfilled : (value) => {
return value
}
onRejectd = typeof onRejectd === "function" ? onRejectd : (reason) => {
throw (reason)
}
...
}
此时还缺一个.catch的catch方法,catch其实就是一个then方法
catch (errorCallBack) {
this.then(null, errorCallBack)
}
然后就可以在.then后面加.catch啦
promise2.then().then().then().then((res) => {
console.log("res", res);
}, (reason) => {
console.log(reason);
return reason
}).catch((e) => {
console.log("catch:", e);
})
