谈到JavaScript相信它的事件回调大家肯定都听过。即使只有一个执行线程,它也能处理异步高并发。
同样很多人回调写多了都不可避免的会变成**Callback Hell(回调地狱)**,这样的代码会非常复杂难懂,因为回调不像同步代码,它的执行顺序不是从上至下的,读回调代码必须反复横跳,思考什么情况下回跳到什么地方。
Promise就是一种异步编程,很早就有了随着ES6的发布Promise也成了JavaScript原生支持的对象,但学校这学期的课程并没有相关章节。因此顺便学习下Promise对象的使用。
以JavaScript原生的AJAX为栗子,AJAX的请求形式如下:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 
 | function ajax(url, callback) {let xhr = new XMLHttpRequest()
 xhr.open('GET', url)
 xhr.send()
 xhr.onload = function() {
 if (this.status == 200) {
 callback(JSON.parse(this.response))
 } else {
 throw new Error("加载失败")
 }
 }
 }
 
 | 
我们就以此方式依次请求三个接口(地址),假设响应体的JSON格式是{id: 1, name: "farmer"}, JS代码如下:  
| 12
 3
 4
 5
 6
 7
 8
 
 | ajax('http://127.0.0.1:5003/?name=farmer', (user) => {
 ajax('http://127.0.0.1:5003/?name=' + user.name, (e) => {
 ajax('http://127.0.0.1:5003/?name=' + user.name, (e) => {
 console.log(e)
 })
 })
 })
 
 | 
是不是觉得嵌套很多? 如果连续请求更多的地址,那嵌套就要看傻了。 接下来我们试试用Promise对象对ajax进行封装,看看效果怎么样。 代码如下:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 
 | function ajax(url) {return new Promise((resolve, reject) => {
 let xhr = new XMLHttpRequest()
 xhr.open('GET', url)
 xhr.send()
 xhr.onload = function () {
 if (this.status == 200) {
 resolve(JSON.parse(this.response))
 } else {
 reject("加载失败")
 }
 }
 xhr.onerror = function () {
 reject(this)
 }
 })
 }
 
 | 
上例中,我们自己封装的AJAX会返回一个“Promise”对象,初始化该对象时我们要传入一个函数,这个函数又接受两个回调函数作为参数,分别是resolve和reject。resolve就是你操作成功时调用的方法,reject就是失败时调用的。接下来让我们同样实现前面三个接口的功能:  
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 
 | let url = "http://127.0.0.1:5003/"ajax(`${url}?name=xiaotao`).then(
 value =>{
 
 return ajax(`${url}?name=` + value.name)
 }
 ).then(value =>{
 return ajax(`${url}?name=` + value.name)
 }).then(
 value => console.log(value),
 reason => console.log(reason)
 )
 
 | 
大家是不是发现,本来长长的嵌套,变成了顺序执行的代码了? 到此就是Promise的简单探讨了。 如果你对上面的栗子还不太清楚,那下面是一些Promise对象更基础、详细的解释or栗子。希望能帮到你~😃
Promise怎么用?
相信刚接触Promise的童鞋都比较迷惑,到底应该怎么用Promise。其实上面有提到过,初始化该对象时我们要传入一个函数(我这里使用的是匿名函数),这个函数又接受两个回调函数作为参数(这里读起来比较拗口,可以和下面的栗子结合起来看),分别是resolve和reject。resolve就是你操作成功时调用的方法,reject就是失败时调用的
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 
 | 
 new Promise((resolve, reject) => {
 
 resolve("成功状态")
 
 }).then(
 
 
 value => {
 
 console.log("成功业务处理-1")
 },
 reason => {
 
 console.log('失败(拒绝)的业务处理-1')
 }
 ).then(
 value => console.log("成功业务处理-2"),
 reason => console.log('失败(拒绝)的业务处理-2')
 
 
 
 
 )
 
 | 
Then的更多用法
我们从上面的栗子可以看到,then函数也有两个参数,也是一个成功一个失败。其实then也是一个Promise。
但从上面的栗子也可以发现,第二个then无论前一个then是哪个参数处理的,都只会出发成功状态。如果我们想让第二个then的失败处理也能生效,我们应该将代码改成下面这样:
| 12
 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 p1 = new Promise((resolve, reject) => {resolve('fulfilled')
 })
 
 let p2 = p1.then(
 value => {
 console.log(value)
 
 
 
 return new Promise((resolve, reject) => {
 
 reject("Then 解决失败")
 })
 },
 reason => {
 console.log(reason)
 return new Promise((resolve, reject) => {
 
 reject("Then 解决失败")
 })
 }
 ).then(
 value => {
 console.log(value)
 },
 reason => console.log(reason)
 )
 
 | 
当第一个then返回一个Promise对象后,第二个then就能根据前一个then返回的Promise的状态进行处理。
总结
关于Promise一些更深层次的理论这里就不探讨了,网上资料很多,大家可以去搜索下。本文中的示例代码可以在这里下载。