什么是Promise
Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。
解决了什么
解决了回调嵌套
// 比如我们有这样的一个需求 请求第一个成功之后, 在第一个成功的基础上 需要调用 第二个接口... 一次类推 两层还能接受, 但是如果是 4层 基本上就很难维护,和阅读
previewinit(id, tenantId, row)
.then( () => {
previewresult(statementId,clusterId)
.then( () =>{
getSchema()
.then()
})
})
// 在没有写逻辑的情况下已经很难读懂是什么意思了
对于几种常见异步编程方案
- 回到函数
- 时间监听
- 发布/订阅(可以看这篇文章)
Promise 的两个特点
-
对象的状态不受外界影响
// 有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。 const promise = new Promise(function(resolve, reject) { if (/* 异步操作成功 */){ resolve(value); } else { reject(error); } }); -
一旦状态改变,就不会在变
// 只有两种可能:从pending变为fulfilled和从pending变为rejected。
Promise 新建后就会立即执行
let promise = new Promise(function(resolve, reject) {
// 我们并没有调用 Promise 但是也是先执行啦
console.log('Promise');
resolve();
});
promise.then(function() {
console.log('resolved.');
});
console.log('Hi!');
// Promise 首先输出
// Hi!
// resolved
在函数内使用 Promise 需要 return promise
function loadImage () {
let promise = new Promise(function (resolve, reject) {
// some code
})
// 只有返回出去 外部才能拿到 promise 的实例
return promise
}
需要注意
resolved 的 Promise 是在本轮事件循环的末尾执行,总是晚于本轮循环的同步任务。
let promise = new Promise(function (resolve, reject) {
resolve(1)
console.log(2)
})
promise.then((result) => console.log(result))
// 2
// 1
let promise = new Promise(function (resolve, reject) {
// 一般情况下 我们执行 resolve 之后是不需要在执行后边的代码的所有使用 return
return resolve(1)
console.log(2)
})
promise.then((result) => console.log(result))
Promise.prototype.then()
- then方法是定义在原型对象Promise.prototype上的
- 可是使用链式操作
- then方法返回的是一个新的Promise实例(注意,不是原来那个Promise实例)
- 第一个回调函数完成以后,会将返回结果作为参数,传入第二个回调函数。
getJSON("/posts.json").then(function(json) {
return json.post;
}).then(function(post) {
// ...
});
Promise.prototype.catch()
- .then(null, rejection) 或 .then(undefined, rejection) 的别名
- 用于指定发生错误的对调函数
- 如果状态已经变成resolved,再抛出错误是无效的。
- Promise 对象的错误具有“冒泡”性质,会一直向后传递,直到被捕获为止。也就是说,错误总是会被下一个catch语句捕获。
- 建议总是使用catch方法,而不使用then方法的第二个参数。
- Promise 内部的错误不会影响到 Promise 外部的代码,
Promise.prototype.finally()
- 不管promise最后的状态,在执行完then或catch指定的回调函数以后,都会执行finally方法指定的回调函数。
- 回调函数 不接受任何参数, 不知道状态是成功还是失败, 所以与状态无关
- 如果 成功和失败都需要些同样的逻辑 则可以直接使用 finally
server.listen(port)
.then(function () {
// ...
})
// finally方法关掉服务器。
.finally(server.stop);
Promise.all()
- 方法接受一个数组作为参数 每个值都是 Promise 的实例 参数可以不是数组,但必须具有 Iterator 接口
- 如果作为参数的 Promise 实例,自己定义了catch方法,那么它一旦被rejected,并不会触发Promise.all()的catch方法。
- 实例的状态都变成fulfilled,或者其中有一个变为rejected,才会调用Promise.all方法后面的回调函数。
Promise.race()
const p = Promise.race([p1, p2, p3]);
- 方法接受一个数组作为参数
- 只要其中有一个实例率先改变状态,P的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数。
- 如果指定时间内没有获得结果,就将 Promise 的状态变为reject,否则变为resolve
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('success')
},1000)
})
let p2 = new Promise((resolve, reject) => {
setTimeout(() => {
reject('failed')
}, 500)
})
Promise.race([p1, p2]).then((result) => {
// 这里不会执行
console.log(result)
}).catch((error) => {
console.log(error) // 打印的是 'failed'
})
Promise.allSettled()
- 我们不关心异步操作的结果,只关心这些操作有没有结束。这时,Promise.allSettled()方法就很有用。
Promise.any()
- 方法接受一个数组作为参数
- 只要参数实例有一个变成fulfilled状态,包装实例就会变成fulfilled状态;如果所有参数实例都变成rejected状态,包装实例就会变成rejected状态。
Promise.resolve()
- 把现有对象转成 Promise 对象
- resolve()的 Promise 对象,是在本轮“事件循环”(event loop)的结束时执行,而不是在下一轮“事件循环”的开始时。
- 可以理解为 让一个对象有 then 方法
var promise1 = Promise.resolve(123);
promise1.then(function(value) {
console.log(value);
// expected output: 123
});
setTimeout(function () {
console.log('three');
}, 0);
Promise.resolve().then(function () {
console.log('two');
});
console.log('one');
// one
// two
// three