查看了
阮一峰ES6
借鉴里面的内容总结
什么是 Promise
Promise 是异步编程的一种解决方案, 没有
Promise
之前, 使用的是 回调函数和事件
回调地狱
- 以前没有
Promise
时, 我们使用回调
来解决异步问题, 但一旦回调的次数变多, 回调里面嵌套回调, 代码就变得难以维护
// 当一个数据返回, 使用结果来请求另一个数据, 等待结果再次请求其它数据... , 无穷尽也
<script>
$.ajax({
type: 'get',
url: './user.json',
success: (res) => {
const { id } = res
$.ajax({
type: 'get',
url: './tel.json',
success: res => {
const { tel } = res
$.ajax({
type: 'get',
url: './tel.json',
success: res => {
// TODO: 请求...
}
})
}
})
}
})
</script>
ES6 -> Promise
Promise
解决了上面的回调地狱
-
Promise
特点- 对象的状态不受外界影响
- 一旦状态改变, 就不会再变
-
Promise
基本使用
/**
* 接受一个函数作为参数
* 参数函数 有两个参数: resolve, reject
*/
new Promise((resolve, reject) => {})
// 得到结果
[[Prototype]]: Promise
[[PromiseState]]: "pending"
[[PromiseResult]]: undefined
-
Promise
状态- 看到上面
new Promise
返回结果里有一个[[PromsieState]]: pending
-
Promise
有三种状态:pending(进行中) fulfilled(已成功) rejected(以失败)
- 看到上面
-
改变
Promise
状态上面我们知道 Promise 特点就是: 对象状态不受外界影响, 那我们应该怎么改变 Promise 的状态呢?
// 只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态 // Promise 状态从 pending -> fulfilled const p1 = new Promise((resolve, reject) => resolve()) console.log(p1) // [[PromiseState]]: "fulfilled" // Promise 状态从 pending -> rejected const p2 = new Promise((resolve, reject) => reject()) console.log(p2) // [[PromiseState]]: "rejected" // Promise 状态一旦改变. 就不会再变 const p3 = new Promise((resolve, reject) => { resolve() reject() }) console.log(p3) // [[PromiseState]]: "fulfilled" const p4 = new Promise((resolve, reject) => { reject() resolve() }) console.log(p4) // [[PromiseState]]: "rejected"
-
得到
Promise
的结果// 得到成功的结果 const p1 = new Promise((resolve, reject) => { resolve('成功了') }) console.log(p1) // [[PromiseResult]]: "成功了" p1.then(res => console.log(res)) // 成功了 // 得到失败的结果 const p2 = new Promise((resolve, reject) => { reject('失败了') }) console.log(p2) // [[PromiseResult]]: "失败了" p2.catch(err => console.log(err)) // 失败了
使用 Promise 方法
then 方法
- Promise 实例具有
then
方法,也就是说,then
方法是定义在原型对象Promise.prototype
上的-
then
方法的第一个参数是resolved
状态的回调函数,第二个参数是rejected
状态的回调函数,它们都是可选的 -
then
方法返回的是一个新的Promise
实例, 状态是pending
可以采用链式写法
-
// then 接收两个参数, 都是可选的, 参数都是函数, 返回值也是 Promise 实例
const p1 = new Promise((resolve, reject) => {
// 实参
resolve('成功')
})
// [[PromiseState]]: "fulfilled"
// resolve 实参 传给 第一个函数的形参
p1.then((res) => {
console.log(res, '成功时的回调') // 成功 成功时的回调
}, (err) => {
console.log(err, '失败时的回调')
})
const p2 = new Promise((resolve, reject) => {
reject('失败')
})
p2.then((res) => {
console.log(res, '成功时的回调')
}, (err) => {
console.log(err, '失败时的回调') // 失败 失败时的回调
})
-
Promise
状态不改变 不会执行.then()
里面的方法
new Promise((resolve, reject) => {
}).then((res) => {
console.log(res, '成功时的回调')
}, (err) => {
console.log(err, '失败时的回调')
})
// 返回结果 pending
[[Prototype]]: Promise
[[PromiseState]]: "pending"
[[PromiseResult]]: undefined
// 两次 then, resolve()
new Promise((resolve, reject) => {
resolve()
}).then((res) => {
console.log(res, '成功时的回调') // undefined '成功时的回调'
}, (err) => {
console.log(err, '失败时的回调')
}).then((res) => {
console.log(res, '成功2') // undefined '成功2'
}, (err) => {
console.log(err, '失败2')
})
// 在 then 成功里面 return
new Promise((resolve, reject) => {
resolve()
}).then((res) => {
console.log(res, '成功时的回调') // undefined '成功时的回调'
return 'yym'
}, (err) => {
console.log(err, '失败时的回调')
}).then((res) => {
console.log(res, '成功2') // yym 成功2
}, (err) => {
console.log(err, '失败2')
})
// 返回结果 fulfilled
[[Prototype]]: Promise
[[PromiseState]]: "fulfilled"
[[PromiseResult]]: undefined
// 进入 失败 的回调
new Promise((resolve, reject) => {
resolve()
}).then((res) => {
console.log(res, '成功时的回调')
throw new Error('出错了')
}, (err) => {
console.log(err, '失败时的回调')
}).then((res) => {
console.log(res, '成功2')
}, (err) => {
console.log(err, '失败2') // Error: 出错了, '失败2'
})
catch 方法
-
Promise.prototype.catch()
方法是.then(null, rejection)
或.then(undefined, rejection)
的别名,用于指定发生错误时的回调函数
// catch 中的参数函数在什么时候执行
// 1. 当 promise 的状态从 pending -> rejected
new Promise((resolve, reject) => {
reject()
}).catch(() => {
console.log('失败了...') // 失败了...
})
// 2. 当 promise 代码执行出现错误
new Promise((resolve, reject) => {
throw new Error('错误')
}).catch(() => {
console.log('失败了...')
})
-
[引用阮一峰ES6 promise]
Promise 对象的错误具有“冒泡”性质,会一直向后传递,直到被捕获为止。也就是说,错误总是会被下一个catch
语句捕获
// 一共有三个 Promise 对象:一个由`getJSON()`产生,两个由`then()`产生。它们之中任何一个抛出的错误,都会被最后一个`catch()`捕获
getJSON('/post/1.json').then(function(post) {
return getJSON(post.commentURL);
}).then(function(comments) {
// some code
}).catch(function(error) {
// 处理前面三个Promise产生的错误
});
-
catch
最佳实践- 下面代码第二种写法可以捕获前面
then
方法执行中的错误,也更接近同步的写法(try/catch
)。因此,建议总是使用catch()
方法,而不使用then()
方法的第二个参数
- 下面代码第二种写法可以捕获前面
// bad
promise
.then(function(data) {
// success
}, function(err) {
// error
});
// good
promise
.then(function(data) { //cb
// success
})
.catch(function(err) {
// error
});
-
finally()
方法
-
finally()
方法用于指定不管 Promise 对象最后状态如何,都会执行的操作 -
finally
方法的回调函数不接受任何参数,这意味着没有办法知道,前面的 Promise 状态到底是fulfilled
还是rejected
。这表明,finally
方法里面的操作,应该是与状态无关的,不依赖于 Promise 的执行结果
promise
.then(result => {···})
.catch(error => {···})
.finally(() => {···});
// finally 实现
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 其它使用
Promise.all
-
Promise.all()
方法用于将多个 Promise 实例,包装成一个新的 Promise 实例
// 接收一个数组为参数
Promise.all([a, b, c]).then(() => {})
// a b c 都是 promise 实例, 都从 pending -> fulfilled, Promise.all 才会返回成功 fulfilled
// 只要有一个 rejected, Promise.all 就会失败
const p1 = new Promise((resolve) => resolve(1))
const p2 = new Promise((resolve) => resolve(2))
const p3 = new Promise((resolve) => resolve(3))
Promise.all([p1, p2, p3]).then(res => {
console.log(res, 'res是个数组')
})
// [1, 2, 3] 'res是个数组'
const p1 = new Promise((resolve) => resolve(1))
const p2 = new Promise((resolve) => resolve(2))
const p3 = new Promise((resolve, reject) => reject(3))
Promise.all([p1, p2, p3]).then(res => {
console.log(res, 'res是个数组')
}).catch(reason => {
console.log(reason, 'reason') // 3 'reason'
})
Promise.allSettled()
有时候,我们希望等到一组异步操作都结束了,不管每一个操作是成功还是失败,再进行下一步操作
-
Promise.allSettled()
方法接受一个数组作为参数,数组的每个成员都是一个 Promise 对象,并返回一个新的 Promise 对象。只有等到参数数组的所有 Promise 对象都发生状态变更(不管是fulfilled
还是rejected
),返回的 Promise 对象才会发生状态变更
const p1 = new Promise((resolve) => resolve(1))
const p2 = new Promise((resolve) => resolve(2))
const p3 = new Promise((resolve, reject) => reject(3))
Promise.allSettled([p1, p2, p3]).then(res => {
console.log(res)
})
// 返回
[
{status: 'fulfilled', value: 1}
{status: 'fulfilled', value: 2}
{status: 'rejected', reason: 3}
]
// 使用 Promise.all 实现 Promise.allSettled 效果
const p1 = new Promise((resolve, reject) => reject(1))
const p2 = new Promise((resolve) => resolve(2))
const p3 = new Promise((resolve, reject) => reject(3))
x = promiseList => promiseList.map(promise => promise.then(result => ({status: 'ok', value: result}),reason => ({status: 'not ok', reason}) ))
Promise.all(x([p1, p2, p3])).then(res => console.log(res, 'res...'))
// {status: 'not ok', reason: 1}
// {status: 'ok', value: 2}
// {status: 'not ok', reason: 3}
Promise.race()
-
Promise.race()
方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例
const p = Promise.race([p1, p2, p3]);
// 只要`p1`、`p2`、`p3`之中有一个实例率先改变状态,`p`的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给`p`的回调函数
const p1 = new Promise((resolve, reject) => reject(1))
const p2 = new Promise((resolve) => resolve(2))
const p3 = new Promise((resolve, reject) => reject(3))
Promise.race([p1, p2, p3]).then(res => {
console.log(res, 'res')
}).catch(reason => {
console.log(reason, 'reason') // 1, p1 先改变状态, 是 Promise 实例的返回值
})
Promise.any()
方法接受一组 Promise 实例作为参数,包装成一个新的 Promise 实例返回
- 只要参数实例有一个变成
fulfilled
状态,包装实例就会变成fulfilled
状态;如果所有参数实例都变成rejected
状态,包装实例就会变成rejected
状态
// `Promise.any()`不会因为某个 Promise 变成`rejected`状态而结束
const p1 = new Promise((resolve, reject) => reject(1))
const p2 = new Promise((resolve) => resolve(2))
const p3 = new Promise((resolve, reject) => reject(3))
Promise.any([p1, p2, p3]).then(res => {
console.log(res) // 2 成功的
})
---
const p1 = new Promise((resolve, reject) => reject(1))
const p2 = new Promise((resolve, reject) => reject(2))
const p3 = new Promise((resolve, reject) => reject(3))
Promise.any([p1, p2, p3]).then(res => {
console.log(res)
})
// 返回 rejected
[[Prototype]]: Promise
[[PromiseState]]: "rejected"
[[PromiseResult]]: AggregateError: All promises were rejected
- 就是
Promise.any()
不会因为某个 Promise 变成rejected
状态而结束,必须等到所有参数 Promise 变成rejected
状态才会结束
Promise.resolve()
有时需要将现有对象转为 Promise 对象,
Promise.resolve()
方法就起到这个作用
-
参数是一个
Promise
实例- 如果参数是 Promise 实例,那么
Promise.resolve
将不做任何修改、原封不动地返回这个实例
- 如果参数是 Promise 实例,那么
-
参数是一个
thenable
对象-
thenable
对象指的是具有then
方法的对象 -
Promise.resolve()
方法会将这个对象转为Promise
对象,然后就立即执行thenable
对象的then()
方法
let thenable = { then: function(resolve, reject) { resolve(42); } }; let p1 = Promise.resolve(thenable); p1.then(function (value) { console.log(value); // 42 });
-
-
参数是一个原始值
-
Promise.resolve()
方法返回一个新的 Promise 对象,状态为resolved
const p = Promise.resolve('Hello'); p.then(function (s) { console.log(s) }); // Hello
-
-
不带有任何参数
-
Promise.resolve()
方法允许调用时不带参数,直接返回一个resolved
状态的 Promise 对象
// 立即`resolve()`的 Promise 对象,是在本轮“事件循环”(event loop)的结束时执行,而不是在下一轮“事件循环”的开始时 setTimeout(function () { console.log('three'); }, 0); Promise.resolve().then(function () { console.log('two'); }); console.log('one'); // one // two // three
-
Promise.reject()
Promise.reject(reason)
方法也会返回一个新的 Promise 实例,该实例的状态为rejected
const p = Promise.reject('出错了');
// 等同于
const p = new Promise((resolve, reject) => reject('出错了'))
p.then(null, function (s) {
console.log(s)
});
// 出错了
Promise.try()
Promise.try
为所有操作提供了统一的处理机制,所以如果想用then
方法管理流程,最好都用Promise.try
包装一下
try {
database.users.get({id: userId})
.then(...)
.catch(...)
} catch (e) {
// ...
}
// 上面的方法看起来很笨拙, 可以统一用`promise.catch()`捕获所有同步和异步的错误
Promise.try(() => database.users.get({id: userId}))
.then(...)
.catch(...)
// `Promise.try`就是模拟`try`代码块,就像`promise.catch`模拟的是`catch`代码块
网友评论