第一次接触promise的时候一脸蒙不知道这个东西是什么?是干什么的? 包括看了官方文档后还是不太清楚
其实是一种异步编程的解决方案
什么?回调地狱是什么?完全没听过啊!不要着急 接着往下看
我们来考虑下面这样的场景
我们需要通过一个url1从服务器加载一个属于data1,data1中包含了下一个需要请求的url2而我们就需要通过data1中取出url2,在从服务器加载data2,此时data2中包含了下一个请求的url3这是我们通过data2取出url3,从服务器加载数据data3,而data3中包含了下一个请求的url4发送网路请求 请求url4, 获取最终的数据data4有可能还更多而这种情况我们就称之为 回调地狱 还没太看明白,那我们就看下面的伪代码吧:(方便起见用了jquery的ajax) $.ajax('url1', function (data1) { $.ajax('url2', function (data2) { $.ajax('url3', function (data3) { $.ajax('url4', function (data4) { console.log(data4); }) }) }) })看起来简单,但是其中还包含的对每次请求到的data进行解析的过程,代码中没有标注出来。
虽然这样写没什么问题,但是,这样的代码比较复杂而且不容易维护。我们更加期望的是一种优雅的方式来进行这种异步操作。
这就要用到Promise,它可以以一种非常优雅的方式来解决这个问题 。
简而言之就是将请求来的数据放在.then()中操作。
一般情况下是由异步操作时,使用Promise对这个异步操作进行封装。
在resolve中接受data,在.then中可调用,上面这段代码可以直接把Hello World打印出来,也就印证了resolve中传递data给.then的作用了。
Promise中的resolve 和 reject都是js内部定义的函数,resolve 成功时调用。reject 失败时调用,而此时一旦调用reject就会把错误信息返回到.catch中:
new Promise((resolve, reject) => { setTimeout(() => { //resolve('Hello World') reject('Error') }) }).then((data) => { console.log(data); }).catch(err => { console.log(err) })这里也成功的将Error Message打印了出来
首先,当我么你再开发中有异步操作时,就可以给异步操作包装一个Promise 而异步操作之后会有三种状态:
pendding:等待状态,比如正在进行网络请求,或者定时器没有到时间。fufill:(也称为resolved)满足状态,当我们主动回调了resolve时,就处于该状态,并且会回调.then()reject:拒绝状态,当我们主动毁掉了reject时,就处于该状态,并且会回调.catch()Promise还有另一种写法,直接再.then中传入两个函数的参数,第一个是resolve的结果,第二个就是reject的结果:
new Promise((resolve, reject) => { setTimeout(() => { resolve('Hello World') // reject('error message') }, 1000) }).then(data => { console.log(data); //Hello World },err => { console.log(err); }) new Promise((resolve, reject) => { setTimeout(() => { //resolve('Hello World') reject('error message') }, 1000) }).then(data => { console.log(data); },err => { console.log(err);// error message })都如愿以偿的打印出了想要的结果
我们来想象一下有这样一个需求: 1. 我们第一次进行网络请求拿到了数据‘aaa’,2. 我们想给拿到的aaa拼接字符串‘111’,然后再给拼接后的字符串再拼接’222‘: (这里我们假设setTimeout就是一次请求)
new Promise((resolve, reject) => { setTimeout(() => { resolve('aaa') }, 1000) }).then(res => { // console.log(res, '第一层处理的10行代码') //对结果进行第一次处理 return new Promise((resolve) => { //reject可以不传 resolve(res + '111'); }) }).then(res => { console.log(res, '第二层处理的10行代码') return new Promise((ressolve) => { resolve(res + '222') }) }).then(res => { console.log(res, '第三层的10行处理代码') })上面代码就是一个很优雅的链式调用。下面是打印的结果 其实上面的代码还可以简写:
new Promise((resolve, reject) => { setTimeout(() => { resolve('aaa') }, 1000) }).then(res => { console.log(res, '第一层处理的10行代码') //对结果进行第一次处理 return Promise.resolve(res + '111') }).then(res => { console.log(res, '第二层处理的10行代码') return Promise.resolve(res + '222') }).then(res => { console.log(res, '第三层的10行处理代码') })打印结果都是一样的,但其实还可以再简化,省略掉Promise.resolve:
new Promise((resolve, reject) => { setTimeout(() => { resolve('aaa') }, 1000) }).then(res => { console.log(res, '第一层处理的10行代码') //对结果进行第一次处理 return res + '111' //内部会对Promise进行包装,并且内部调用resolve }).then(res => { console.log(res, '第二层处理的10行代码') return res + '222' }).then(res => { console.log(res, '第三层的10行处理代码') })结果还是能正确打印。但如果中间某一步调用的时reject的时候,那么下面的代码就不会执行,直到.catch();
new Promise((resolve, reject) => { setTimeout(() => { resolve('aaa') }, 1000) }).then(res => { // console.log(res, '第一层处理的10行代码') //对结果进行第一次处理 return new Promise((resolve, reject) => { //reject可以不传 // resolve(res + '111'); reject('error 1') }) }).then(res => { console.log(res, '第二层处理的10行代码') return new Promise((ressolve) => { resolve(res + '222') }) }).then(res => { console.log(res, '第三层的10行处理代码') }).catch(err => { console.log(err); })我们再来看看打印结果: 而reject和resolve一样也有简写return Promise.reject('error 1');
如果某个需求需要发送两次需求才能继续执行,我们可以使用Promise.all()方法。我们还是以setTimeout为例,直接就把setTimeout当作网络请求:
Promise.all([ new Promise((resolve, reject) => { setTimeout(() => { resolve({age: 18, name: 'Venciki'}) }, 2000) }), new Promise((resolve, reject) => { setTimeout(() => { resolve({age: 19, name: 'Relo'}) }, 1000) }) ]).then(results => { console.log(results) })上面代码中发送了两次请求(使用了两次setTimeout)我们把他门放在all方法中,最终可以通过一个.then(results)的results来接受两次请求的返回的参数:
