Promise

作者: mah93 | 来源:发表于2019-10-09 16:30 被阅读0次

    简介

    Promise简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。

    Promise有三种状态:pendingfulfilledrejected

    Promise对象初始化时状态为:pending(进行中)

    调用resolve方法时,Promise的状态由pending变为fulfilled

    调用rejected方法时,Promise的状态由pending变为rejected

    1、 Promise对象的状态不受外界影响,只有异步操作的结果可以决定当前时哪一种状态,任何其他操作都无法改变这个状态。

    2、 一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected

    使用

    简单的初始化一个Promise

    const promise = new Promise((resolve) => {
        setInterval(() => {
            resolve('延迟2s回调');
        }, 2000);
    });
    

    上面初始化了一个Promise对象,并创建了一个异步操作:在两秒后调用resolve方法。这里仅仅是初始化了这个对象,并没有调用。继续调用这个promise对象

    const promise = new Promise((resolve) => {
        setInterval(() => {
            resolve('延迟2s回调');
        }, 2000);
    });
    
    promise.then((data) => {
        console.log(data);
    });
    

    当执行代码的时候,控制台在两秒钟后打印出了“延迟2s回调”,也就是说在上面初始化Promise的resolve里面的参数回调到了下面then方法中的data参数中。简单来说就是then里面的函数,会传递到Promise中并由resolve来控制这个函数的执行时间以及执行所需要的参数并回调。

    上述代码的执行过程就是Promise内部状态由pending变为fulfilled

    Promise还有从pending变为rejected的过程。

    const promise = new Promise((resolve, reject) => {
        setInterval(() => {
            let number = getRandomNumber();
            if(number > 5) {
                resolve('大于5');
            } else {
                reject('不大于5');
            }
        }, 2000);
    });
    
    promise.then((data) => {
        console.log('then');
        console.log(data);
    }).catch((error) => {
        console.log('catch');
        console.log(error);
    });
    

    Promise中初始化了一个简单逻辑,两秒之后获得一个随机数字,该数字大于5的时候调用resolve方法,反之则调用reject方法。由上面的例子可以得知,当数字大于5的时候会在then中打印。那么当数字小于5的时候,则会在catch中打印改数字。

    简单总结下来,resolve方法回调至then中,reject方法回调至catch中。

    那么可以借用Promise的特点,简单的封装一个网络请求。使用resolvereject分别包装正常返回和异常返回的值和信息。

    const promise = new Promise((resolve, reject) => {
                fetch(url)
                    .then((response) => {
                        return response.json();
                    })
                    .then((responseData) => {
                        resolve(responseData);
                    })
                    .catch(function (error) {
                        reject(error)
                    })
            })
    
    promise.then((data) => {
        // 请求返回的数据
    }).catch((error) => {
        // 请求报错
    })
    

    链式调用

    通过上面的例子Promise可以理解为是一个类似延迟加载的异步回调函数,那么其实也可以用普通的方法实现Promise的功能

    myPromise = (callback) => {
        setInterval(() => {
            console.log('执行完成');
            callback('随便什么数据');
        }, 2000);
    }
    
    myPromise((data) => {
        console.log(data);
    })
    

    它也会和Promise拥有同样的效果。那Promise到底能实现什么不可替代的功能呢?

    假如有许多的异步操作需要执行,比如连续的三个请求,每一次请求都需要从前一个请求中获取参数,那么它的写法如下

    fetch(url1).then((data1) => {
        if (data1 == 200) {
            fetch(url2).then((data2) => {
                if(data2 == 200) {
                    fetch(url3) ....
                    ...
                }
            })
        }
    })
    

    虽然可以实现需求,然是代码看起来并不那么友好,它庞大的层级结构使之无法轻易被修改。如果要是需要在第二个请求和第三个请求中再加入一些异步操作,那么将是不可修改的,这被称为回调地狱(Callback hell)。

    使用Promise即可解决上述问题,Promise的优势在于,可以在then方法中继续写Promise对象并返回,然后继续调用then来进行回调操作。也就是说可以一直return一个Promise对象,可以一直在在后面调用then方法。如果使用Promise后上述的需求可以写为

    // 分别将三个请求包装为函数
    request1 = () => {
        return fetch(url1);
    }
    request2 = () => {
        return fetch(url2);
    }
    request3 = () => {
        return fetch(url3);
    }
    // 调用时
    request1().then((data)=> {
        return request2();
    }).then((data) => {
        return request3();
    }).then((data) => {
        ...
    }).catch();
    

    只需要在then中调用下一个Promise,上一个Promise中回调的数据即可传递下去。

    关于回调地狱(Callback hell)的问题也可以使用async/await解决,类似的代码如下

    task() async {
       try{
        String id = await request1();
        String userInfo = await request2();
        await request3();
        //执行接下来的操作   
       } catch(e){
        //错误处理   
        print(e);   
       }  
    }
    

    相关API

    all

    Promise.all方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。

    const p = Promise.all([promise1, promise2, promise3]);
    

    p的状态由promise1promise2promise3决定,分成两种情况。

    (1)只有promise1promise2promise3的状态都变成fulfilledp的状态才会变成fulfilled,此时promise1promise2promise3的返回值组成一个数组,传递给p的回调函数。

    (2)只要promise1promise2promise3之中有一个被rejectedp的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。

    注意,如果作为参数的 promise 实例,自己定义了catch方法,那么它一旦被rejected,并不会触发Promise.all()catch方法。

    race

    Promise.race方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例。

    const p = Promise.race([promise1, promise2, promise3]);
    

    上面代码中,只要有任何一个promise改变状态,那么p的状态也会跟着改变。也就是说最快改变状态的promise会让其他promise不会回调。

    可以通过这个方法来完成一个请求超时功能

    const p = Promise.race([
      fetch(url),
      new Promise((resolve, reject) => {
        setTimeout(() => reject(new Error('request timeout')), 5000)
      })
    ]);
    
    p
    .then(console.log)
    .catch(console.error);
    

    即当5s内请求没有返回结果,就返回请求超时。

    参考链接

    相关文章

      网友评论

          本文标题:Promise

          本文链接:https://www.haomeiwen.com/subject/nwegpctx.html