Promise(2) | Promise完结篇

63 阅读7分钟

二、Promise

2.1 Promise介绍

  • new Promise就可以得到一个对象,new Promise时,需要传入一个回调函数,这个回调函数是立即执行,叫执行器,这个执行器中有两个参数,分别是resolve和reject。
<script>
    //Promise resolver 执行器,必须是一个函数
    //执行器会立即执行
    //p叫Promise对象
    //默认创建的Promise有三种状态,当new出来时,处于等状态
    //调用resolve可以把等待状态(pending)的promise变成成功态(fullfilled)
    //调用reject可以把等待状态(pending)的promise变成失败态(rejected)
    //一个Promise只能从等待到成功或者从等待到失败
    //一旦成功了,就不能失败了
    let p = new Promise((resolve, reject) => {
        //在执行器中通常写异步代码,异步指的是定时器中的回调函数
        console.log("xxx")
        setTimeout(() => {
            console.log("我是定时器~")
            reject("没钱");//和resolve只能二选一
            resolve("包包");//把等待的Promise变成一个成功的Promise
            //resolve("成功的值,也叫做终值")
            reject("没钱");//和resolve只能二选一
        }, 2000)
    });
    console.log('--p', p);
    setTimeout(() => {
        console.log(p)
    }, 3000)
</script>

用Promise重写0-100之和:

<script>
    function fn(counter) {
        let promise = new Promise((resolve,reject) => {
            setTimeout(() => {
                if (counter > 0) {
                    let total = 0;
                    for (let i = 0; i <= counter; i++) {
                        total += i;
                    }
                    resolve(total)
                } else {
                    reject("你传递的数据不合法")
                }
            }, 3000)
        })
        return promise;
    }
    // console.log(fn(100))
    //promise.then里面有2个参数,第一个拿成功的,第二个拿失败的
    fn(100).then((value)=>{
        console.log('--value',value);
    },(reason)=>{
        console.log('--reason:',reason);
    })
</script>

2.2 resolve的实参问题

调用resolve,promise不一定都是成功的promise,分三种情况:

  • 传递一个普通的数据,promise是成功的promise
  • 传递一个p(promise),最终的promise是成功还是失败取决于p
  • 传递一个thenable{then(resolve,reject){}}(大括号then小括号大括号),最终的promise是成功还是失败取决于thenable

代码演示:

<script>
    const p = new Promise((resolve,reject)=>{
        // thenable {then(){}}   {eat(){}} : eatable
        //
        setTimeout(()=>{
            //resolve("p的resolve")
            reject("没钱")
        },2000)
    });
​
    let promise = new Promise((resolve, reject) => {
        // 1)参数是普通的数据
        // resolve(111)
        // resolve('包包')
        // resolve(["a","b","c"])
        // resolve({name:"ml"})
        // 2)参数是promise
        // 成功与否取决于参数的promise
        // resolve(p)
        // 3)参数是thenable 就是一个对象中有一个then函数
        resolve({
            then(resolve,reject){
                //resolve('包包')
                reject('没钱')
            }
        })
    })
    promise.then((value)=>{
        console.log('--value',value);
    },(reason)=>{
        console.log('--reason:',reason);
    })
</script>

2.3 then方法

一个promise对象,都有一个then方法,只要是一个promise,都有一个then方法,代码演示:

<script>
    const p = new Promise((resolve,reject)=>{
        reject("error")
    })
    p.then((res)=>{console.log(res);},(err)=>{console.log(err);});
    p.then((res)=>{console.log(res);},(err)=>{console.log(err);});
    p.then((res)=>{console.log(res);},(err)=>{console.log(err);});
    p.then((res)=>{console.log(res);},(err)=>{console.log(err);});
​
</script>

2.4 then函数的返回值

then方法是有返回值的,它返回一个新的promise。只要then,就可以一直then

<script>
    const p = new Promise((resolve,reject)=>{
        reject("error")
    })
    //then链 then完之后,得到一个新的promise,我们要研究新的promise是成功的还是失败的
    p.then((res)=>{console.log(res);},(err)=>{console.log(err);})
    .then((res)=>{console.log(res);},(err)=>{console.log(err);})
    .then((res)=>{console.log(res);},(err)=>{console.log(err);})
    .then((res)=>{console.log(res);},(err)=>{console.log(err);});
​
</script>

现在我们需要研究新的promise是成功的还是失败的,新的promise是成功的还是失败的,取决于上一个then做了什么,当上一个then方法中的回调函数在执行时,新promise处于等待状态,当商业给then返回一个结果时,那这个结果就决定了新的promise的状态,情况有下面四种:[需要背会]

  • 上一个then返回一个普通的值(包含undefined) 新的promise是成功的promise
  • 上一个then返回一个promise,新的promise是成功还是失败取决于返回的哪个promise
  • 上一个then返回一个thenable值,新的promise是成功还是失败取决于thenable是成功还是失败
  • 上一个then抛出一个错误,新的promise就是失败的promise

