Promise是什么
Promise是ECMAscript 6 原生提供的一个对象。用来解决回调地狱的问题,所谓回调地狱就是函数不断嵌套调用。Promise 对象用于表示一个异步操作的最终完成 (或失败)及其结果值。
Promise有什么用
传统的 Ajax 异步调用在需要多个操作的时候,会导致多个回调函数嵌套,导致代码不够 直观,就是常说的 Callback Hell。Promise可以解决这样的问题,Promise就是异步编程的一种解决方案。通过链式调用的方式来解决,也就是Promise完成当前异步操作后交给下一个Promise来继续完成异步操作。
Promise的三种状态
Promise有三种状态,表示异步操作的的状态,并且不受外界影响。
- pending:初始状态
- fulfilled:表示操作成功
- rejected:表示操作失败
只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。
Promise的创建
Promise是一个对象,所以使用new Promise()创建对象。
var p = new Promise((resolve, reject) => {
// 写异步处理的代码,如ajax
// 在异步操作结束后调用resolve或者reject传给下一个Promise的调用
// resolve(参数) 表示异步操作成功并把数据携带给下一个Promise
// reject(参数) 表示异步操作失败并把数据携带给下一个Promise
})
上面的代码通过 p.then()的方法实现链式调用,then里面继续传入一个Promise对象,并且then方法中可以接受resolve传过来的参数。而reject会被catch捕获,同样也可以在catch中得到reject传过来的参数。
Promise的基本使用
下面使用代码完成3次异步请求。首先看看使用$.ajax的方式如何完成。
首先在本地创建了3个json文件进行测试用
传统的ajax嵌套调用的代码
$.ajax({
url: "data/student_id_100.json",
success(res) {
console.log("第一次请求:", res)
$.ajax({
url: `data/class_id_10.json`,
success(res) {
console.log("第二次请求:", res)
$.ajax({
url: `data/school_id_9.json`,
success(res) {
console.log("第三次请求:", res)
},
error(err) {
console.log("第三次请求:", err)
}
})
},
error(err) {
console.log("第二次请求:", err)
}
})
},
error(err) {
console.log("第一次请求:", err)
}
})
可以发现已经开始出现大量的嵌套问题,并且上面代码才只有3次回调,如果更多,那么回调地狱的问题就会更明显。
Promise写法
let p = new Promise((resolve, reject) => {
$.ajax({
url: "data/student_id_100.json",
success(res) {
console.log("第一次请求:", res)
resolve(res)
},
error(err) {
reject(err)
}
})
}).then(resultData => {
return new Promise((resolve, reject) => {
$.ajax({
url: `data/class_id_10.json`,
success(res) {
console.log("第二次请求:", res)
resolve(res)
},
error(err) {
reject(err)
}
})
})
}).then(resultData => {
return new Promise((resolve, reject) => {
$.ajax({
url: `data/school_id_9.json`,
success(res) {
console.log("第三次请求:", res)
},
error(err) {
reject(err)
}
})
})
}).catch(err => {
console.log(err)
})
上面的Promise写法功能和第一个ajax嵌套调用实现的功能是一样的。通过.then的方法实现链式调用。.then里面的resultData这个参数就是resolve(参数)这个传过来的参数。而最后的catch就是捕捉所有的reject,err就是reject传过来的参数。
可以发现Promise的写法解决的回调地狱的问题,通过链式调用,但可以发现,在Promise里面有大量的重复代码,我们可以提取出来,形成一个函数,于是就有了下面的写法。
Promise的简洁写法
我们提取Promise的重复代码为一个get方法,通过调用这个方法来实现链式编程。
function get(url, data) {
return new Promise((resolve, reject) => {
$.ajax({
url: url,
data: data,
success(res) {
resolve(res)
},
error(err) {
reject(err)
}
})
})
}
get("data/student_id_100.json").then(resultData => {
console.log("第一次请求:", resultData)
return get(`data/class_id_10.json`)
}).then(resultData => {
console.log("第二次请求:", resultData)
return get(`data/school_id_9.json`)
}).then(resultData => {
console.log("第三次请求:", resultData)
}).catch(err => {
console.log(err)
})
可以发现,这样代码就非常简洁了,并且也解决的回调地狱的问题。