说说Promise~

100 阅读5分钟

「这是我参与11月更文挑战的第13天,活动详情查看:2021最后一次更文挑战

ES6中有一个非常重要和好用的特性就是Promise 那么Promise到底是做什么的呢?

基本概念

简单来说,Promise就是异步编程的一种解决方案,其实就是一个构造函数。自己身上有resolve、reject、all这几个方法。原型链上有then、catch等方法。

两大特点

  1. 对象的状态不受外界影响。Promise对象代表着一个异步操作,它有三种状态:pending(进行中)、fulfilled(已完成)、rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何操作都无法改变这个状态。 2. 一旦状态改变,就不会再变,任何时候都可以得到这个状态。Promise对象的状态改变,只有两种结果:从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,状态就凝固了,不会在改变了,会一直保持这个结果。

基本使用

先new 一个最基本的Promise对象

let p = new Promise((resolve,reject)=>{
    setTimeout(()=>{
        console.log('执行完成Promise');
        resolve('要返回的任何数据:接口数据等等');
    },2000)
})

刷新页面会打印如下结果 它的执行过程是:执行了一个异步操作(setTimeout),2秒之后,输出图中结果,并且调用了resolve方法。 注意:这里我只是new了一个对象,并没有调用它,里面传进去的函数就已经执行了。所以一般情况下我们用Promise的时候都是包在一个函数中,在需要的时候去运行这个函数。

<div onclick='promiseClick()'>开始异步请求</div>
  const promiseClick = () => {
        console.log('点击方法被执行')
        let p = new Promise((resolve, reject) => {
            setTimeout(() => {
                console.log('执行完成Promise');
                resolve('要返回的任何数据:接口数据等等');
            }, 2000)
        })
        return p
    }

此时刷新页面,控制台没有打印任何信息,当我们点击div之后,打印台先后打出 这样我们只有在调用函数的时候才会被执行,那resolve是什么? 如上图我们在包装好的函最后,return 出一个Promise对象(p),也就是说,执行这个函数我们得到了一个Promise对象。

resolve/then

接下来就可以使用Promise对象身上的then方法了。

promiseClick().then(item=>{
        console.log(item);
    })

第一行代码直接出现,2秒之后打印Promise对象里面的,当我们多次点击之后,resolve执行的代码依旧只打印一次。验证了Promise对象的状态一旦发生,就不会在改变。

这个时候你会发现一件事情,then这不是和平时的回调函数一样嘛,在promiseClick这个异步函数执行完成之后被执行。那么Promise的精髓就来了,需要多层回调的时候,Promise就能简化层层回调的写法。

  function run1() {
        let p = new Promise((resolve, reject) => {
            setTimeout(() => {
                console.log('异步任务1完成');
                resolve('随便的数据1')
            }, 2000)
        })
        return p
    }

    function run2() {
        let p = new Promise((resolve, reject) => {
            setTimeout(() => {
                console.log('异步任务2完成');
                resolve('随便的数据2')
            }, 2000)
        })
        return p
    }

    promiseClick()
        .then(item => {
            console.log(item);
            return run1();
        })
        .then(item => {
            console.log(item);
            return run2()
        })
    .then(item=>{
        console.log(item);
    })

在控制台打印的结果如下 间隔2秒打印一个红框里面的内容,这样就能够按照顺序间隔2秒输出一个异步回调中的内容。

reject/catch

以上是对promise的resolve用法进行了解释,相当于resolve是对promise成功时候的回调,它把promise的状态修改为fullfiled,那么,reject就是失败的时候的回调,他把promise的状态修改为rejected,这样我们在catch中就能捕捉到,然后执行“失败”情况的回调。

 new Promise((resolve, reject) => {
        setTimeout((data) => {
            //成功的时候调用resolve
            resolve('hello World');

            //失败的时候执行reject
            reject('error message');
        })
    }).then((data)=>{
        console.log(data)
    }).catch((err)=>{
        console.log(err)
    })

all

与then同级的一个方法,该方法提供了并行执行异步操作的能力,在所有异步执行并执行结果都是成功的时候进行回调。

 function run1() {
        let p = new Promise((resolve, reject) => {
            setTimeout(() => {
                let nums = Math.ceil(Math.random() * 10)
                console.log('随机生成的数字:' + nums);
                if (nums <= 5) {
                    resolve(nums)
                } else {
                    reject('数字太大了')
                }
            }, 2000)
        })
        return p;
    }
    function run2() {
        let p = new Promise((resolve, reject) => {
            setTimeout(() => {
                let nums = Math.ceil(Math.random() * 10)
                console.log('随机生成的数字:' + nums);
                if (nums <= 5) {
                    resolve(nums)
                } else {
                    reject('数字太大了')
                }
            }, 2000)
        })
        return p;
    }
    function run3() {
        let p = new Promise((resolve, reject) => {
            setTimeout(() => {
                let nums = Math.ceil(Math.random() * 20)
                console.log('随机生成的数字:' + nums);
                if (nums <= 10) {
                    resolve(nums)
                } else {
                    reject('数字太大了')
                }
            }, 2000)
        })
        return p;
    }

    Promise
        .all([run1(),run2(),run3()])
    .then(result=>{
        console.log(result);
    })

race

all 是等所有异步操作执行完毕且成功之后在执行then方法,race正好是相反的,谁先执行完毕谁就先执行回调。先执行完的不管是进行了race的成功回调还是失败回调,其余的将不会再进入race的任何回调。

 function run1() {
        let p = new Promise((resolve, reject) => {
            setTimeout(function () {
                let num = Math.ceil(Math.random() * 20); //生成1-10的随机数
                console.log('2s随机数生成的值:', num)
                if (num <= 10) {
                    resolve(num);
                } else {
                    reject('2s数字大于10了即将执行失败回调');
                }
            }, 2000);
        })
        return p
    }

    function run2() {
        let p = new Promise((resolve, reject) => {
            setTimeout(function () {
                let num = Math.ceil(Math.random() * 20); //生成1-10的随机数
                console.log('3s随机数生成的值:', num)
                if (num <= 10) {
                    resolve(num);
                } else {
                    reject('3s数字大于10了即将执行失败回调');
                }
            }, 3000);
        })
        return p
    }

    function run3() {
        let p = new Promise((resolve, reject) => {
            setTimeout(function () {
                let num = Math.ceil(Math.random() * 20); //生成1-10的随机数
                console.log('4s随机数生成的值:', num)
                if (num <= 10) {
                    resolve(num);
                } else {
                    reject('4s数字太于10了即将执行失败回调');
                }
            }, 4000);
        })
        return p
    }

    Promise
        .race([run1(), run2(), run3()]) 
        .then(function (results) {
            console.log('成功', results);
        }, function (reason) {
            console.log('失败', reason);
        });

例子

在一个请求在10s内请求成功的话就走then方法,如果10s内没有请求成功的话进入reject回调执行另一个操作。

 function requestData(){
        let p = new Promise((resolve,reject)=>{
            //请求的数据
            resolve(res);
        })
        return p;
    }

    function TimeOut(){
        let p = new Promise((resolve,reject)=>{
            setTimeout(()=>{
                reject('请求超时');
            },10000)
        })
        return p;
    }

    Promise.race([requestData(),TimeOut])
    .then(res=>{
        console.log(res);
    })
    .catch(err=>{
        console.log(err);
    })