斗胆谈谈Promise

1.Promise概念

1.1为什么需要promise?

promise是ES6异步编程新的解决方案,它可以用来解决回调地狱的问题,回调地狱就是许多回调函数嵌套,导致代码太乱了,不易读,也不太好看。如下代码(读文件是异步操作,需要回调函数不停嵌套,透露出一股恶心劲)

fs.readFile('./1.html',(err,data)=>{
    if(err) throw err;
    fs.readFile('./2.html',(err,data1)=>{
        if(err) throw err;
        fs.readFile('./3.html',(err,data2)=>{
            if(err) throw err;
            fs.readFile('./4.html',)
        })
    })

})

1.2promise是什么?

promise其实就是一个构造函数,它里面包含一些属性和方法,支持链式调用。

promise其中一个属性PromiseState代表它的状态,它只有三种状态:

fulfilled/resolved(成功)

rejected (失败)

pending (进行中,最初的状态)

其中只会有两种情况的状态变化:

pending -> fulfilled/resolved

pending->rejected

就是只能从初始变为成功,或者从初始变为失败,成功和失败之间不能再互相转化了。

下面我们通过具体的使用来了解。

2.Promise使用

2.1创建promise

上代码(最简单的promise使用,定义一个成功的promise)

let p = new Promise((resolve,reject)=>{
            resolve('ok')
        })
console.log(p);

输出P是一个promise实例,它的状态是成功的,PromiseResult是promise的另一个属性,代表promise的值。

斗胆谈谈Promise

定义一个失败的promise

let p = new Promise((resolve,reject)=>{
            reject('fail')
        })
 console.log(p);

 输出结果是P是一个promise但他的状态是rejected失败的,promise的值就是传入的值斗胆谈谈Promise

 2.2promise的方法

then():

then方法的参数可以传入两个回调函数,当promise状态变为成功( fulfilled)时,执行第一个参数接受的回调函数,状态变为失败(rejected)执行第二个参数接收的回调函数,注意then方法返回的仍然是一个promise对象,所以在then方法之后可以继续调用then方法

上代码

let p = new Promise((resolve,reject)=>{
            reject('fail')
        })
        p.then((value)=>{
            console.log('成功',value);
        },(reason)=>{
            console.log('失败',reason);

        })

斗胆谈谈Promise

当一个rejected状态的promise调用.then时执行的是第二个参数的回调函数,所以输出失败,值就是通过reject()传入的值

 let p = new Promise((resolve,reject)=>{
            resolve('ok')
           
        })
        p.then((value)=>{
            console.log('成功',value);
        },(reason)=>{
            console.log('失败',reason);

        })
        

斗胆谈谈Promise

 同理,当一个resolve状态的promise调用.then时,执行的是第一个参数的回调函数,输出成功,value值就是通过resolve()传入的值

 那我们说then返回的也是一个promise对象,若then里面的回调函数返回的是非promise的数值那么then返回的就是resolved/fulfilled状态的promise,

如果then里面的回调函数返回的是promise类型,则回调函数返回的promise的成功与否直接决定了then方法返回的promise的结果和状态(有些绕,看代码就清楚了)

上代码(回调函数返回非promise)

let p = new Promise((resolve,reject)=>{
            resolve('ok')
           
        })
        const res = p.then((value)=>{
            console.log('成功',value);
        },(reason)=>{
            console.log('失败',reason);})
            
        console.log(res);
p是resolved状态的,那么执行then里面的第一个回调函数,打印成功,回调函数并没有返回一个新的promise,因此p.then返回的就是一个状态为fulfilled的promise,值为undifined,因为没有新的promise对象。

斗胆谈谈Promise

 回调函数返回promise

 let p = new Promise((resolve,reject)=>{
            resolve('ok')
           
        })
        const res = p.then((value)=>{
            return new Promise((resolve,reject)=>{
                resolve('new Promise')

            })  
        },(reason)=>{
            console.log('失败',reason);})

        console.log(res);

斗胆谈谈Promise

因为成功的回调函数返回了一个新的promise,他决定了then返回的promise的状态和值也是成功的,值就是传入的新值

let p = new Promise((resolve,reject)=>{
            resolve('ok')
           
        })
        const res = p.then((value)=>{
            return new Promise((resolve,reject)=>{
                reject('fail Promise')

            })  
        },(reason)=>{
            console.log('失败',reason);})

        console.log(res);

斗胆谈谈Promise 

若回调函数返回的是失败的promise,则then返回的也是失败的promise,值就是传入的值

catch()

