Promise
1. 介绍与基本使用
1.1 Promise是什么?
抽象表达:
- Promise是一个新的ES6规范
- Promise是JS中异步编程的 新解决方案 注:旧方案单纯使用回调函数
具象表达:
- 从语法上说,Promise是一个构造函数,可以进行对象的实例化
- 从功能上说:Promise对象用来封装一个异步操作,并取到成功/失败的结果值
异步操作列举(包括但不限于):
1)fs 文件操作 2)数据库操作 3)AJAX 4)定时器
1.2 为什么要用Promise?
1.2.1 指定回调函数的方式更加灵活
- 旧的,必须在启动任务前指定,例如:
setTimeout(() => {
// 回调函数
}, 2000);
- Promise:可以在启动异步任务之后再绑定回调函数,甚至可以绑定多个
const p = new Promise((resolve, reject) => {
// 异步操作
setTimeout(() => {
resolve('ok');
}, 2000);
});
p.then((value) => {
// 执行成功的回调函数
console.log(value); // ok
});
p.then((value) => {
// 可以多次调用
console.log(123); // 123
});
1.2.2 支持链式调用,解决回调地狱问题(重要)
- 什么是回调地狱?看代码
asyncFunc1(opt, (...arg1) => {
asyncFunc2(opt, (...arg2) => {
asyncFunc3(opt, (...arg3) => {
// 执行操作
});
});
});
- 回调地狱缺点:
不便于阅读,不便于异常处理
1.3 Promise的基本用法
const promise = new Promise((resolve, reject) => {
// do someing
if (/* 异步操作成功 */) {
resolve(value);
} else {
reject(error);
}
});
promise.then(
// 成功回调
(value) => {
console.log(`success ${value}`)
},
// 失败回调
(reason) => {
console.log(`fail ${reason}`)
})
1.4 Promise的状态改变
1.4.1 Promise的状态
实例对象中的一个属性 「PromiseState」
- pending 变为 resolved(同fulfilled)
- pending 变为 rejected
默认起始状态为
pending(未决定的),改变后的状态只有这两种fulfilled(已成功)和rejected(已失败),并且一个Promise对象状态只能改变一次,成功或者失败,成功的结果数据一般称为value,失败的结果数据一般为reason
1.4.2 Promise的值
实例对象中的另一个属性「PromiseResult」
保存着「成功/失败」的结果值,是由resolve和reject两个函数的返回值决定的

