• 前端异步技术之Promise


    前言

    从事前端的朋友或多或少的接触过Promise,当代码中回调函数层级过多你就会发现Promise异步编程的魅力,相信此文一定能帮你排忧解惑!

    Promise概念

    Promise是JS异步编程中的重要概念,异步抽象处理对象,是目前比较流行Javascript异步编程解决方案之一
    或许是笔者理解能力有限,对官方术语怎么也感受不到亲切,下面我来用通俗易懂的语言解释下:
    Promise是一个包含三种状态的对象(pending、fulfilled、rejected),可以链式的处理异步请求(then方法)并能很好地处理异常问题,是解决回调地狱的良好方案之一。
    回调函数处理多层异步示例
    $.ajax({
        url: url1,
        success: function(rsp){
            $.ajax({
               url: url2,
               success: function(rsp){
                   $.ajax({
                      url: url3,
                      success: function(rsp){
                          //do sth
                      },
                      error: function(error){
                      }
                  });
               },
               error: function(error){
               }
           });
        },
        error: function(error){
        }
    });
    将promise封装在$.ajax中
    $.ajax = function(config){
        return new Promise(function(resolve, reject){
            //1省略...
            xmlhttp.onreadystatechange = function(){
                if(xmlhttp.status==200){
                    resolve(rspData);
                }else{
                    reject(xmlhttp.statusText);
                }
            };
            //2省略...
        })
    }
    $.ajax({url: url1}).then(function(val){
        return $.ajax({url: val.url})
    }).then(function(val){
        return $.ajax({url: val.url})
    }).catch(function(err){
        console.log(err);
    }}
    封装好的Promise处理异步可读性可维护性以及代码美观度不言而喻

    Promise API

    'new' Promise

    //pending状态的promise
    var promise = new Promise(function(resolve, reject){
        //do sth
    })
    //fulfilled状态的promise
    var promise = Promise.resolve(1).then(function resolve(value){console.log(value)});
    // var promise = new Promise(function(resolve){resolve(1)})
    //rejected状态的promise
    var promise = Promise.reject(new Error('error')).catch(function(error){console.error(error)});
    // var promise = new Promise(function(resolve,reject){resolve(new Error('error'))})

    Promise.prototype.then

    Promise#then
    promise.then(onFulfilled, onRejected)
    返回一个新的promise。这里经常会有一个疑问:为什么不返回原来的promise,个人是这样认为的,若返回同一个promise则状态不一致,promise规范说明当pending至fulfilled/rejected时状态确定后不能再改变。

    Promise.prototype.catch

    Promise#catch
    promise.catch(function(error){
        throw new Error(error);
    })
    注意:IE8及以下版本会出现 identifier not found 的语法错误,可将点标记法改为中括号标记法
    promise['catch'](function(error){
        throw new Error(error);
    })
    rejected状态的promise抛出异常
    相当于
    promise.then(undefined, onRejected)
    then & catch 结合示例
    promise.then(function f1(value){
        //do sth 1
    }).then(function f2(value){
        //do sth 2
    }).then(function f3(value){
        //do sth 3
    }).catch(function(error){
        console.log(error);
    })

    Promise.prototype.finally

    promise.finally(onFinally)
    返回一个Promise,在promise执行结束时,无论结果是fulfilled或者是rejected,在执行then()和catch()后,都会执行

    Promise.all

    promise.all([promise1, promise2, promise3]).then(resolve);
    示例
    // `delay`毫秒后执行resolve
    function timerPromisefy(delay) {
        return new Promise(function (resolve) {
            setTimeout(function () {
                resolve(delay);
            }, delay);
        });
    }
    var startDate = Date.now();
    // 所有promise变为resolve后程序退出
    Promise.all([
        timerPromisefy(1),
        timerPromisefy(32),
        timerPromisefy(64),
        timerPromisefy(128)
    ]).then(function (values) {
        console.log(Date.now() - startDate + 'ms');
        // 约128ms
        console.log(values);    // [1,32,64,128]
    });
    在接收到所有的对象promise都变为 FulFilled 返回一个resolve(array),或者 某一个promise对象变成Rejected 状态返回resolve(err)
    传递给 Promise.all 的promise并不是一个个的顺序执行的,而是同时开始、并行执行的。

    Promise.race

    promise.race([promise1, promise2]).then(resolve, reject)
    示例
    // `delay`毫秒后执行resolve
    function timerPromisefy(delay) {
        return new Promise(function (resolve) {
            setTimeout(function () {
                resolve(delay);
            }, delay);
        });
    }
    // 任何一个promise变为resolve或reject 的话程序就停止运行
    Promise.race([
        timerPromisefy(1),
        timerPromisefy(32),
        timerPromisefy(64),
        timerPromisefy(128)
    ]).then(function (value) {
        console.log(value);    // => 1
    });
    只要有一个promise对象进入 FulFilled 或者 Rejected 状态的话,就会继续进行后面的处理。

    Promise polyfill & Test

    promise-polyfill.js

    学习完Promise后,必定要重写Promise,后续遇到浏览器环境不支持也可有的放矢
    代码如下
    /**
     * @author chenchangyuan
     * @date 2019-02-23
     * */
    function Promise(executor){
        if(typeof executor !== 'function'){
            throw new Error('executor is not a function');
        }
        var self = this;
        self.state = 'pending';//pending fulfilled rejected
        self.value = null;
        self.reason = null;
        self.callbackResolveFn = [];
        self.callbackRejectFn = [];
        function resolve(value){
            if(self.state === 'pending'){
                self.state = 'fulfilled';
                self.value = value;
                self.callbackResolveFn.forEach(function(fn){
                    fn();
                });
            }
        }
        function reject(reason){
            if(self.state === 'pending'){
                self.state = 'rejected';
                self.reason = reason;
                self.callbackRejectFn.forEach(function(fn){
                    fn();
                });
            }
        }
        try{
            executor(resolve, reject);
        }catch(err){
            reject(err);
        }
    }
    //回溯函数
    function resolvePromise(promise, x, resolve, reject){
        if(promise === x) return reject(new TypeError('循环引用'));
        var flag = false;
        if(x !== null && (typeof x === 'object' || typeof x === 'function')){
            try{
                var then = x.then;
                if(typeof then === 'function'){
                    then.call(x, function(val){
                        if(flag) return;
                        flag = true;
                        resolvePromise(promise, val, resolve, reject);
                    }, function(err){
                        if(flag) return;
                        flag = true;
                        reject(err);
                    });
                }else{
                    resolve(x);
                }
            } catch(err){
                if(flag) return;
                flag = true;
                reject(err);
            }
    
        }else{
            resolve(x);
        }
    }
    //返回一个新的promise(pending:push(fn),fulfilled:resolve(val),rejected:reject(reason))
    Promise.prototype.then = function(onFulfilled, onRejected){
        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : function(value){
            return value;
        };
        onRejected = typeof onRejected === 'function' ? onRejected : function(err){
            throw new Error(err);
        };
        var self = this,
            promise2;
        if(self.state === 'fulfilled'){
            promise2 = new Promise(function(resolve, reject){
                setTimeout(function(){
                    try{
                        //将x处理成一个原始值
                        var x = onFulfilled(self.value);
                        resolvePromise(promise2, x, resolve, reject);
                    } catch(e){
                        reject(e);
                    }
                })
            })
        }
        if(self.state === 'rejected'){
            promise2 = new Promise(function(resolve, reject){
                setTimeout(function(){
                    try{
                        //将x处理成一个原始值
                        var x = onRejected(self.reason);
                        resolvePromise(promise2, x, resolve, reject);
                    } catch(e){
                        reject(e);
                    }
                })
            })
        }
        if(self.state === 'pending'){
            promise2 = new Promise(function(resolve, reject){
                self.callbackResolveFn.push(function(){
                    setTimeout(function(){
                        try{
                            //将x处理成一个原始值
                            var x = onFulfilled(self.value);
                            resolvePromise(promise2, x, resolve, reject);
                        } catch(e){
                            reject(e);
                        }
                    })
                });
                self.callbackRejectFn.push(function(){
                    setTimeout(function(){
                        try{
                            //将x处理成一个原始值
                            var x = onRejected(self.reason);
                            resolvePromise(promise2, x, resolve, reject);
                        } catch(e){
                            reject(e);
                        }
                    })
                });
            })
        }
        return promise2;
    }
    Promise.prototype['catch']= function (callback) {
        return this.then(undefined, callback)
    }
    Promise.all = function (promises) {
        return new Promise(function (resolve, reject) {
            let arr = [];
            let i = 0;
            function processData(index, y) {
                arr[index] = y;
                if (++i === promises.length) {
                    resolve(arr);
                }
            }
            for (let i = 0; i < promises.length; i++) {
                promises[i].then(function (y) {
                    processData(i, y)
                }, reject)
            }
        })
    }
    Promise.race = function (promises) {
        return new Promise(function (resolve, reject) {
            for (var i = 0; i < promises.length; i++) {
                promises[i].then(resolve,reject)
            }
        });
    }
    Promise.resolve = function(value){
        return new Promise(function(resolve,reject){
            resolve(value);
        });
    }
    Promise.reject = function(reason){
        return new Promise(function(resolve,reject){
            reject(reason);
        });
    }
    Promise.defer = Promise.deferred = function () {
        var d = {};
        d.promise = new Promise(function (resolve, reject) {
            d.resolve = resolve;
            d.reject = reject;
        });
        return d
    }
    module.exports = Promise;

    promise-aplus-tests

    由于是参(抄)考(袭)前辈的polyfill,自己编码测试时出现了两处错误,ES6 Promise 规范的2.3.1和2.3.4

    2.3.1

    2.3.4

    经过改正测试成功

    后记

    你们的支持是我最大的动力,熬夜码字不易,如果此文对你有帮助,请不吝star--->https://github.com/chenchangyuan/promise

    有兴趣加笔者好友的同学请扫描下方二维码(1.本人微信,2.微信公众号,3.技术交流微信群),愿与您成为好友共同探讨技术,畅聊生活!

    参考资料

    https://promisesaplus.com/

    http://liubin.org/promises-book

    https://juejin.im/post/5ab20c58f265da23a228fe0f







  • 相关阅读:
    mysql 锁相关的视图(未整理)
    MYSQL的用户变量(@)和系统变量(@@)
    mysql杀死线程
    mysql 系统变量和session变量
    Oracle DB 移动数据
    MySQL数据库------常用函数
    练习-----查询
    练习建表
    课堂笔记总结
    数据库--------用代码来创建表
  • 原文地址:https://www.cnblogs.com/ccylovehs/p/10425199.html
Copyright © 2020-2023  润新知