promise还有一个特点是可以进行异常穿透,就是已经失败了,就不要总是定义失败(reject)的回调函数了,只要在最后指定一个失败的回调catch()就好了,捕获失败结果,返回值就第一个失败的值,这样代码就更清晰了。

 let p1 = new Promise((resolve,reject)=>{
            reject('fail')
           
        })
        p1.then((value)=>{
            console.log('成功',value);

        }).catch(e=>
            {
            console.log('失败',e);
        })

失败的promis执行catch(),then方法里面不用再写失败的回调了

斗胆谈谈Promise

 如果.then后面还有.then,许许多多.then也不怕,catch仍然能抓到第一个失败的值

 let p1 = new Promise((resolve,reject)=>{
            resolve('ok')
           
        })
        p1.then(value=>{
            console.log('111');
            

        }).then(value=>{
            console.log('222');
            throw('ERROR')
        }).then(value=>{
            console.log('333');
            
        }).catch(reason=>{
            console.log('失败',reason)
        })

斗胆谈谈Promise

成功的promise会继续执行.then方法,直到catch捕获到了第一个失败,就不再继续执行了,不会输出33333

 all()

promise.all传入的是一个promise类型的数组,它的返回值也是一个promise,他的状态由数组决定,若promise数组里均为resolved状态的,那么promise.all返回的就是resolved状态的,值就是由所有传入值组成的数组,若promise数组中有一个失败了,那么promise.all返回的就是reject状态的,值就是失败的传入的值

上代码(promise全为成功状态)

let p1 = new Promise((resolve,reject)=>{
            resolve('ok')
           
        })
        let p2 = new Promise((resolve,reject)=>{
            resolve('success')
           
        })
        let p3 = new Promise((resolve,reject)=>{
            resolve('nice')
           
        })
        const res = Promise.all([p1,p2,p3])

        console.log(res);

斗胆谈谈Promise

有一个为失败状态

  let p1 = new Promise((resolve,reject)=>{
            resolve('ok')
           
        })
        let p2 = new Promise((resolve,reject)=>{
            reject('fail')
           
        })
        let p3 = new Promise((resolve,reject)=>{
            resolve('nice')
           
        })
        const res = Promise.all([p1,p2,p3])

        console.log(res);

斗胆谈谈Promise

 race()

promise.all传入的也是一个primise数组,返回值是一个promise,只是它的状态和值是由最先发生变化的promise状态和值决定的,就像赛跑先到先得

        let p1 = new Promise((resolve,reject)=>{
            resolve('ok')
           
        })
        let p2 = new Promise((resolve,reject)=>{
            reject('fail')
           
        })
        let p3 = new Promise((resolve,reject)=>{
            resolve('nice')
           
        })
        const res = Promise.race([p1,p2,p3])

        console.log(res);

斗胆谈谈Promise

 P1先到,是成功的,值是ok,则all方法返回的promise是成功的值为ok

若P1变为异步了,则p2先到那么结果一定会是一个返回失败的promise

        let p1 = new Promise((resolve,reject)=>{
            setTimeout(()=>{
                resolve('ok')
            })
        })
        let p2 = new Promise((resolve,reject)=>{
            reject('fail')
           
        })
        let p3 = new Promise((resolve,reject)=>{
            resolve('nice')
           
        })
        const res = Promise.race([p1,p2,p3])

        console.log(res);

斗胆谈谈Promise

4.async await

async是一个函数,返回结果是一个promise对象

1.如果函数里面return的不是一个promise,那promise的结果就是成功的,值就是return的数值

2.如果函数里面return的是一个promise,那async的Promise就是return的promise

3.抛出异常,返回的就是失败的promise对象

(这个很像对于then方法那个表述)

await右边表达式一般为promise对象

1.右边是promise对象,await返回值是promise成功值

2.右边是其他值,直接将此值作为await的返回值(很少用)

注意二者常常结合使用简化promise操作

await必须写在async里面,但是async可以没有await

上代码

        async function main(){
            let p = new Promise((resolve,reject)=>{
                resolve('ok')
                // reject('error')
            })
            try{
                let res = await p;
                console.log(res);
            }catch(e){
                console.log(e);
            }
            
        }
        main()

await返回的是promise的成功值,所以需要用try catch捕获失败的情况,输出ok,以后就可以用这样的方法简化promise操作,只需要awaitpromise成功的值即可

上一篇:JS中的Promise对象,解决回调地狱案例详解,让代码同步执行


下一篇:微信小程序 - 云开发data exceed max size 解决方案