其实,我对 promise
了解的很差,所以,这篇博文也会继续完善。
在这里,我就以例子为主。
参考资料
回调地狱
promise 设计的一个目的就是解决回调地狱的。
1 2 3 4 5 6 7 8 9
| ajaxA(function( ){ ajaxB(function( ){ ajaxC(function( ){ ajaxD(function( ){ ...... }); }); }); })
|
promise 用法
状态
- 待定(pending): 初始状态,既没有被兑现,也没有被拒绝。
- 已兑现(fulfilled): 意味着操作成功完成。
- 已拒绝(rejected): 意味着操作失败。
状态不可逆转。
因为 Promise.prototype.then
和 Promise.prototype.catch
方法返回的是 promise
, 所以它们可以被链式调用。
案例介绍
链式调用 有 resolve()
1 2 3 4 5 6 7 8 9 10
| new Promise(function (resolve, reject) { console.log(1) resolve() }).then(function () { console.log(2) }).then(function () { console.log(3) })
console.log(777)
|
输出
链式调用 无 resolve()
1 2 3 4 5 6 7 8 9
| new Promise(function (resolve, reject) { console.log(1) }).then(function () { console.log(2) }).then(function () { console.log(3) })
console.log(777)
|
输出
这里的 resolve
起到的是通知作用。
这其实就是在通知 Promise
,当前这个函数结束啦。
你可以开始执行下一个。 这时Promise
就会去执行then
里面的函数了。
resolve
函数, 就好像一个对讲机,当我们的异步任务要结束时,通过对讲机 来通知Promise
对象。所以这个resolve
函数,必须在异步任务的最后调用(例如ajax
的回调方法),相当于告诉Promise
对象,该任务结束,请开始下一个。
异步调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| new Promise(function (resolve, reject) { axios.get("https://www.baidu.com").then((res) => { console.log(1) resolve("XXX") }) }).then(function (data) { console.log(data) }).then(function () { console.log(2) }).then(function () { console.log(3) }).then(function () { console.log(4) })
console.log(777)
|
输出
这个异步调用很好理解。
异步调用中的异步调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| new Promise(function (resolve, reject) { axios.get("https://www.baidu.com").then((res) => { console.log(1) resolve("XXX") }) }).then(function (data) { axios.get("https://www.baidu.com").then((res) => { console.log(2) }) }).then(function () { console.log(3) }).then(function () { console.log(4) }).then(function () { console.log(5) })
console.log(777)
|
输出
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| new Promise(function (resolve, reject) { axios.get("https://www.baidu.com").then((res) => { console.log(1) resolve("XXX") }) }).then(function (data) { axios.get("https://www.baidu.com").then((res) => { console.log(2) }) }).then(function () { axios.get("https://www.baidu.com").then((res) => { console.log(3) }) }).then(function () { console.log(4) }).then(function () { console.log(5) })
console.log(777)
|
输出
之所以是这个顺序,是因为 promise
还涉及到让出线程的概念,这个下面给说。
这里,我想让顺序输出是
可以这样修改
异步调用中的顺序执行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| new Promise(function (resolve, reject) { axios.get("https://www.baidu.com").then((res) => { console.log(1) resolve("XXX") }) }).then(function (data) { return new Promise(function (resolve, reject) { axios.get("https://www.baidu.com").then((res) => { console.log(2) resolve() }) }) }).then(function () { axios.get("https://www.baidu.com").then((res) => { console.log(3) }) }).then(function () { console.log(4) }).then(function () { console.log(5) })
console.log(777)
|
输出
通过上述编写,就可以异步也能同步执行,但是,具体的原理目前还没搞懂。
异常编写
resolve
是成功返回,然后调用成功方法。
reject
是异常返回,然后调用异常捕获方法。
在 promise
的 then
中完整版本是
1 2 3 4 5 6 7
| p.then(onFulfilled[, onRejected]);
p.then(value => { }, reason => { });
|
即,then
的传入参数是两个方法,其中 第一个是 resolve()
调用,第二个是 reject()
调用。
1 2 3 4 5 6 7 8 9 10 11
| new Promise(function (resolve, reject) { axios.get("https://www.baidu.com").then((res) => { resolve() }).catch((reason => { reject() })) }).then((value) => {
}, (reason) => { console.log(123) })
|
输出
把网关掉,由于没有网络就会调用 reject() 然后触发 then 后面的 onRjected 函数。
1 2 3 4 5 6 7 8 9
| new Promise(function (resolve, reject) { axios.get("https://www.baidu.com").then((res) => { reject() }) }).then((value) => {
}, (reason) => { console.log(123) })
|
同样输出
异常的链式执行
1 2 3 4 5 6 7 8 9 10 11
| new Promise(function (resolve, reject) { axios.get("https://www.baidu.com").then((res) => { reject() }) }).then((value) => {
}, (reason) => { console.log(123) }).then((value) =>{ console.log(234) })
|
输出
也就是,执行完 reject
后,依然会正常执行下面的 then
。 可以参考上面的图来查看。
其他方法
all
如果我有 A
,B
,C
三个异步任务,ABC
同时开始执行
当A,B,C
三个任务全部都结束时,执任务D
,
传统方法实现起来就比较复杂,Promise
就非常简单,就像这样:
1 2 3 4
| Promise.all([new Promise(A), new Promise(B), new Promise(C)]) .then(function(){ D(); });
|
race
那如果我希望 A
, B
, C
其中任意一个任务完成,
就马上开始任务 D
,该怎么做?
1 2 3 4
| Promise.race([new Promise(A), new Promise(B), new Promise(C)]) .then(function(){ D(); });
|
强制顺序同步
第一个例子中
1 2 3 4 5 6 7 8 9 10
| new Promise(function (resolve, reject) { console.log(1) resolve() }).then(function () { console.log(2) }).then(function () { console.log(3) })
console.log(777)
|
输出
我如果想执行完 1,2,3 后再执行 777 呢。
那可以借助上面的 all 还有 async/await。