美文网首页
ES6(Promise)

ES6(Promise)

作者: KATENGC | 来源:发表于2020-04-29 16:35 被阅读0次

    Promise是异步编程的解决方案。举个例子,有一个函数A,A执行一些步骤,A执行完要执行函数B,这里有个顺序问题,就是A执行完执行B。那在程序上如何实现这个场景呢?
    这里有两种方式,一种是通过回调的方式实现,另外一种是通过事件触发的方式实现。而Promise是区别与以上两种方式的。

    一、Promise的基本用法

    先来回顾下ES5中利用回调来解决异步的问题
    我们模拟一个前端与服务端通信时的ajax过程,添加一个callback回调方法,用于接收服务端的返回结果。这里用定时器setTimeout模拟了一个通信的过程,一秒钟之后会调用回调方法。

    {
        let ajax = function (callback) {
            console.log('执行');
            setTimeout(() => {
                callback && callback.call();
            }, 1000); 
        };
    
        ajax(function () {
            console.log('timeout1');
        })
    }
    

    先输出了执行,一秒钟之后执行了回调函数,输出了timeout1,这样就实现了一个异步操作。

    但是开发过程中经常会遇到比较复杂的情况,先执行A再执行B,甚至执行完B再执行C,如果用ES5中回调的方式去处理,这么这个代码将非常复杂。除此之外,这个代码的复杂还会影响后期的代码维护,无法一眼看出代码执行的顺序问题,很难阅读,所以呢,为了解决这些问题,就引出了Promise这个解决方案。

    函数执行完之后会返回一个对象,这个对象就是Promise的实例,这个实例有一个then方法去执行下一步的功能。这里会有两个参数resolverejectresolve表示要执行下一步操作,而reject表示中断当前的操作

    {
        let ajax = function () {
            console.log('执行2');
            /**
             * resolve:要执行下一步的操作
             * reject:要中断当前的操作
             */
            return new Promise(function (resolve, reject) {
                setTimeout(function () {
                    resolve();
                }, 1000);
            })
        };
    
        ajax().then(() => {
            console.log('promise', 'timeout2');
        });
    }
    

    执行结果:
    先打印执行2,一秒钟之后再打印出timeout2

    那么对于执行完函数A再执行函数B的场景,利用Promise就很容易实现了

    {
        let ajax = function () {
            console.log('执行3');
            
            return new Promise(function (resolve, reject) {
    
                setTimeout(function () {
                    resolve();
                }, 1000);
            })
        };
    
        ajax()
            .then(() => {
                return new Promise(function (resolve, reject) {
                    console.log('执行3-1');
                    setTimeout(function () {
                        resolve();
                    }, 2000);
                })
            })
            .then(() => {
                console.log('timeout3');
            });
    }
    

    上面的代码就模拟了两个函数的执行过程。输出执行3,一秒后打印出执行3-1,再过两秒后输出timeout3

    可以清楚看到利用Promise实现的优势,多个函数执行只要再前一个Promisethen方法中再new一个Promise,同时再添加then用于接收下一个函数的执行结果。整个结构非常清晰,代码可维护。
    但是这边还要考虑一个问题,如果在这个串行过程中(A==>B==>C),其中某个函数执行出现了异常,那如何来捕获这个错误?幸运的是Promise已经提供了这样一个方法catch,可以用来捕获异常错误。

    {
        let ajax = function (num) {
            console.log('执行4', num);
            /**
             * resolve:要执行下一步的操作
             * reject:要终止当前的操作
             */
            return new Promise((resolve, reject) => {
                if (num > 5) {
                    resolve();
                } else {
                    throw  new Error('出错啦');
                }
            })
        };
    
        ajax(6).then(() => {
            console.log('log', 6);
        }).catch(err => {
            console.log('catch', err);
        });
    
        //修改传入的num值,num小于5就会抛出错误,catch能捕捉到该错误
        // ajax(2).then(() => {
        //     console.log('log', 6);
        // }).catch(err => {
        //     console.log('catch', err);
        // })
    }
    
    image.png
    二、Promise的高级用法
    • Promise.all
      在实际开发过程中,可能会遇到这样一个需求:加载三张图片,要求三张图片都加载完成后才显示在页面上。这里可以思考下应该如何实现呢?而Promise就提供来这样一个方法(Promise.all
    {
        // 所有图片加载完(忽略加载成功或加载失败)再添加到页面
        function loadImg(src) {
            return new Promise(((resolve, reject) => {
                let img = document.createElement('img');
                img.src = src;
                img.onload = function () {
                    resolve(img);
                };
    
                img.onerror = function (err) {
                    reject(err);
                }
            }))
        }
    
        function showImgs(imgs) {
            imgs.forEach(img => {
                document.body.appendChild(img);
            })
        }
    
        //Promise.all 将多个Promise实例当作一个Promise实例,当所有Promise实例的状态发生改变时,这个Promise实例才会跟着发生变化
        //在这里也就是说,只有当三个图片的所有的状态都完成之后,才会触发Promise.all这个新的Promise
        Promise.all([
            loadImg('https://pics6.baidu.com/feed/e4dde71190ef76c6f8a619195cd869fcae5167e5.jpeg?token=83461bdb4a26ce68441d12a04ce4c127&s=843053975A4226CC5F84691E0300C063'),
            loadImg('https://pics2.baidu.com/feed/77094b36acaf2edd362ad591288595ef3801930f.jpeg?token=939c0e1cf863beba12e9e0dfa3f42b23'),
            loadImg('https://pics7.baidu.com/feed/64380cd7912397dd701ca9865b2226b1d1a28775.jpeg?token=9df8d6fb97b587e7131aee048d334c6a')
        ]).then(showImgs)
    }
    
    • Promise.race
      Promise还有个Promise.race方法,这个方法的作用是多个Promise实例中任何一个Promise的状态完成后,这个新的Promise就会被执行。利用这个方法可以显示这样一个需求:假设有三张图片,要求其中任意一张图片加载完成,就显示在页面中。
    {
    
        // 任意一张图片加载完就添加到页面
        function loadImg(src) {
            return new Promise(((resolve, reject) => {
                let img = document.createElement('img');
                img.src = src;
                img.onload = function () {
                    resolve(img);
                };
    
                img.onerror = function (err) {
                    reject(err);
                }
            }))
        }
    
        function showImgs(img) {
            let p = document.createElement('p');
            p.appendChild(img);
            document.body.appendChild(p);
    
        }
    
        //Promise.race 三个Promise中任何一个Promise的状态发生改变,这个Promise就会发生改变
        //在这里也就是说,三张图片任一张图片加载完就显示在页面上,先到先得
        Promise.race([
            loadImg('https://pics6.baidu.com/feed/e4dde71190ef76c6f8a619195cd869fcae5167e5.jpeg?token=83461bdb4a26ce68441d12a04ce4c127&s=843053975A4226CC5F84691E0300C063'),
            loadImg('https://pics2.baidu.com/feed/77094b36acaf2edd362ad591288595ef3801930f.jpeg?token=939c0e1cf863beba12e9e0dfa3f42b23'),
            loadImg('https://pics7.baidu.com/feed/64380cd7912397dd701ca9865b2226b1d1a28775.jpeg?token=9df8d6fb97b587e7131aee048d334c6a')
        ]).then(showImgs)
    }
    

    相关文章

      网友评论

          本文标题:ES6(Promise)

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