1、正常使用Promise
var p = new Promise(function(resolve, reject){
console.log('执行')
setTimeout(function(){
resolve(2)
}, 1000)
})
p.then(function(res){
console.log('suc',res)
},function(err){
console.log('err',err)
})
同步实现
2、首先实现三种状态:等待态(Pending)、执行态(Fulfilled)和拒绝态(Rejected)。
function MyPromise(executor){
var _this = this
_this.state = 'pending'; //状态
_this.value = undefined; //成功结果
_this.reason = undefined; //失败原因
function resolve(value) {
if(_this.state=='pending'){
_this.state = 'fulfilled'
_this.value = value
}
}
function reject(reason) {
if(_this.state=='pending'){
_this.state = 'rejected'
_this.value = reason
}
}
try { //executor也会可能存在异常,用try/catch来捕获异常情况:
executor(resolve, reject);
} catch (e) {
reject(e);
}
}
//实例化MyPromise时,构造函数会马上调用传入的执行函数executor
let p = new Promise((resolve, reject) => {
console.log('执行了');
});
3、then实现:当Promise的状态改变之后,不管成功还是失败,都会触发then回调函数。因此,then的实现就是根据状态的不同,来调用不同处理终值的函数。
MyPromise.prototype.then = function (onFulfilled, onRejected) {
if(this.state === 'fulfilled'){
onFulfilled(this.value)
}
if(this.state === 'rejected'){
onRejected(this.reason)
}
};
异步实现
4、如何让MyPromise来支持异步呢?可以参考发布订阅模式,在执行then方法的时候,如果当前还是PENDING状态,就把回调函数寄存到一个数组中,当状态发生改变时,去数组中取出回调函数。
将then里面的两个函数储存起来,由于一个promise可以有多个then,所以存在同一个数组内。成功或者失败时,forEach调用它们
function MyPromise(executor) {
this.onFulfilled = [];//成功的回调
this.onRejected = []; //失败的回调
}
当then执行时,如果还是PENDING状态,我们不是马上去执行回调函数,而是将其存储起来:
MyPromise.prototype.then = function (onFulfilled1, onRejected1) {
if(this.state === 'pending'){
this.onFulfilled.push(onFulfilled1)
this.onRejected.push(onRejected1)
}
};
存储起来后,当resolve或者reject异步执行的时候就可以来调用了
function resolve(value) {
if(_this.state === PENDING){
_this.state = FULFILLED
_this.value = value
_this.onFulfilled.forEach(fn => fn( _this.value))
}
}
function reject(reason) {
if(_this.state === PENDING){
_this.state = REJECTED
_this.reason = reason
_this.onRejected.forEach(fn => fn( _this.reason))
}
}
5、then链式调用
- 每个then方法都返回一个新的Promise对象(原理的核心)
- 如果then方法中显示地返回了一个Promise对象就以此对象为准,返回它的结果
- 如果then方法中返回的是一个普通值(如Number、String等)就使用此值包装成一个新的Promise对象返回。
- 如果then方法中没有return语句,就视为返回一个用Undefined包装的Promise对象
- 若then方法中出现异常,则调用失败态方法(reject)跳转到下一个then的onRejected
- 如果then方法没有传入任何回调,则继续向下传递(值的传递特性)
//1、
MyPromise.prototype.then = function (onFulfilled, onRejected) {
let promise2 = new Promise((resolve, reject)=>{
})
return promise2
}
判断是普通值还是Promise对象用resolvePromise函数(这个函数可以复用)
MyPromise.prototype.then = function (onFulfilled, onRejected) {
let promise2=new MyPromise((resolve,reject)=>{
if(this.state === 'fulfilled'){
let x=onFulfilled(this.value)
resolvePromise(promise2,x,resolve,reject);
}
if(this.state === 'rejected'){
let x= onRejected(this.reason)
resolvePromise(promise2,x,resolve,reject);
}
if(this.state === 'pending'){
this.onFulfilled.push(()=>{
let x=onFulfilled(this.value)
resolvePromise(promise2,x,resolve,reject);
})
this.onRejected.push(()=>{
let x=onRejected(this.reason)
resolvePromise(promise2,x,resolve,reject);
})
}
}))
return promise2;
};
then的回调是异步执行的,因此需要把onFulfilled和onRejected执行放到异步中去执行,同时做一下错误的处理:
onFulfilled或onRejected不能同步被调用,必须异步调用。用setTimeout解决异步问题
if(_this.state === FULFILLED){
setTimeout(()=>{
try {
let x = onFulfilled(_this.value)
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
} else if(_this.state === REJECTED){
setTimeout(()=>{
try {
let x = onRejected(_this.reason)
resolvePromise(promise2, x ,resolve, reject)
} catch (error) {
reject(error)
}
})
} else if(_this.state === PENDING){
_this.onFulfilled.push(()=>{
setTimeout(()=>{
try {
let x = onFulfilled(_this.value)
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
})
_this.onRejected.push(()=>{
setTimeout(()=>{
try {
let x = onRejected(_this.reason)
resolvePromise(promise2, x ,resolve, reject)
} catch (error) {
reject(error)
}
})
})
}
6、Promise.all()方法
Promise.all
接收一个 promise
对象的数组作为参数,当这个数组里的所有 promise
对象全部变为resolve
或 有 reject
状态出现的时候,它才会去调用 .then
方法,它们是并发执行的。
7、Promise.race()方法
当想要实现一个方法,每次传入多个请求,哪个先返回就取消其他的,使用先返回的值
8、Promise.resolve()方法
有时需要将现有对象转为 Promise 对象,Promise.resolve方法就起到这个作用。
//resolve方法
MyPromise.resolve = function(val){
return new Promise((resolve,reject)=>{
resolve(val)
});
}