• 前端,如何更优雅的面对异步


    本文是在阐述异步编程思想,让前端代码更易于维护,看起来更优雅!不是讲技术,但你若能耐心看完,一定会有收获。
    本文是不断补充的,随着开发实践的越来越多,以及技术的不断发展,代码可以写的越来越优雅!

    用 Promise 处理交互和异步

    前端开发经常会遇到这样的场景:

    当满足一定条件时,需要弹出一个模态框,以便接收用户的输入。然后根据不同的输入,进行不用的操作。(ps:这类场景太常见了)

    看了很多人的js代码,我发现大多数人的设计是这样的:

    modalModule{ 

      ……//其他代码。

      cancel(){

        closeModal();

      }

      ok(){

        handle(inputResult);

        closeModal();

      }  

    }

    parentModule{

      if(condition){

        call modalModule;

      }

    }

    这样设计,两个模块有严重的耦合:

    我们虽然写了一个modal模块,可是这个模块好像是专门为parent模块设计的。因为怎么处理结果,是完全取决于parent模块的业务需求的! 显然这样一个被量身打造的“专用模块”,几乎无法被重用。遗憾的是,我看到过很多这样设计的代码——想象一下,整个项目有大量类似的modal模块,打开模态框,关闭,确认等的这些代码 完全一样,唯一不同的就是handle。你能想象这是灾难吗?

    接下来,我们来换一种设计:(把模态交互设计成回调模式,让handle(inputResult)这部分在parentModule中执行!)

    modalModule{ 

      ……//其他代码。

      cancel(){

        Promise.reject();

        closeModal();

      }

      ok(){

        Promise.resolve(inputResult);

        closeModal();

      }

      return Promise;

    }

    parentModule{

      if(condition){

        call modalModule .then(res=>handle(res));

      }

    }

    这样设计可以发现,modalModule就是一个通用的模块了,绿色部分就是回调,表示对返回用户输入结果的一个承诺(promise),至于怎么处理这个结果就和它无关了——modalModule变得简单单一了。

    另外parentModule的功能更集中了,更方便阅读理解了。

    (多运用这种设计,自己感受,领悟它的好处吧!)

    多重异步时,函数式编程 避开层层嵌套的处理

    ——补充于: 2017-11-30 23:09:57

    前面学会使用Promise(rxjs中有更强大的Observable),代码一下子优雅了很多,但还不够!
    想一下这个场景:先验证数据有无过期,没有过期 创建一个班级,成功后为班级创建一个课程表,成功后取到按课程分类的数据,最终成功后展示列表,失败时给出提示,另外在这个过程中页面应当一直提示处理中 !

    很多人是这样处理的:

        func() {
            loading("处理中...");
            checkData().then(() => {
                createClass().then(() => {
                    createSchedule().then(() => {
                        getList().then(() => {
                            closeLoading();
                   showInPage(); }, err
    => { closeLoading(); toaster("获取课程表失败!"); }); }, err => { closeLoading(); toaster("创建课程表失败"); }); }, err => { closeLoading(); toaster("创建班级失败!"); }); }, err => { closeLoading(); toaster("数据已过期!"); }); }

    关于loading的控制少了一处都不行,会导致loading一直存在:异步处理,定义错误信息,关闭loading,弹出提示,揉在一起,稍有疏忽漏掉一个就报错!


    现在带大家体验一下函数式编程:

        func2(resolve,reject){
            checkData().then(() => {
                createClass().then(() => {
                    createSchedule().then(() => {
                        getList().then(() => {
                            resolve();
                        }, err => {
                            reject("获取课程表失败!");
                        });
                    }, err => {
                        reject("创建课程表失败");
                    });
                }, err => {
                    reject("创建班级失败!");
                });
            }, err => {
                reject("数据已过期!");
            });
    
        }
    
        func() {
            loading("处理中...");
            new Promise((resolve,reject)=>{
                func2(resolve,reject);
            }).then(()=>{
                closeLoading();      
                showInPage();      
            },msg=>{
                closeLoading();
                toaster(msg||"处理失败!");
            });
        }

    可以func2 中四个异步就是四个异步处理+定义错误信息,对于结束时的结果处理(处理只在一个地方,不用导出都是),在 func 中!
    这段代码 易读,易改,不易出错! 

    async 和 await + Promise链式调用

    补充于:2019年12月8日18:20:44

    现在看来上面的代码写的太糟糕了,先别说明明有了异步,为啥还要用函数式调用,至少存在回调地狱的问题!

    es2017的 async await 和 es2015的Promise链式调用 这两个特性对于解决该问题,非常有效,瞬间让你的代码可读性增强,非常优雅。请看修改: 

    async function func2() {
        await checkData().catch(() => {
            return Promise.reject("数据已过期!")
        })
        await createClass().catch(() => {
            return Promise.reject("创建班级失败!")
        })
        await createSchedule().catch(() => {
            return Promise.reject("创建课程表失败!")
        })
        await getList().catch(() => {
            return Promise.reject("获取课程表失败!")
        })
    }
    
    function func() {
        loading("处理中...")
        func2().then(() => {
            showInPage()
        }).catch(msg => {
            toaster(msg || "处理失败!");
        }).finally(() => {
            closeLoading()
        })
    }    

       

  • 相关阅读:
    精准测试
    git 管理
    git
    代码覆盖率测试
    vue 前端视频
    jenkins
    go学习资料
    4-4 求自定类型元素的平均
    4-3 简单求和
    4-2 多项式求值
  • 原文地址:https://www.cnblogs.com/zhwc-5w4/p/6908527.html
Copyright © 2020-2023  润新知