promise - lucky0604/web-development GitHub Wiki
Promise
Promise三种状态
- Pending
unresolved
,即不是resolve
也不是reject
状态,属于Promise
实例刚创建的初始化状态。 - Fulfilled
has-resolution
,成功(resolve)
时,此时会调用onFulfilled
- Rejected
has-rejection
,失败(reject)
时,此时会调用onRejected
Tips:
Promise
对象的状态,从Pending
转换为Fulfilled
或Rejected
之后,这个对象的状态就不会再发生任何变化,即,在.then()
后执行的函数只会被调用一次。Fulfilled
和Rejected
这两个中的任一状态都可以表示为不变的Settled
创建Promise实例的快捷方式
Promise.resolve
可以认为静态方法Promise.resolve(value)
是new Promise()
的快捷方式,比如Promise.resolve(1)
可以认为是下面代码的语法糖:
new Promise(function(resolve) {
resolve(1)
})
其中resolve(1)
会让promise
实例对象直接进入resolve
状态,并将1传递给后面将要调用的.then()
方法里所指定的onFulfilled
函数。
Tips:
Promise.resolve(value)
返回值是一个promise对象
,因此可以直接对其进行.then()
调用
另一个作用
Promise.resolve
方法另外一个作用是将thenable
对象转换成promise
对象
thenable: 带有
then
的方法
可以认为Promise.resolve
的作用就是将传递给它的参数填充(Fulfilled)
到promise
对象后并返回这个promise
对象
Promise.reject
Promise.reject(error)
和Promise.resolve(value)
是类似的静态方法,也是创建Promise
实例的快捷方式
即Promise.reject(error)
方法等同于
new Promise(function(resolve, reject) {
reject(new Error('Error'))
})
Promise chain
当promise
对象的方法链长度变得很长时:
function taskA() {
console.log('Task A')
}
function taskB() {
console.log('Task B')
}
function onRejected(error) {
console.log('Catch error: A or B', error)
}
function finalTask() {
console.log('Final Task')
}
var promise = Promise.resolve()
promise.then(taskA)
.then(taskB)
.catch(onRejected)
.then(finalTask)
上面代码没有为then
方法指定第二个参数,所以可以理解为:
then
注册onFulfilled
时的回调函数catch
注册onRejected
时的回调函数
在taskA
或taskB
的处理中,下面的情况会调用onRejected
方法
- 发生异常的时候
- 返回了一个
Rejected
状态的promise
对象
reject
而不是throw
使用当发生异常时,会被catch
捕获并被由在此函数注册的回调函数进行错误处理。
另外一种异常处理策略是通过返回一个Rejected
状态的promise
对象来实现,这种方法不通过使用throw new Error()
就能在promise chain
中对onRejected
进行调用。
function taskA() {
console.log('Task A')
throw new Error('throw Error at Task A')
}
function taskB() {
console.log('Task B')
}
function onRejected(error) {
console.log(error)
}
function finalTask() {
console.log('Final Task')
}
var promise = Promise.resolve()
promise.then(taskA)
.then(taskB)
.catch(onRejected)
.then(finalTask)
这里在taskA
中使用throw
方法故意制造了一个异常,但在实际中想主动进行onRejected
调用时,应该返回一个Rejected
状态的promise
对象。
Promise
的构造函数,以及被then
调用执行的函数基本上都可以认为是在try...catch
代码块中执行的,所以在这些代码中即使使用throw
,程序本身也不会因为异常而终止。
如果在Promise
中使用throw
语句的话,会被try...catch
住,最终promise
对象也变为Rejected
状态
var promise = new Promise(function(resolve, reject) {
throw new Error('message')
})
promise.catch(function(error) {
console.error(error) // output: 'message'
})
代码运行时不会出现问题,但是如果想把promise对象状态
设置为Rejected
状态,使用reject
方法则更显得合理
var promise = new Promise(function(resolve, reject) {
reject(new Error('message'))
})
promise.catch(function(error) {
console.error(error) // output: 'message'
})
promise chain
中传递参数
上面代码中,task都是相互独立,只是被简单调用,此时若需要taskA
给taskB
传递一个参数,即在taskA
中return
的返回值,会在taskB
执行时传递给它
function doubleUp(value) {
return value * 2
}
function increment(value) {
return value + 1
}
function output(value) {
console.log(value)
}
var promise = Promise.resolve(1)
promise.then(increment)
.then(doubleUp)
.then(output)
.catch(function(error) {
// promise chain中出现异常的时候会被调用
console.error(error)
})
整体执行流程为:
Promise.resolve(1)
,传递1给increment
函数- 函数
increment
对接收的参数进行+1
操作并返回(通过return
) - 此时参数变为2,并再次传给
doubleUp
函数 - 最后在函数
output
中打印结果
每个方法中return
的值不仅只局限于字符串或者数值类型,也可以是对象或者promise
对象等复杂类型。
return
的值会由Promise.resolve(return的返回值)
,进行相应的包装处理,因此不管回调函数中会返回一个什么样的值,最终then
的结果都是返回一个新创建的promise
对象。
也就是说,
.then()
不仅仅是注册一个回调函数这么简单,还会将回调函数的返回值进行变换,创建并返回一个promise
对象
Promise.then()
处理多个异步请求
使用处理多个异步请求,Promise.all()
比较适合,这里故意采用大量.then()
的写法
function getUrl(URL) {
return new Promise(function(resolve, reject) {
var req = new XMLHttpRequest()
req.open('GET', URL, true)
req.onload = function() {
if (req.status === 200) {
resolve(req.responseText)
} else {
reject(new Error(req.statusText))
}
}
req.onerror = function() {
reject(new Error(req.statusText))
}
req.send()
})
}
var request = {
comment: function getComment() {
return getUrl('http://localhost').then(JSON.parse)
},
people: function getPeople() {
return getUrl('http://localhost').then(JSON.parse)
}
}
function main() {
function recordValue (results, value) {
results.push(value)
return results
}
// []用来保存初始化的值
var pushValue = recordValue.bind(null, [])
return request.comment().then(pushValue).then(request.people).then(pushValue)
}
main().then(function(value) {
console.log(value)
}).catch(function(error) {
console.error(error)
})
Promise.all()
Promise.all()
接收一个promise
对象的数组作为参数,当这个数组里所有promise
对象全部变为resolve
或reject
状态时,才会去调用.then()
方法
因此可以将上面代码改为:
function main() {
return Promise.all([request.comment(), request.people()])
}
main().then(function (value) {
console.log(value)
}).catch(function(error) {
console.log(error)
})
Promise.all()
的promise数组
并不是一个个的顺序执行,而是同时开始,并行执行。