上一个then返回一个普通的值(包含undefined)新的promise是成功的promise,代码演示:

<script>
    //p成功还是失败,取决于调用的是resolve还是reject
    const p = new Promise((resolve, reject) => {
        resolve("success");
    });
    p.then((res) => { 
        console.log(res); 
    }, (err) => { 
        console.log(err); 
    }).then((res) => { 
        console.log(res); 
    }, (err) => { 
        console.log(err); 
    }).then((res) => { 
        console.log(res); 
    }, (err) => { 
        console.log(err); 
    })
</script>

上一个then返回promise,代码演示

<script>
    const px = new Promise((resolve, reject) => {
        setTimeout(()=>{
            //resolve("px的resolve")
            reject("没钱")
        },2000)
    });
​
    const p = new Promise((resolve, reject) => {
        resolve("success");
    });
    //成功或者是失败是作用于下一个then上面的
    //p成功作用在了p.then上面
    p.then((res) => {               //p是成功的,所以走res
        console.log(res);           //执行这一行,输出res ,即success
        return px;
    }, (err) => { 
        console.log(err); 
    }).then((res) => {              //p.then,return px,是失败的,所以走err
        console.log(res); 
    }, (err) => { 
        console.log(err);           //执行这一行,输出err,即没钱 没有返回值,默认返回undefined
    }).then((res) => {              //p.then.then是成功的,所以走res
        console.log(res);           //执行这一行,输出res,即undefined
    }, (err) => { 
        console.log(err); 
    })
</script>

上一个then返回一个thenable值,新的promise是成功还是失败取决于thenable是成功还是失败,代码演示:

<script>
​
    const p = new Promise((resolve, reject) => {
        resolve("success");
    });
    //成功或者是失败是作用于下一个then上面的
    //p成功作用在了p.then上面
    p.then((res) => {               //p是成功的,所以走res
        console.log(res);           //执行这一行,输出res ,即success
        return {
            then(resolve,reject){
                reject("没钱")
            }
        };
    }, (err) => { 
        console.log(err); 
    }).then((res) => {              //p.then,由于上面返回reject,是失败的,所以走err
        console.log(res); 
    }, (err) => { 
        console.log(err);           //执行这一行,输出err,即没钱 没有返回值,默认返回undefined
    }).then((res) => {              //p.then.then是成功的,所以走res
        console.log(res);           //执行这一行,输出res,即undefined
    }, (err) => { 
        console.log(err); 
    })
</script>

上一个then抛出一个错误,代码演示:

<script>
​
    const p = new Promise((resolve, reject) => {
        resolve("success");
    });
​
    p.then((res) => {               
        console.log(res);           
        // throw new Error("bad")
        console.log(aaa);
    }, (err) => { 
        console.log(err); 
    }).then((res) => {             
        console.log(res); 
    }, (err) => { 
        console.log(err);           
    }).then((res) => {              
        console.log(res);           
    }, (err) => { 
        console.log(err); 
    })
</script>

2.5 then的顺延

then的顺延分成2种。

  • 一般写then的格式为。p.then((res)=>{console.log(res)},(err)=>{console.log(err)})

    但是可以将其中一个形参改成null,如果将成功(也就是前者)改成null,那么会一直顺延下去,直到找到成功时的console.log,再进行输出,失败同理

    <script>
    ​
        const p = new Promise((resolve, reject) => {
            resolve('success');
            // reject("bad");
        });
        p.then(null,(err)=>{console.log(err)})
        .then(null,(err)=>{console.log(err)})
        .then(null,(err)=>{console.log(err)})
        .then((res)=>{console.log(res)},(err)=>{console.log(err)})//在这一行输出了res
    </script>
    
  • 另外一种关于顺延的则是then,catch。then用来获取成功结果,catch用来获取失败结果

    p.then((res)=>{console.log(res)}).catch((err)=>{console.log(err)})

    <script>
    ​
        const p = new Promise((resolve, reject) => {
            resolve('success');
            // reject("bad");
        });
    ​
        // catch(null,err=>{})
        p.then((res)=>{ //拿成功结果
            console.log(res);
        }).catch((err)=>{ //获取失败结果
            console.log(err);
        })
        // p.then((res)=>{console.log(res)}).catch((err)=>{console.log(err)})
    </script>
    

    2.6 finally

不管promise成功还是失败,最终都会执行finally,代码如下:

