参考链接:JavaScript Promise:简介
Promise 是一个解决异步操作的对象。 常见的的异步实现方案,就是「回调」。 回调是很好的异步解决方案,不过「嵌套多了」就惹得心烦,且代码难以阅读,不直观。 Promise 并非解决具体问题的算法,而已代码组织更好的模式。 我们也可以实现类似 Promise 的结构,比如 jQuery 的 ajax 「$.ajax 」。
一个简单的例子 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 const imageLoad = url => new Promise ((resolve, reject ) => { const image = new Image() image.onload = function ( ) { resolve('加载成功' ) } image.onerror = function ( ) { reject(new Error ('加载失败' )) } image.src = url }) imageLoad('https://avatars3.githubusercontent.com/u/9067839?s=460&v=4' ) .then( success => console .log(success), error => console .log(error) )
认真看了上面的典型的简单的 Promise 例子,开发者应该对 Promise 不陌生了,至少对 then 方法不陌 😆 下面,进一步揭开 Promise 的面纱
Promise 实例的状态 每个 Promise 实例都有一个状态,初始为 Pending
resolve 方法可以将 Pending 改为 Resolved
reject 方法可以将 Pending 改为 Rejected
注意:没有其他方式可以修改 Promise 实例的状态,且状态不可逆
Promise 原型链方法
原型链方法又称实例方法
Promise.prototype.then()
then 方法接受2个函数参数,第一个函数参数将状态变为 Resolved
,调用第二个函数参数将状态变为 Rejected
then 方法内部 return 详解: 如果 then 方法内部 return 的不是一个 Promise
对象 那么 return 的值将作为下一个 then 的形参 如果没有 return 语句,等同于 return undefined 如果 then 方法内部 return 是一个 Promise
对象,那么下一个 then 的形参就是这个 Promise 对象执行方法的实参 文字有点绕,不是很好理解,请看看如下代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 function newPromise ( ) { return new Promise (resolve => resolve('I was resolved' )) } new Promise (resolve => { resolve() }) .then(() => { return '我只是一个字符串' }) .then(_data => { console .log(_data) }) .then(_data => { console .log(_data) return newPromise() }) .then(_data => { console .log(_data) })
Promise.prototype.catch()
catch 与 then 一样,返回值是 新的 Promise 对象 我们知道, then 的第二个函数参数,可以看做捕获错误的方法 我们还知道 then 可以链式调用 试想一下,当链式调用多个 then 方法时,难道要写多个错误处理方法,不会显得臃肿么 那么, catch 方法就是为此而生 所以, catch 方法可以充当 then 方法的第二个函数参数,并且建议使用 catch 方法 请看下面的详细分析
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 new Promise (resolve => { resolve(msg) }) .then(_data => console .log(_data)) .catch(_error => console .log(_error)) new Promise (resolve => { resolve(msg) }) .catch(_error => console .log(_error)) .then(_data => console .log(_data)) new Promise (resolve => { resolve('OK' ) }) .then(_data => { var test = unnamed }) .catch(_error => console .log(_error)) new Promise (resolve => { resolve('OK' ) }) .then(_data => { console .log(_data) var test = unnamed_one }) .catch(_error => { console .log(_error) var test = unnamed_two }) .catch(_error => console .log(_error))
看过上面的代码分析后,至少可以总结出: Promise 错误具有冒泡性质,错误会不断的向后传递,直到 .catch() 捕获 如果 then 方法遇到没有捕获的储物,就不会执行
还有:catch 方法是then(null, rejection)
的别名(如下代码)
1 2 3 4 5 6 7 8 9 Promise .resolve() .then(_success => console .log(_success)) .catch(_error => console .log(_error)) Promise .resolve() .then(_success => console .log(_success)) .then(null , _error => console .log(_error))
注意:catch 不能捕获异步错误
,请看如下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 let _promise1 = () => new Promise (() => { throw new TypeError ('I am a error' ) }), _promise2 = () => new Promise (() => { setTimeout(() => { throw new TypeError ('I am a error' ) }, 0 ) }), _promise3 = () => new Promise ((resolve, reject ) => { setTimeout(() => { reject('I am a error' ) }, 0 ) }) _promise1() .catch(_error => console .log(_error)) _promise2() .catch(_error => console .log(_error)) _promise3() .catch(_error => console .log(_error))
Promise 的静态方法 Promise.resolve(param)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 let thenable = { then: function (resolve, reject ) { resolve('I was resolved' ) } } var _promise = Promise .resolve(thenable)_promise.then(_data => console .log(_data)) var _promise = Promise .resolve('I am promise' )_promise.then(_data => console .log(_data))
Promise.reject()
和Promise.resolve()
一样,只是返回的 Promise 实例的状态为rejected
即使传入的参数是状态为 resolved 的 Promise 实例,返回的实例状态依旧是rejected
1 2 3 4 5 var _promise = Promise .reject('error' )_promise.catch(_errpr => console .log('I am error' ))
Promise.all()
all
方法可以接受一个具有 Iterator 接口的对象(一般为数组),且返回的每个成员都是 Promise 实例all
方法依旧返回一个新的 Promise 实例 当参数的所有 Promise 实例都为resolved
时, all 方法才返回resolved
,反之则然
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 let _promise = _value => new Promise ((resolve, reject ) => { setTimeout(_value => { if (/^resolve/ .test(_value)) { resolve(_value) return } reject(_value) }, 1000 , _value) }) Promise .all([_promise('resolveOne' ), _promise('resolveTwo' )]) .then(_success => console .log(_success)) .catch(_error => console .log(_error)) Promise .all([_promise('resolveOne' ), _promise('rejectOne' )]) .then(_success => console .log(_success)) .catch(_error => console .log(_error))
Promise.race()
race 方法和 all 方法用法一模一样,只是返回值有点差别 从字面理解就能看出来, race 是比赛的意思 说明参数实例谁先状态发送改变就调用谁
1 2 3 4 5 6 7 8 9 10 11 12 let _promise = (_time, _value ) => new Promise ((resolve, reject ) => { setTimeout(() => resolve(_value), _time) }) Promise .race([_promise(2000 , 'resolveSlow' ), _promise(1000 , 'resolveFast' )]) .then(_success => console .log(_success))
Promise 总结 Promise 可以看做是回调函数的改进方案,解决了 callback 的回调深渊 使用 then 可以让异步操作更加清晰明了 不过原来的异步任务被 Promise 包装后,不管什么操作,放眼望去都是 then ,这导致原来的语义变得不那么清楚