1. 90前端首页
  2. 前端开发
  3. JavaScript

谈谈ES6中Promise的使用

Promise是一个对象,同时也是一个构造函数,为了对Promise有一个直观的认识,首先我们把Promise直接在控制台打印出来:

谈谈ES6中Promise的使用

通过这张图片我们可以很清除地看到,Promise自己身上有all,race,resolve,reject这些我们熟悉的方法,而在原型之上,则有then,catch,finally这些同样很熟悉的方法。

Promise怎么用?

既然Promise是一个构造函数,那我们就new一个实例出来吧:

var p = new Promise(function(resolve,reject){
    setTimeout(() =>{
        if(1){    //假设操作成功
            console.log(\"执行成功\")
            resolve(\"执行成功之后的数据\")
        }else{
            console.log(\"执行失败\")
            reject(\"执行失败之后的数据\")
        }
    }, 1000)
})

Promise接收一个参数,是一个函数,该函数有两个参数:resolve和reject,也是两个函数,这两个函数是javascript引擎给我们提供的,不用我们自己去部署。
Promise有三种状态:pending/fulfilled/rejected 。pending就是未决,fulfilled可以理解为成功,rejected可以理解为失败。

resolve函数的作用是将Promise的状态置为fullfiled,当状态变成fullfiled时,then方法的第一个回调会执行,reject函数是将Promise的状态置为rejected,当状态变成rejected时,then方法的第二个回调或者catch方法里的回调会执行

并且Promise有以下特点:
1 .对象的状态不受外界影响,只有内部异步操作的结果可以修改他的状态,任何其他操作都无法修改他的状态。
2 .一旦状态发生改变,就不会再变,任何时候都可以得到这个结果。如果改变已经发生了,只要添加回调函数,任何时候都可以得到返回值。

运行以上代码,我们在控制台可以看到打印出了执行成功:

谈谈ES6中Promise的使用
注意,这里我们只是new了一个Promise对象,并没有去调用它,里面代码就已经执行了,所以我们一般都是把Promise放到一个函数里面,在需要的时候调用,为了方便探讨,我们对函数做如下封装:

function createPro(num,time){
    return new Promise(function(resolve,reject){
        setTimeout(() =>{
            if(num > 5){
                console.log(\"执行成功\")
                resolve(\"执行成功之后的数据\")
            }else{
                console.log(\"执行失败\")
                reject(\"执行失败之后的数据\")
            }
        }, time)
    })
}

我们封装了一个函数,返回一个Promise对象,我们给该函数传递两个参数,num和time,num用来控制异步操作的结果,num大于5理解为执行成功,time用来控制延迟时间。
刚才我们看到函数已经执行成功,但是resolve和reject传递的参数去哪里了?还记得刚才我们说过当Promise状态改变时会执行then或者catch方法里的回调吧,没错,在回调函数里面就可以取到传递的数据。

then方法和catch方法

then中有2个参数,第一个参数是状态变为成功后应该执行的回调函数,第二个参数是状态变为失败后应该执行的回调函数。

createPro(10,1000).then((data)=>{
    console.log(\"num为10时then方法的第一个参数收到的:\"+data)
},(err)=>{
    console.log(\"num为10时then方法的第二个参数收到的:\"+err)
})
createPro(1,1000).then((data)=>{
    console.log(\"num为1时then方法的第一个参数收到的:\"+data)
},(err)=>{
    console.log(\"num为1时then方法的第二个参数收到的:\"+err)
})

执行以上函数,我们观察控制台的打印情况:

谈谈ES6中Promise的使用

由于第一次调用createPro时,我们给num传的值为10,比5要大,所以在函数内部执行了resolve方法,Promise的状态变成了fullfiled,then方法的第一个回调被执行,并且接收到了resolve方法传递来的数据,而在第二次调用createPro时,我们给num传的值为1,比5要小,所以在函数内部调用了reject方法,Promise的状态变成了rejected,then方法的第二个回调被执行,并且收到了reject传递的数据。
当然then方法也可以只接收一个回调,即异步操作成功时执行的回调。
catch方法是用来接收异步操作失败的结果,效果和then方法的第二个参数一样:

createPro(1,1000).then((data)=>{
    console.log(\"then方法的第一个参数收到的:\",data)
}).catch((err)=>{
    console.log(\"catch方法里收到的:\",err)
})

我们在控制台可以看到打印了:

谈谈ES6中Promise的使用

如果我们想要不管成功还是失败,都要执行一些操作可以用Promise.finally(),但是该方法的回调函数不接受任何参数,这意味着没有办法知道,前面的 Promise 状态到底是fulfilled还是rejected。这表明,finally方法里面的操作,是与状态无关的,不依赖于 Promise 的执行结果。

Promise的链式操作

Promise的then方法之后会继续返回一个Promise对象,可以继续调用then方法,而接收的参数值就是上一个then方法return的结果:

createPro(10,1000).then((data)=>{
    console.log(\"then方法的第一个参数收到的:\"+data)
    return 100
}).then(data=>{
    console.log(\"第二个then方法接收到的的参数\",data)
})

谈谈ES6中Promise的使用
我们可以看到在第二个then中接收到了我们在第一个then方法中返回的数字100.当然我们也可以返回一个Promise对象

createPro(10,1000).then((data)=>{
    console.log(\"第一个then:\",data)
    return createPro(10,1000)
}).then(data=>{
    console.log(\"第二个then:\",data)
    return createPro(2,1000)
}).then(data=>{
    console.log(\"第三个then:\",data)
    return createPro(10,1000)
}).catch(err=>{
    console.log(\"公共的catch方法:\",err)
})

运行结果如下:
谈谈ES6中Promise的使用

我们可以看到函数依次执行,所以Promise可以解决所谓“地狱回调”的问题,并且如果中途有异步操作执行失败,都会执行catch里面的回调。

Promise.all和Promise.race

Promise的all方法提供了并行执行异步操作的能力,并且在所有异步操作执行完后才执行回调。Promise.all接收一个数组参数,里面的异步操作的并行执行的,等到它们都执行完后才会进到then里面。那么,异步操作返回的数据哪里去了呢?都在then里面呢,all会把所有异步操作的结果放进一个数组中传给then。
我们对createPro函数设置不同的延迟时间:

Promise.all([createPro(10,1000),createPro(10,2000),createPro(10,3000)]).then(data=>{
    console.log(data)
})

执行以上代码,我们可以看到控制台每隔一秒打印出了一次“执行成功”,并且在最后打印出了传递的数据,是一个数组:
谈谈ES6中Promise的使用
Promise.all有一个经常用到的场景就是,在一个页面有多个请求接口,当所有接口都请求到数据之后,关闭loading遮罩层,这时候我们就可以用到Promise.all方法。

理解了Promise.all再来看Promise.race就好理解多了,all方法的效果实际上是「谁跑的慢,以谁为准执行回调」,那么相对的就有另一个方法「谁跑的快,以谁为准执行回调」,这就是Promise.race:

Promise.race([createPro(10,1000),createPro(10,2000),createPro(10,3000)]).then(data=>{
    console.log(data)
})

运行结果如下:
谈谈ES6中Promise的使用
我们在控制台可以看到,一秒之后打印出了“执行成功”,并且拿到了resolve传递的数据,但是另外两个函数并没有停止运行,所以我们看到每间隔一秒又打印出了“执行成功”。

关于Promise常用的方法先写这些了,另外还有Promise.resolve和Promise.reject等方法有时间再研究,由于作者水平有限,文章难免有错误之处,还请大神斧正。

本文来自网络整理,转载请注明原出处:https://segmentfault.com/a/1190000021600206

展开阅读全文

发表评论

登录后才能评论