Promise是ES6提供的一种异步解决方案, 它容许将写法复杂的传统回调函数和监听事件的异步操做, 用同步代码的形式将结果传达出来. 从本意讲, promise表示承诺, 就是承诺必定时间处理异步(也可同步)以后会给你一个结果, 而且这个结果会根据状况有着不一样的状态.javascript
例子:java
function fn1(value, callback) {
setTimeout(() => {
let a = 1
for(let i = 1; i <= value; i++) {
a *= i
callback(a)
}
}, )
}
fn1(10000000, function(result) => {
console.log(result)
})
复制代码
上面代码是先进行阶乘运算, 计算完后执行callback
回调. 假如为了获得10000000
的的阶乘, 由于运算量大, 不让他阻塞js, 使其在异步中执行, 所以须要同回调来获得结果.数组
可是此时又须要将这个结果在fn2
函数中作一些减法处理:promise
function fn2(value, callback) {
setTimeout(() => {
const b = value - 1 - 2 - 3 - 4 - 1000
callback(b)
}, 100)
}
fn1(10000000, function(result1) => {
fn2(result1, function(result2) => {
console.log(result)
})
})
复制代码
而后须要在fn3
函数中作一些乘法处理, 在fn4
函数中作一些加法处理...fn5 fn6 fn7...fn100
........bash
function fn3(value, callback) {
// value = x*x*123...
callback(value)
}
function fn4(value, callback) {
// value = x+x+123...
callback(value)
}
fn1(10000000, function(result1) => {
fn2(result1, function(result2) => {
fn3(result2, function(result3) => {
fn4(result3, function(result4) => {
...
fn100(result99, function(result100) => {
console.log(result)
})
})
})
})
})
复制代码
经过一百次回调获得最终结果...就成了回调地狱, 真实状况虽然没有这么多层级, 可是每个处理函数
的内容也不可能这么简单, 到时候确定很臃肿不美观, 说不定其中的某个回调的结果在哪里都找不到(result1, result2, result3...)...并发
Promise表示承诺, 它也会像回调函数同样, 承诺一个结果, 可是这个结果会根据promise的状态经过不一样的方式(成功或者失败
)传递出来.异步
回调的弊端:async
Promise能解决两个问题:函数
回调地狱, 它能经过函数链式调用方式来执行异步而后处理结果, 使得代码逻辑书写起来像同步ui
支持并发, 好比说获取多个并发请求的结果
Promise是一个构造函数, 经过new Promise
的方式获得一个实例对象, 建立时接受一个执行函数
(下面简称 fn )做为参数, 这个执行函数也同时也有两个形参resolve
, reject
const promise = new Promise((resolve, reject) => {
// ...do something asynchronous
// resolve sth or reject sth
})
复制代码
promise自己有三种状态:
Promise是一个构造函数, 他须要经过 new
实例化来使用, 实例化的同时 Promise内部的状态为初始的 pending
fn
表示传入一个回调函数, 它会被Promise内部传入两个参数 resolve
, reject
当fn内部的代码执行resolve 或者 reject时, 它的内部的状态都会变化
与 resolve reject 对应的状态为
resolve -> fulfilled
reject -> rejected
复制代码
一旦promise被resolve或者reject, 不能再迁移到其余任何状态
基本过程:
上述能够先不用管, 先来看看用法
当resolve(成功)/reject(失败)时
的回调函数promise.then(fulfilled, rejected)
// fulfilled 是promise执行当resolve 成功时的回调
// rejected 是promise执行当reject 失败时的回调
复制代码
当 fn 内部执行 resolve 方法时(此时的Promise内部状态为 resolved
), 能够传入一个参数 value
, 便会执行 then 中的 fulfilled 回调, 并把 value
做为参数值传入,
const promise = new Promise((resolve, reject) => {
let value = 1 + 1
resolve(value)
}).then(function(res) {
console.log(res) // --> 2 , 这里的 res 就是resolve传入的 value
})
复制代码
同理 reject 也同样 不一样之处在于, 须要在then中多传入一个执行回调:
const promise = new Promise((resolve, reject) => {
let value = 1 + 1
reject(value)
})
.then(function(res) {
console.log(res) // fulfilled 不会被调用
}, function(err) {
console.log(err) // 2
})
复制代码
上面代码中, fn
代码 执行了 reject
, 此时的Promise内部状态为 rejected
. 所以就会只执行then中的第二个执行回调(rejected), 一样 reject
接受一个 value 参数 传给 下一个then 中的 rejected
执行后续错误的回调
链式调用写法中能够捕获前面的 then 中 resolved 回调发生的异常
promise.catch(rejected)
// 至关于
promise.then(null, rejected)
// 注意: rejected 不能捕获当前 同一层级fulfilled 中的异常
promise.then(fulfilled, rejected)
// 能够写成:
promise.then(fulfilled)
.catch(rejected)
复制代码
当 fullfill中发生错误时:
const promise = new Promise((res, rej) => {
res(1)
})
.then(res => {
let a = 1
return res + a.b.c
})
.then(res => {
return res + 1
}, err => {
// 会捕获上一级的错误
console.log(err) // Cannot read property 'c' of undefined
})
复制代码
const promise = new Promise((res, rej) => {
res(1)
}).then(res => {
let a = 1
return res + a.b.c
}).then(res => {
return res + 1
}).then(res=> {
console.log(res)
}).catch(err => {
// 上面任何一级发生错误 最终都会转入catch
console.log(err) // TypeError: Cannot read property 'c' of undefined
})
复制代码
上述故意让代码发生错误(a.b.c
), 就会转到catch函数, 中间不管有多少个 then 都不会执行, 除非 then 中传入了失败的回调:
const promise = new Promise((res, rej) => {
res(1)
})
.then(res => {
let a = 1
return res + a.b.c
})
.then(res => {
return res + 1
}, err => { // 这里会被先捕获
console.log(err) // TypeError: Cannot read property 'c' of undefined
})
.then(res=> {
console.log(res)
}).catch(err => {
// 已经被上面的 rejected 回调捕获 就不会执行 catch 了
console.log(err)
})
复制代码
promise.then方法每次调用 都返回一个新的promise对象 因此能够链式写法
复制代码
function taskA() {
console.log("Task A")
}
function taskB() {
console.log("Task B")
}
function rejected(error) {
console.log("Catch Error: A or B", error)
}
var promise = Promise.resolve()
promise
.then(taskA)
.then(taskB)
.catch(rejected) // 捕获前面then方法中的异常
复制代码
须要注意的是 当then执行 rejected
回调后 传入的 参数会被 下一级 的 resolved
执行回调接受 而不是 rejected
:
const promise = new Promise((res, rej) => {
res(1)
})
.then(res => {
let a = 1
return res + a.b.c
})
.then(res => {
return res + 1
}, err => {
console.log(err) // 这里捕获到错误后, 返回的值 仍然是会被 下一级 then 中的 resolved 执行回调 接收
return 'dz'
})
.then(res=> {
console.log(res) // dz
}, err => {
console.log(err)
})
复制代码
Promise.resolve('dz').then(res => { console.log(res) })// --> dz
// 至关于
new Promise((resolve) => {resolve('dz')}).then(res => { console.log(res) }) // --> dz
复制代码
只有每一个promise对象状态`都为resolve`才会调用, 一般用来处理多个并行异步操做
复制代码
const p1 = Promise.resolve('dz1')
const p2 = Promise.resolve('dz2')
const p3 = Promise.resolve('dz3')
Promise.all([p1, p2 , p3]).then(res => {
console.log(res) // --> ['dz1', 'dz2', 'dz3'], 结果与数组中的promise返回的结果顺序一致
})
复制代码
Promise.race只要其中某个元素先进入 fulfilled 或者 rejected 状态就会进行后面的处理(执行then)
复制代码
function timer(delay) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(delay)
}, delay)
})
}
Promise.race([
timer(10),
timer(20),
timer(30),
]).then(res => { console.log(res) }) // -> 10
复制代码
不管Promise返回的结果是什么都会执行 finally
而且 不会改变 Promise 的状态
Promise.resolve(1).finally(()=>{})
Promise.reject(1) .finally(()=>{})
复制代码