前言

在实际开发中,我们经常会在发送一个请求后,得到反馈,再进行一下次请求,再得到反馈,又再进行下一次请求,每次的代码都在ajax内部的success实现,这样看起来繁琐,容易造成数据通信堵塞。如何解决这个问题呢?这时我们就可以利用Promise来解决!

在开始深入学习Promise前,熟悉JS Event Loop的机制是非常有必要的,如果你对Event Loop还不熟悉,非常推荐你先阅读JavaScript之多线程和Event Loop这篇文章,会对你更好理解Promise执行顺序帮助很大!

什么是Promise?

Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。它由社区最早提出和实现,ES6 将其写进了语言标准,统一了用法,原生提供了Promise对象。

古人云:“君子一诺千金”,所谓Promise,正如其中文含义,简单说就是一个承诺,“承诺将来会执行”约定的事情。

从语法上说,Promise 是一个对象,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。

Promise也有一些缺点。首先,无法取消Promise,一旦新建它就会立即执行,无法中途取消。其次,如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。第三,当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。

约定
不同于“老式”的传入回调,在使用 Promise 时,会有以下约定:

在本轮 Javascript event loop(事件循环)运行完成之前,回调函数是不会被调用的。

  • 通过then()添加的回调函数总会被调用,即便它是在异步操作完成之后才被添加的函数。
  • 通过多次调用then(),可以添加多个回调函数,它们会按照插入顺序一个接一个独立执行。
  • 因此,Promise 最直接的好处就是链式调用(chaining)。

Promise的使用

一个Promise的三种状态
在开始使用Promise之前,我们首先需要了解Promise的三种状态:

pending: 初始状态,既不是成功,也不是失败状态。
fulfilled: 意味着操作成功完成。
rejected: 意味着操作失败。

pending 状态的 Promise 对象可能会变为fulfilled 状态并传递一个值给相应的状态处理方法,也可能变为失败状态(rejected)并传递失败信息。当其中任一种情况出现时,Promise 对象的 then 方法绑定的处理方法(handlers )就会被调用(then方法包含两个参数:onfulfilled 和 onrejected,它们都是 Function 类型。当Promise状态为fulfilled时,调用 then 的 onfulfilled 方法,当Promise状态为rejected时,调用 then 的 onrejected 方法, 所以在异步操作的完成和绑定处理方法之间不存在竞争)。

因为Promise.prototype.then和Promise.prototype.catch方法返回promise 对象, 所以它们可以被链式调用。

ES6之Promise实战,让你的多次请求更清晰_json

Promise实战

有这么个需求,根据查询某个用户的课程得分。

如下图,有三个json文件,首先请求用户获取用户,然后通用户id查询到其课程信息Id,然后根据课程Id,获取当前课程的得分

ES6之Promise实战,让你的多次请求更清晰_java_02


user.json:

{
"id": "1",
"name": "tom",
"age": 20
}

user_course_1.json

{
"id": "1",
"userId": "1",
"title": "java"
}

course_score_1.json

{
"id": "1",
"courseId": "1",
"score": 50
}

以前的实现方法

<script>
/**
* 1.查询当前用户信息
* 2.按照当前用户的id查出他的课程
* 3.按照当前课程id查询出分数
*/
$.ajax({
url:'mall-vue/src/views/demo/promise/user.json',
success(data){
$.ajax({
url:'mall-vue/src/views/demo/promise/user_coure_${data.id}.json',
success(data){
$.ajax({
url:'mall-vue/src/views/demo/promise/course_score_{data.id}.json',
success(data){
console.log(data.score)
},
error(err){

}
})
},
error(err){

}
})
},
error(err){

}
})

</script>

使用Promise实现

在每一次成功,才进行一下请求

const p = new Promise(function(resolve, reject) {
$.ajax({
url:'mall-vue/src/views/demo/promise/user.json',
success(data){
console.log("查询用户成功!=用户名称==", data.name)
resolve(data);
},
error(err){
reject(error);
}
})

p.then(function(data)){
return new Promise(function(resolve, reject) {
$.ajax({
url:'mall-vue/src/views/demo/promise/user_coure_${data.id}.json',
success(data){
console.log("查询课程成功!=课程名称==", data.title)
resolve(data);
},
error(err){
reject(error);
}
})
})

},function(error){

}

}).then(function(data){
$.ajax({
url:'mall-vue/src/views/demo/promise/course_score_{data.id}.json',
success(data){
console.log("查询分数成功!=分数==", data.score)
},
error(err){

}
})
})

将上述代码优化封装:

function get(url, data){
return new Promise((resolve, reject) => {
$.ajax({
url: url,
success(data){
resolve(data);
},
error(err){
reject(error);
}
})
})
}

得到简化版:

//上述代码简写:
get(`user.json`)
.then((data) => {
console.log("查询用户成功!=用户名称==", data)
return get(`user_course_${data.id}.json`)
})
.then((data) => {
console.log("查询课程成功!=课程名称==", data)
return get(`course_score_${data.id}.json`)
})
.then((data) => {
console.log("查询分数成功!=分数==", data)
})
.catch((err) => {
console.log("出现异常:", err)
})