<script>
​
    const p = new Promise((resolve, reject) => {
        resolve('success');
        // reject("bad");
    });
    p.then((res)=>{console.log(res)})
    .catch((err)=>{console.log(err)})
    .finally(()=>{console.log("----------")})
</script>

2.7 promise的静态方法

前面学习的then,catch,finally都是promise实例上的方法,其实在Promise这个类上面,还有一些,这些方法,叫静态方法,代码如下:

<script>
    let p = Promise.resolve("包包");
    // 相当于
    // new Promise((resolve)=>{
    //     resolve("包包")
    // })
    p.then((res)=>{
        console.log("then的结果:",res)
    })
</script>
<script>
    let p = Promise.reject("没钱");
    // 相当于
    // new Promise((resolve)=>{
    //     reject("没钱")
    // })
    p.catch((err)=>{
        console.log("then的结果:",err)
    })
</script>

还有一个all方法,all的作用:

  • 所有promise都成功后,得到所有成功后的promise结果
  • 如果有一个先失败了,直接得到最先失败promise的结果

代码演示:

<script>
​
    const p1 = new Promise((resolve,reject)=>{
        setTimeout(()=>{
            // resolve("p1 resolve")
            reject("p1 reject")
        },3000)
    })
    const p2 = new Promise((resolve,reject)=>{
        setTimeout(()=>{
            // resolve("p2 resolve")
            reject("p2 reject")
        },2000)
    })
    const p3 = new Promise((resolve,reject)=>{
        setTimeout(()=>{
            resolve("p3 resolve")
            // reject("p3 reject")
        },5000)
    })
    // axios.all([p1,p2])
    Promise.all([p1,p2,p3]).then((res)=>{
        console.log("---res:",res)
    }).catch((err)=>{
        console.log("---err",err)
    })
​
</script>

还有一个方法,叫allSettled

  • 获取所有的promise的结果,不管成功还是失败
<script>
​
    const p1 = new Promise((resolve,reject)=>{
        setTimeout(()=>{
            // resolve("p1 resolve")
            reject("p1 reject")
        },3000)
    })
    const p2 = new Promise((resolve,reject)=>{
        setTimeout(()=>{
            // resolve("p2 resolve")
            reject("p2 reject")
        },2000)
    })
    const p3 = new Promise((resolve,reject)=>{
        setTimeout(()=>{
            resolve("p3 resolve")
            // reject("p3 reject")
        },5000)
    })
    // axios.all([p1,p2])
    Promise.allSettled([p1,p2,p3]).then((res)=>{
        console.log("---res:",res)
    }).catch((err)=>{
        console.log("---err",err)
    })
​
</script>

还有一个方法,叫race,race是比赛的意思,作用

  • 会等到第一个Promise有结果(无论这个结果是fulfilled还是rejected)
<script>
​
    const p1 = new Promise((resolve,reject)=>{
        setTimeout(()=>{
            // resolve("p1 resolve")
            reject("p1 reject")
        },3000)
    })
    const p2 = new Promise((resolve,reject)=>{
        setTimeout(()=>{
            resolve("p2 resolve")
            // reject("p2 reject")
        },2000)
    })
    const p3 = new Promise((resolve,reject)=>{
        setTimeout(()=>{
            resolve("p3 resolve")
            // reject("p3 reject")
        },5000)
    })
    // axios.all([p1,p2])
    Promise.race([p1,p2,p3]).then((res)=>{
        console.log("---res:",res)
    }).catch((err)=>{
        console.log("---err",err)
    })
​
</script>

最后一个,叫any,作用:

  • 返回第一个成功的 或者 返回所有都失败了
<script>
​
    const p1 = new Promise((resolve,reject)=>{
        setTimeout(()=>{
            // resolve("p1 resolve")
            reject("p1 reject")
        },3000)
    })
    const p2 = new Promise((resolve,reject)=>{
        setTimeout(()=>{
            // resolve("p2 resolve")
            reject("p2 reject")
        },2000)
    })
    const p3 = new Promise((resolve,reject)=>{
        setTimeout(()=>{
            // resolve("p3 resolve")
            reject("p3 reject")
        },5000)
    })
    // axios.all([p1,p2])
    Promise.any([p1,p2,p3]).then((res)=>{
        console.log("---res:",res)
    }).catch((err)=>{
        console.log("---err",err)
    })
​
</script>

总结Promise的静态方法:

Promise.resolve(); //成功
Promise.reject();  //失败
Promise.all();     //要成功都成功,有一个失败就不行了
Promise.allSettled();//获取所有的promise的结果,不管成功还是失败
Promise.race();    //获取第一个Promise的结果
Promise.any();     //要失败都失败,有一个成功就返回成功的