Appearance
promise
什么是promise
- Promise 是一种在 JavaScript 中提供了异步编程范式的特殊对象。它可以被用来表示一个将来会发生的操作,或者说它是一个代表一个异步操作结果。使用它,可以轻松地实现异步请求,并用非常方便的方式处理请求成功或失败之后的操作
promise优缺点
- 优:promise很好的解决了异步编程中的,回调层层嵌套问题,使代码结构看起来更加的简洁,可读性更强
- 缺:promise一旦开始,无法取消或重置,意味着犯错了无法挽回
promiseA+规范
- 所有的promise都会遵循一个promiseA+规范来实现promiseA+文档
1、promise执行器
- promise是一个类,当在实例化时,会立马执行构造器,构造器接受resolve, reject函数等待用户执行
WARNING
构造器在执行的时候如果出现异常直接会调用reject函数
js
class Promise {
constructor ( executor ) {
const resolve = ( value ) => {
console.log( value )
}
const reject = ( reason ) => {
console.log( reason )
}
try {
// 出现异常直接走reject
executor( resolve, reject )
} catch ( e ) {
reject( e )
}
}
}
new Promise( ( resolve, reject ) => {
resolve( 'ok' )
} )
new Promise( ( resolve, reject ) => {
throw 'error'
resolve( 'ok' )
} )
2、promise状态
- promise有种状态分别是
pending(等待)
、fufilled(成功)
、rejected(失败)
- 状态只能从
pending=>fufilled
或者pending=>rejected
不能逆转 - 当在执行构造器中的
resolve
或者reject
时,如果此时的状态是pending,改变当前的状态,并且把成功或者失败的回调值
存储在实例上
js
const STATUS = {
PENDING: "PENDING",
FUFILLED: "FUFILLED",
REJECTED: "REJECTED",
};
class Promise {
constructor ( executor ) {
this.status = STATUS.PENDING
this.value = undefined;
this.reason = undefined;
const resolve = ( value ) => {
if ( this.status === STATUS.PENDING ) {
this.status = STATUS.FUFILLED
this.value = value
}
}
const reject = ( reason ) => {
if ( this.status === STATUS.PENDING ) {
this.status = STATUS.REJECTED
this.reason = reason
}
}
try {
executor( resolve, reject )
} catch ( e ) {
reject( e )
}
}
}
new Promise( ( resolve, reject ) => {
resolve( 'ok' )
} )
new Promise( ( resolve, reject ) => {
reject( 'error' )
} )
3、then函数
- 1、then 接收2个回调函数(onFulfilled,onRejected),一个成功的回调,一个失败的回调
- 2、当then回调传递的不是函数时,为了能够把值传递下去,会转换成函数
- 3、当在调用then函数时,如果此次时的状态是pending(等待),会把成功、失败的回调加入到队列中,等待执行
- 4、如果此时的状态不是pending(等待),会直接调用成功或者失败的回调
js
const STATUS = {
PENDING: "PENDING",
FUFILLED: "FUFILLED",
REJECTED: "REJECTED",
};
class Promise {
constructor ( executor ) {
this.status = STATUS.PENDING
this.value = undefined;
this.reason = undefined;
this.onFulfilledCallbacks = []
this.onRejectedCallbacks = []
const resolve = ( value ) => {
if ( this.status === STATUS.PENDING ) {
this.status = STATUS.FUFILLED
this.value = value
this.onFulfilledCallbacks.forEach( onRejected => {
onRejected( this.value )
} )
}
}
const reject = ( reason ) => {
if ( this.status === STATUS.PENDING ) {
this.status = STATUS.REJECTED
this.reason = reason
this.onRejectedCallbacks.forEach( onRejected => {
onRejected( this.value )
} )
}
}
try {
executor( resolve, reject )
} catch ( e ) {
reject( e )
}
}
then ( onFulfilled, onRejected ) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : ( value ) => value
onRejected = typeof onRejected === 'function' ? onRejected : ( err ) => { throw err };
if ( this.status === STATUS.PENDING ) {
this.onFulfilledCallbacks.push( () => onFulfilled )
this.onRejectedCallbacks.push( () => onRejected )
} else if ( this.status === STATUS.FUFILLED ) {
onFulfilled( this.value )
} else {
onRejected( this.reason )
}
}
}
let promise = new Promise( ( resolve, reject ) => {
resolve( 'ok' )
} )
promise.then((value)=>{
console.log(value)
})
new Promise( ( resolve, reject ) => {
reject( 'error' )
} )
4、then函数链式调用
- 为了支持then能够链式调用,then函数会返回一个新的promise2
js
then ( onFulfilled, onRejected ) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : ( value ) => value
onRejected = typeof onRejected === 'function' ? onRejected : ( err ) => { throw err };
const promise2 = new Promise( ( resolve, reject ) => {
if ( this.status === STATUS.PENDING ) {
this.onFulfilledCallbacks.push( () => onFulfilled )
this.onRejectedCallbacks.push( () => onRejected )
} else if ( this.status === STATUS.FUFILLED ) {
onFulfilled( this.value )
} else {
onRejected( this.reason )
}
} )
return promise2
}
5、then函数回调返回值处理
- 如果then回调函数调用出现异常,会走到下一个失败的then回调中
- 如果then回调返回的是一个promise,promise成功或者失败,会走到下一个成功或者失败的then回调中
- 如果then回调返回的是一个普通的值,不管是成功或者失败的回调,都有走到下一个成功的then回调中
循环引用案例
js
// 循环引用案例:
const promise2 = new Promise( ( resolve, reject ) => {
resolve( 'ok' )
} )
// 循环引用,造成无限死循环需要处理成 reject失败
promise2.then(()=>{
return promise2
})
// 处理异常
if ( promise2 === x ) {
return reject( new TypeError( "循环引用,造成无限死循环" ) );
}
// ....
then回调返回值是对象,取then异常处理
js
const x = {}
Object.defineProperty( x, 'then', {
get () {
throw new Error( 'error' )
}
} )
// 处理异常
try {
const then = x.then
} catch (e) {
// 取then错误走下一个失败的then回调
reject(e)
}
// ....
如果then回调返回值是一个Promise,并且resolve中的值也是一个Promise,需要递归把值传递下去
js
const promise = new Promise( ( resolve, reject ) => {
resolve( 'ok' )
} )
promise.then(()=>{
return new Promise( ( resolve, reject ) => {
resolve( Promise( ( resolve, reject ) => {
resolve( 'ok' )
} ) )
} )
})
// 处理递归
then.call(x,(y)=>{
// y有可能还是一个promise,递归到普通值结束
resolvePromise(y, promise2, resolve, reject);
},(r)=>{
// promise失败直接到下一个失败的then回调
reject(r)
})
// ....
如果then回调返回值是不一个规范的Promise,即可以成功也可以失败,我们需要防止这种情况,不可以逆向
js
const promise = new Promise( ( resolve, reject ) => {
resolve( 'ok' )
} )
promise.then(()=>{
// 自己实现的Promise即可以成功也可以失败
return new MyPromise( ( resolve, reject ) => {
resolve('ok')
reject('err')
} )
})
// 处理不规范的Promise(即可以成功也可以失败)
let called;
try {
const then = x.then
if(typeof then ==='function'){
// 执行promise.then
then.call(x,(y)=>{
if (called) return;
called = true;
// y有可能还是一个promise,递归到普通值结束
resolvePromise(y, promise2, resolve, reject);
},(r)=>{
if (called) return;
called = true;
// promise失败直接到下一个失败的then回调
reject(r)
})
}else{
if (called) return;
called = true;
// 普通值走下一个成功的then回调
resolve(x)
}
} catch (e) {
if (called) return;
called = true;
// 取then错误走下一个失败的then回调
reject(e)
}
// ....
6、完整源码实现
js
const STATUS = {
PENDING: "PENDING",
FUFILLED: "FUFILLED",
REJECTED: "REJECTED",
};
/**
*
* @param {*} x then回调的返回值
* @param {*} promise promise2的实例
* @param {*} resolve promise成功
* @param {*} reject promise失败
*/
function resolvePromise ( x, promise2, resolve, reject ) {
if ( promise2 === x ) {
return reject( new TypeError( "循环引用,造成无限死循环" ) );
}
// 对象或者function都有可能是Promise
if ( (typeof x === 'object' && x !== null) || typeof x ==='function') {
// 防止别人实现的promise即可以成功,也可以失败
let called;
try {
const then = x.then
if(typeof then ==='function'){
// 执行promise.then
then.call(x,(y)=>{
if (called) return;
called = true;
// y有可能还是一个promise,递归到普通值结束
resolvePromise(y, promise2, resolve, reject);
},(r)=>{
if (called) return;
called = true;
// promise失败直接到下一个失败的then回调
reject(r)
})
}else{
if (called) return;
called = true;
// 普通值走下一个成功的then回调
resolve(x)
}
} catch (e) {
if (called) return;
called = true;
// 取then错误走下一个失败的then回调
reject(e)
}
} else {
// 普通值走下一个成功的then回调
resolve( x )
}
}
class Promise {
constructor ( executor ) {
this.status = STATUS.PENDING
this.value = undefined;
this.reason = undefined;
this.onFulfilledCallbacks = []
this.onRejectedCallbacks = []
const resolve = ( value ) => {
if ( this.status === STATUS.PENDING ) {
this.status = STATUS.FUFILLED
this.value = value
this.onFulfilledCallbacks.forEach( onRejected => {
onRejected( value )
} )
}
}
const reject = ( reason ) => {
if ( this.status === STATUS.PENDING ) {
this.status = STATUS.REJECTED
this.reason = reason
this.onRejectedCallbacks.forEach( onRejected => {
onRejected( reason )
} )
}
}
try {
executor( resolve, reject )
} catch ( e ) {
reject( e )
}
}
then ( onFulfilled, onRejected ) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : ( value ) => value
onRejected = typeof onRejected === 'function' ? onRejected : ( err ) => { throw err };
const promise2 = new Promise( ( resolve, reject ) => {
if ( this.status === STATUS.PENDING ) {
this.onFulfilledCallbacks.push( () => {
// 保证promise2实例化完成
setTimeout( () => {
try {
const x = onFulfilled( this.value )
// 处理回调的结果
resolvePromise( x, promise2, resolve, reject )
} catch ( e ) {
// then回调出新异常直接调用下一个失败的then
reject( e )
}
} )
} )
this.onRejectedCallbacks.push( () => {
setTimeout( () => {
try {
const x = onRejected( this.reason )
resolvePromise( x, promise2, resolve, reject )
} catch ( e ) {
reject( e )
}
} )
} )
} else if ( this.status === STATUS.FUFILLED ) {
setTimeout( () => {
try {
const x = onFulfilled( this.value )
resolvePromise( x, promise2, resolve, reject )
} catch ( e ) {
reject( e )
}
} )
} else {
setTimeout( () => {
try {
const x = onRejected( this.reason )
resolvePromise( x, promise2, resolve, reject )
} catch ( e ) {
reject( e )
}
} )
}
} )
return promise2
}
catch(onRejected) {
return this.then(null, onRejected);
}
static resolve(val) {
return new Promise((resolve) => {
resolve(val);
});
}
static reject(reason) {
return new Promise((resolve, reject) => {
reject(reason);
});
}
static all(promisArr) {
return new Promise((resolve, reject) => {
let result = [],
count = 0;
function done(i, data) {
result[i] = data;
if (count++ == i) {
resolve(result);
}
}
promisArr.map((p, i) => {
p.then((data) => done(i, data), reject);
});
});
}
static race(promisArr) {
return new Promise((resolve, reject) => {
promisArr.map((p) => {
p.then((data) => resolve(data), reject);
});
});
}
}
Promise.defer = Promise.deferred = function () {
let dfd = {};
dfd.promise = new Promise((resolve, reject) => {
dfd.resolve = resolve;
dfd.reject = reject;
});
return dfd;
};
module.exports = Promise;
6、case
- 安装
npm install promises-aplus-tests -g
- 执行
promises-aplus-tests promise.js
(promise入口文件路径)
then 交替执行
- 如果有多个 fulfilled 状态的 promise 实例,同时执行 then 链式调用,
then 会交替调用
- 这是编译器的优化,防止一个 promise 持续占据事件
js
Promise.resolve().then(() => {
console.log(1)
}).then(() => {
console.log(2)
}).then(() => {
console.log(3)
}).then(() => {
console.log(4)
})
Promise.resolve().then(() => {
console.log(10)
}).then(() => {
console.log(20)
}).then(() => {
console.log(30)
}).then(() => {
console.log(40)
})
Promise.resolve().then(() => {
console.log(100)
}).then(() => {
console.log(200)
}).then(() => {
console.log(300)
}).then(() => {
console.log(400)
})
// 1 10 100 2 20 200 3 30 300 4 40 400
then返回promise
js
Promise.resolve().then(() => {
console.log(0)
return Promise.resolve(4) // 相当于多处一个 promise 实例,会慢2拍
}).then((res) => {
console.log(res)
})
Promise.resolve().then(() => {
console.log(1)
}).then(() => {
console.log(2)
}).then(() => {
console.log(3)
}).then(() => {
console.log(5)
}).then(() =>{
console.log(6)
})
// 0 1 2 3 4 5 6