详细

简述ES6中的Promise对象

Promise 的含义

所谓Promise,行为上是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。语法上,Promise 是一个对象,它可以获取异步操作的消息。

  • Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败),一旦状态改变,就不会再变。只有两种可能,从pending变为fulfilled和从pending变为rejected。

基本用法

const promise = new Promise(function(resolve, reject) {
// ... some code
if (/* 异步操作成功 */){
resolve(value);
} else {
reject(error);
}
});
promise.then(function(value) {
// success
}, function(error) {
// failure
});

then方法

  • then方法的第一个参数是resolved状态的回调函数,第二个参数是rejected状态的回调函数,它们都是可选的。
  • then方法返回的是一个新的Promise实例。因此可以采用链式写法,即then方法后面再调用另一个then方法。

catch方法

  • catch()方法是.then(null, rejection)或.then(undefined, rejection)的别名,用于指定发生错误(rejected状态或捕获的代码运行错误)时的回调函数。Promise 对象的错误具有“冒泡”性质。会一直向后传递,直到被捕获为止。也就是说,错误总是会被下一个catch语句捕获。

finally方法

finally()方法用于指定不管 Promise 对象最后状态如何,都会执行的操作。finally本质上是then方法的特例。

promise
.finally(() => {
// 语句
});
// 等同于
promise
.then(
result => {
// 语句
return result;
},
error => {
// 语句
throw error;
}
);

具体实现

Promise.prototype.finally = function (callback) {
let P = this.constructor;
return this.then(
value => P.resolve(callback()).then(() => value),
reason => P.resolve(callback()).then(() => { throw reason })
);
};

Promise的实现

// 1. promise status状态不可逆
// 2. catch处理指定错误(rejected状态或捕获的代码运行错误)
// 3. then返回的是promise,以实现链式调用
class MyPromise {
constructor(executor) {
this.status = 'pending';
this.value = undefined;
this.reason = undefined;
this.onFulfilledCallbacks = [];
this.onRejectedCallbacks = [];
const resolve = (value) => {
if (this.status === 'pending') {
this.status = 'fulfilled';
this.value = value;
this.onFulfilledCallbacks.forEach(fn => fn());
}
};
const reject = (reason) => {
this.status = 'rejected';
this.reason = reason;
this.onRejectedCallbacks.forEach(fn => fn());
};
try {
executor(resolve, reject);
} catch (error) {
reject(error);
}
}
then(onFulfilled, onRejected) {
return new MyPromise((resolve, reject) => {
const fulfilled = () => {
try {
if (typeof onFulfilled === 'function') {
resolve(onFulfilled(this.value));
} else {
resolve(this.value);
}
} catch (error) {
reject(error)
}
};
const rejected = () => {
try {
if (typeof onRejected === 'function') {
resolve(onRejected(this.reason));
} else {
reject(this.reason);
}
} catch (error) {
reject(error);
}
};
switch (this.status) {
case 'fulfilled':
fulfilled();
break;
case 'rejected':
rejected();
break;
default:
this.onFulfilledCallbacks.push(() => fulfilled());
this.onRejectedCallbacks.push(() => rejected());
}
});
}
catch(onRejected) {
return this.then(null, onRejected);
}
finally(cb) {
this.then(() => cb(), () => cb());
}
}