谈到JavaScript相信它的事件回调大家肯定都听过。即使只有一个执行线程,它也能处理异步高并发。
同样很多人回调写多了都不可避免的会变成**Callback Hell(回调地狱)**,这样的代码会非常复杂难懂,因为回调不像同步代码,它的执行顺序不是从上至下的,读回调代码必须反复横跳,思考什么情况下回跳到什么地方。
Promise就是一种异步编程,很早就有了随着ES6的发布Promise也成了JavaScript原生支持的对象,但学校这学期的课程并没有相关章节。因此顺便学习下Promise对象的使用。
以JavaScript原生的AJAX为栗子,AJAX的请求形式如下:
1 2 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代码如下:
1 2 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进行封装,看看效果怎么样。 代码如下:
1 2 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
就是失败时调用的。接下来让我们同样实现前面三个接口的功能:
1 2 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
就是失败时调用的
1 2 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的失败处理也能生效,我们应该将代码改成下面这样:
1 2 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一些更深层次的理论这里就不探讨了,网上资料很多,大家可以去搜索下。本文中的示例代码可以在这里下载。