Promise基础
常见的方法
- 静态方法(类上的方法,通过
Promise.XXX
调用)Promise.all()
Promise.resolve()
Promise.reject()
Promise.race()
- 动态方法(原型上的方法,通过
new Promise().XXX
调用)new Promise().then()
new Promise().catch()
new Promise().finally()
常见方法的用法
- 1.
new Promise()
&&new Promise().then()
- 如图可以看出我们执行
new Promise()
的时候需要传进去一个executor
执行器(函数),并且会立即执行;包含两个参数一个是resolve
,一个是reject
这两个参数依然是函数 executor
函数会立即执行- 默认的状态是pendding
- 注:Promise一共有三种状态,等待态:pendding 、成功态:fulfilled、失败态:rejected
- 调用
executor
中的resolve
方法代表成功态 - 调用
executor
中的reject
方法代表失败态 - 可以从等待态(
pendding
)转化成成功态(fulfill
)/失败态(reject
);不可以从成功态/失败态向其他状态转化
- 如图可以看出我们执行
- 简易实现(仅支持同步)
function Promise(executor) { //1.传入executor
let self = this;
self.status = 'pending'; //5.在Promise内部中定义一个变量用来表示当前promise的状态
self.value = null; //6.记录resolve执行传入的value
self.reason = null; //7.记录reject执行传入的reason
function resolve(value) { //3.调用resolve会传入一个value
if (self.status !== 'pending') return;
self.status = 'fulfilled';
self.value = value;
}
function reject(reason) { // 4.调用reject会传入一个reason
if (self.status !== 'pending') return;
self.status = 'rejected';
self.reason = reason;
}
executor(resolve, reject) //2.executor立即执行,传入两个方法resolve,reject
}
/*在Promise的原型上有一个then方法,then方法执行会传入两个函数onFulfilled && onRejected;*/
Promise.prototype.then = function (onFulfilled, onRejected) {
let self = this;
if (self.status === 'fulfilled') { // promise的状态为fulfilled的时候onFulfilled执行
onFulfilled(self.value);
}
if (self.status === 'rejected') { // promise的状态为rejected的时候onFulfilled执行
onRejected(self.reason);
}
}
module.exports = Promise;
复制代码
- 升级实现(支持异步)
- 上述的代码中我们实现了
executor
函数管理同步的方法,并没有对exctutor
函数中管理的异步代码进行实现;即不是立即执行resolve
或者reject
方法的时候(也就是说then
方法中如果状态是pendding
的时候我们怎么处理)
- 上述的代码中我们实现了
function Promise(executor) {
let self = this;
self.status = 'pending';
self.value = null;
self.reason = null;
self.onFulfilledCallback = [];
self.onRejectedCallback = [];
function resolve(value) {
if (self.status !== 'pending') return;
self.status = 'fulfilled';
self.value = value;
self.onFulfilledCallback.forEach(fn => fn());
}
function reject(reason) {
if (self.status !== 'pending') return;
self.status = 'rejected';
self.reason = reason;
self.onRejectedCallback.forEach(fn => fn());
}
executor(resolve, reject);
}
Promise.prototype.then = function (onFulfilled, onRejected) {
let self = this;
if (self.status === 'fulfilled') {
onFulfilled(self.value);
}
if (self.status === 'rejected') {
onRejected(self.reason);
}
if (self.status === 'pending') {
self.onFulfilledCallback.push(function () {
onFulfilled(self.value);
});
self.onRejectedCallback.push(function () {
onRejected(self.reason);
})
}
}
module.exports = Promise;
复制代码
PeomiseA+实现
- 我们知道`Promise`最大的优点就是通过链式调用,解决回调地狱(恶魔金字塔)
- 链式调用的特点
- 1.如果一个`then`中方法返回普通值,那么这个值会传递给下一个`then`的`onFullfilled`的输入
- 2.如果一个`then`返回的是报错,那么这个错误信息会传递给下一个`then`的`onRejected`的输入
- 3.如果返回的是一个`Promise`,那么这个`Promise`的成功或者失败决定下一个`then`调用的方法
- 4.捕获错误机制
- 默认会找离自己最近的`then`的失败,找不到继续向下找,最后找不到抛错
- 实现原理
- 1.`promise`调用`then`方法会返回一个新的`Promise2`;
- 2.拿到当前`then`方法中成功(`onFulfilled`)或者失败(`onRejected`)执行返回的结果`x`
- 3.判断`then`方法返回的`promise2`和成功(`onFulfilled`)或者失败(`onRejected`)执行返回的结果`x`的关系
- 1).如果`promise === x` 抛出循环引用错误
复制代码
function Promise(executor) {
let self = this;
self.status = 'pending';
self.value = null;
self.reason = null;
self.onFulfilledCallback = [];
self.onRejectedCallback = [];
function resolve(value) {
if(value instanceof Promise){
value.then(y=>{
resolve(y);
},r=>{
reject(r);
})
}
if (self.status === 'pending') {
self.status = 'fulfilled';
self.value = value;
self.onFulfilledCallback.forEach(fn => fn());
};
}
function reject(reason) {
if (self.status === 'pending') {
self.status = 'rejected';
self.reason = reason;
self.onRejectedCallback.forEach(fn => fn());
};
}
try{
executor(resolve, reject);
}catch(err){
reject(err);
}
}
function resolvePromise(promise2, x, resolve, reject) {
if (promise2 === x) {
reject(new TypeError('Circular Reference'));
}
if (x !== null && typeof x === 'object' || typeof x === 'function') {
let called;
try {
let then = x.then;
if (typeof then === 'function') {
then.call(x, (y) => {
if (called) return;
called = true;
resolvePromise(promise2, y, resolve, reject);
// resolve(y);
}, (r) => {
if (called) return;
called = true;
reject(r);
})
} else {
resolve(x);
}
} catch (e) {
if (called) return;
called = true;
reject(e);
}
} else {
resolve(x);
}
}
Promise.prototype.then = function (onFulfilled, onRejected) {
let self = this;
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
onRejected = typeof onRejected === 'function' ?onRejected : err => {throw err};
let promise2 = new Promise(function (resolve, reject) {
if (self.status === 'fulfilled') {
setTimeout(() => {
try {
let x = onFulfilled(self.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0)
}
if (self.status === 'rejected') {
setTimeout(() => {
try {
let x = onRejected(self.reason);;
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0)
}
if (self.status === 'pending') {
self.onFulfilledCallback.push(function () {
setTimeout(() => {
try {
let x = onFulfilled(self.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0)
})
self.onRejectedCallback.push(function () {
setTimeout(() => {
try {
let x = onRejected(self.reason);;
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0)
})
}
})
return promise2;
}
/*实现一个Promise的defer对象*/
Promise.defer = function(){
let dfd = {};
dfd.promise = new Promise((resolve,reject)=>{
dfd.resolve = resolve;
dfd.reject = reject;
})
return dfd;
}
module.exports = Promise;
复制代码
注:上述代码实现过程中我们需要注意的几点说明:
- 1.放到setTimeout中,原因是:当我们
new Promise()
执行的时候传入的excutor
函数会立即执行,并且返回promise2
,但是如果我们不放到setTimeout
中我们是拿不到返回的promise2
的,因为函数还没有执行完,并没有返回值,至于为什么放到setTimeou
中可以拿到就涉及到了js
代码的执行机制以及宏任务微任务的一些知识了,这里我就不做过多赘述了- 2.细心的朋友应该可以看到我代码中注释掉了
resolve(y)
,而是递归调用了resolvePromise(promise2,y,resolve,reject)
,原因很简单就是当我们使用promise.then
调用resolve()
的时候可能继续传进去一个promise
- 3.
called
,使用called
的原因就更简单了,就是我们的promise
可能会出现和别人的promise
一起使用的情况,加called
就是为了防止别人的代码没有实现非pending
状态不能向其他状态转变的情况
验证是否符合PromiseA+
规范
- 使用官方提供的库promises-aplus-tests
- 1.全局安装
npm install promises-aplus-tests -g
- 2.通过
promises-aplus-tests xxx(需要测试的文件)
命令进行测试 - 3.要求测试的时候要有
Promise.deferred
,这就是我们代码中Promise.deffered
的一个别名,加上即可(我这里就不添加了,你们贴过去测一下就会看到效果)
非A+
规范中的Promise
常见方法实现
类上的方法
Promise.resolve()
Promise.resolve = function(value){
return new Promise((reslove,reject)=>{
reslove(value)
})
}
复制代码
Promise.reject()
Promise.reject = function(reason){
return new Promise((resolve,reject)=>{
reject(reason)
})
}
复制代码
Promise.all()
Promise.all = function(promises){
return new Promise((resolve,reject)=>{
let arr = [];
let i = 0;
function processData(index,value){
arr[index] = value;
if(++i === promises.length){
resolve(arr);
}
}
for(let i = 0; i < promises.length; i++){
let current = promises[i];
if(current !== null &&typeof current === 'object' || typeof current === 'function'){
let then = x.then;
if(typeof then === 'function'){
current.then(value=>{
processData(i,value);
},reject);
}else{
processData(i,current);
}
}else{
processData(i,current);
}
}
})
}
复制代码
Promise.race()
Promise.race = function(promises){
return new Promise((resolve,reject)=>{
for(let i = 0; i < promises.length; i++){
let current = promises[i];
if(current !== null && typeof current === 'object' || typeof current === 'function'){
let then = current.then;
if(typeof then === 'function'){
current.then(resolve,reject);
}else{
resolve(current)
}
}else{
resolve(current)
}
}
})
}
复制代码
原型上的方法
Promise.prototype.catch
Promise.prototype.catch = function(errCallback){
return this.then(null,errCallback);
}
复制代码
Promise.prototype.finally
Promise.prototype.finally = function(callback){
return this.then(value=>{
callback();
return value;
},reason=>{
callback();
return reason;
})
}
复制代码