再看Promise
Time: 2019-08-21
回调函数
是一种事件机制,某种事件完成后,会触发相应的回调函数。
Promise是什么
这是一种对异步回调函数的替代方式。Promise是一种对象。
用回调的方式写loadJSON
函数是下面这样:
loadJSON(url, callback)
其中callback
函数还可以继续带上其他的回调函数,如此多个,称之为回调地狱。
换成Promise
的写法是:
let promise = fetch(url);
fetch
函数会返回一个Promise
对象,一旦得到Promise对象,我们就可以进而做很多事情。
Promise对象的几种状态
- pending
- fulfilled/resolved
- rejected
我们可以检查Promise
对象的状态,可以多次检查这个状态。和事件相比,错过了事件监听就是错过了,但是Promise
正如名称讲到的一样,是一种承诺,状态是确定的。其中,Promise
对象的状态会有两种流转方式:
- pending -> fulfilled/resolved
- pending -> rejected
且状态切换之后是不可逆的。
Q: 如何触发Promise对象的状态切换?
两大函数
- .then(),当对象的状态是fulfilled/resolved时
- .catch(),当对象的状态是rejected时
Promise对象是如何构建起来的?
两种方式:
- 主动构建
- 使用某种函数后会返回这个对象,如
fetch
下面是个例子:
let url = 'http://defi.sher.vip/company/listBlacklist'
const gotData = (data) => {
console.log("获取数据结果:", data) // 获取的是一个Response对象,需要解析这个对象
}
const gotError = (error) => {
console.log(error)
}
let promise = fetch(url)
promise.then(gotData)
promise.catch(gotError)
这样做打印出来是个Response
对象,但还没有真的获取到我们需要的数据。
在此之前,我们先看如何写成标准的写法:
fetch(url)
.then(
data => {
console.log("获取数据结果:", data)
})
.catch(
err => {
console.log("错误信息:", err)
}
)
使用链式调用和箭头函数来减少代码量。
可以再简化:
fetch(url)
.then( data => console.log("获取数据结果:", data))
.catch( err => console.log("错误信息:", err))
这三行代码表示的是,fetch(url)
返回一个Promise
对象,然后从pending
进入到fulfilled/resolved
状态后,执行.then
中的代码,参数data
是Promise
返回的Response
对象。
从pending
进入到rejected
状态时,执行.catch
中的代码,参数err
表示返回的错误。
现在问题来了,如何取出真实的数据?进入到关于fetch
函数的funny的部分了。
开始以为data.json()
就可以拿到数据了,其实呢,还是一个Promise
对象。
也就是需要再次.then()
拿出需要的数据。
一种天真但错误的写法:
const res = await fetch(url).then(
response => response.json()
).then(
json
)
这会告诉我们json
未定义,也就是then
中接收的是函数,不管是普通函数还是箭头函数都可以。
注意response => response.json()
是简单写法,实际上是return response.json()
,返回的是Promise
对象。
可以简化为:
屏幕快照 2019-08-22 下午9.01.17.png其中在第二个then
后的return fetch(...)
很重要。
手动构建Promise对象
function delay(time) {
return new Promise((resolve, reject) => {
// 可以加一些判断条件
if (isNaN(time)) {
reject()
}
setTimeout(resolve, time)
})
delay(1000).then(() => console.log("Hello"))
}
这样调用delay
函数会返回一个Promise对象,并且成功后执行打印函数,相当于用自定义的箭头函数代替了resolve
函数。