2. API
2.1 构造函数:Promise(executor){}
executor函数:执行器(resolve, reject) => {}resolve函数:内部定义成功时调用的函数(value) => {}reject函数:内部定义失败时调用的函数(reason) => {}
executor 会在内部立即同步调用
2.2 Promise.prototype.then方法:(onResolved, onRejected) => {}
onResolved函数:成功时回调函数(value) => {}onRejected函数:失败时回调函数(reason) => {}
then方法返回的是一个新的Promise实例(注意,不是原来那个Promise实例)。因此可以采用链式写法,即then方法后面再调用另一个then方法。
2.3 Promise.prototype.catch方法:(onRejected) => {}
onRejected函数:失败时回调函数(reason) => {}
2.4 Promise.resolve方法:(value) => {}
- value:成功的数据或Promise对象
- 返回值为成功/失败的Promise对象
2.5 Promise.reject方法:(reason) => {}
- reason:失败的原因
- 返回值为失败的Promise对象
2.6 Promise.all方法:(promiseArr) => {}
- promiseArr:包含n个Promise对象的数组
- 返回值一个新Promise对象,所有的Promise成功才成功,只要有一个失败就直接失败
2.7 Promise.race:(promiseArr) => {}
- promiseArr:包含n个Promise对象的数组
- 返回值一个新Promise对象,第一个完成的Promise的结果状态就是最终的结果状态
3. 关键问题
3.1 如何改变Promise的状态?
resolve(value):pending => resolvedreject(reason):pending => rejectedthrow抛出异常:pending => rejected
3.2 指定多个成功或失败的回调函数,都会执行吗?
当状态改变时,同一个Promise的多个then/catch函数都会执行,参考1.2.1
3.3 改变Promise状态和指定回调函数谁先谁后?
都有可能
其实是同步异步的问题,执行器是异步函数就是先指定回调函数,再改变状态,反之同步函数则是先改变状态,再指定回调函数
3.4 Promise.then()返回的Promise状态由什么决定?
简单来说,由then指定的回调函数的执行结果决定
const p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('ok');
});
});
const result = p.then((value) => {
// 1. 抛出错误
// throw 'Error'
// result为{PromiseState: 'rejected', PromiseResult: 'error'}
// 2. 返回结果为非Promise类型的对象
// return 'success';
// result为{PromiseState: 'fulfilled', PromiseResult: 'success'}
// 3. 返回结果是Promise对象
// return new Promise((resolve) => { resolve('123')})
// result为新的Promise的结果{PromiseState: 'fulfilled', PromiseResult: '123'}
});
3.5 Promise如何串联多个操作任务?
通过then()链式调用
const p = new Promise((resolve, reject) => {
resolve('ok');
}).then((value) => {
return value;
}).then((v2) => {
return v2;
});
3.6 Promise异常穿透?
当使用then链式调用时,只需在最后指定一次失败的回调,前面任何操作出了异常都会在传到失败的回调函数中处理
const p = new Promise((resolve, reject) => {
resolve('ok');
}).then((value) => {
throw 'error';
}).then((v2) => {
throw 'no';
}).catch((reason) => {
console.log(reason) // error
});
3.7 中断Promise链?
当使用链式调用时,在中间间断,不再调用后面的回调函数
方法:在回调函数中返回一个pending状态的Promise对象
const p = new Promise((resolve, reject) => {
resolve('ok');
}).then((value) => {
console.log(value);
// 中断,有且只有一种方式
return new Promise(() => {});
}).then((v2) => {
console.log(v2);
}).catch((reason) => {
console.log(reason)
});
4. 自定义封装
4.1 声明构造函数
// 声明构造函数
function Promise(executor) {
// 添加 属性
this.PromiseState = 'pending';
this.PromiseResult = null;
// 回调函数
this.callbacks = [];
// 保存实例对象的this值
const self = this;
try {
// 同步调用「执行器函数」
executor(resolve, reject);
} catch (e) {
// 修改Promise的对象状态为「失败」
reject(e);
}
// 成功回调
function resolve(data) {
common('fulfilled', data);
// 回调函数异步执行
setTimeout(() => {
// 执行then中的回调
self.callbacks.forEach(({onResolved}) => {
onResolved(data);
});
});
}
// 失败回调
function reject(data) {
common('rejected', data);
// 回调函数异步执行
setTimeout(() => {
// 执行then中的回调
self.callbacks.forEach(({onRejected}) => {
onRejected(data);
});
});
}
function common(state, data) {
// 状态只能改变一次
if (self.PromiseState !== 'pending') return;
// 改变状态和值
self.PromiseState = state;
self.PromiseResult = data;
}
}
4.2 添加 then 方法
// 添加 then 方法
Promise.prototype.then = function(onResolved, onRejected) {
const self = this;
// then方法返回值为Promise对象
return new Promise((resolve, reject) => {
// 封装函数
function callback(type) {
try {
// 获取回调函数的执行结果
const result = type(self.PromiseResult);
// 执行结果是Promise对象,执行then方法
if (result instanceof Promise) {
result.then((v) => {
resolve(v);
}, (r) => {
reject(r);
});
} else {
// 执行结果的对象状态为「成功」
resolve(result);
}
} catch (e) {
reject(e);
}
}
// 根据状态调用回调函数
if (this.PromiseState === 'fulfilled') {
// 回调函数异步执行
setTimeout(() => {
callback(onResolved);
});
}
if (this.PromiseState === 'rejected') {
// 回调函数异步执行
setTimeout(() => {
callback(onRejected);
});
}
// 异步操作
if (this.PromiseState === 'pending') {
// 保存回调函数
this.callbacks.push({
onResolved: function() {
callback(onResolved);
},
onRejected: function() {
callback(onRejected);
},
})
}
})
}
4.2 添加 catch 方法
// 添加 catch 方法
Promise.prototype.catch = function(onRejected) {
return this.then(undefined, onRejected);
}
4.2 添加 resolve 方法
// 添加 resolve 方法
Promise.resolve = function(value) {
// 返回Promise对象
return new Promise((resolve, reject) => {
if (value instanceof Promise) {
value.then((v) => {
resolve(v);
}, (r) => {
reject(r);
});
} else {
// 执行结果的对象状态为「成功」
resolve(value);
}
})
}
4.2 添加 reject 方法
// 添加 reject 方法
Promise.reject = function(reason) {
// 返回Promise对象
return new Promise((resolve, reject) => {
reject(reason);
})
}
4.2 添加 all 方法
// 添加 all 方法
Promise.all = function (promises) {
return new Promise((resolve, reject) => {
const res = [];
let count = 0;
// 虽然是循环,但状态只改变一次
for (let i = 0, len = promises.length; i < len; i ++) {
const p = promises[i];
p.then((v) => {
count++;
// 将结果保存
// res.push(v); // 因为执行顺序可能不一致,用push会导致下标对应不一致
res[i] = v;
// 改变状态
if (count === len) {
resolve(res);
}
}, (r) => {
reject(r);
});
}
});
}
4.2 添加 race 方法
// 添加 race 方法
Promise.race = function (promises) {
return new Promise((resolve, reject) => {
for (let i = 0, len = promises.length; i < len; i ++) {
const p = promises[i];
p.then((v) => {
resolve(v);
}, (r) => {
reject(r);
});
}
});
}