zoukankan      html  css  js  c++  java
  • [Effective JavaScript 笔记]第63条:当心丢弃错误

    管理异步编程的一个是错误处理。同步代码中只要使用try语句块包装一段代码很容易一下子处理所有的错误。

    try{
        f();
        g();
        h();
    } catch(e){
        //这里用来下得出现的错误
    }
    

    try语句块

    但对于异步的代码,多步的处理通常会被分隔到事件队列的单独轮次中,因此,不可能将它们包装在一个try语句块中。事实上异步的API甚至根本不可能抛出异常,因为,当一个异步的错误发生时,没有一个明显的执行上下文来抛出异常!相反,异步的API倾向于将错误表示为回调函数的特定参数,或使用一个附加的错误处理回调函数。例如,一个涉及下载文件的异步API可能会有一个额外的回调函数来处理网络错误。

    downloadAsync('http://cnblogs.com/wengxuesong',function(text){
        console.log('file contents:'+text);
    },function(error){
        console.log('error:'+error);
    });
    

    如果下载多个文件,可以像62条讲的,使用回调函数嵌套起来。

    downloadAsync('a.txt',function(a){
        downloadAsync('b.txt',function(b){
            downloadAsync('c.txt',function(c){
                console.log('Contents:'+a+b+c);
            },function(error){
                console.log('error:'+error);
            });
        },function(error){
            console.log('error:'+error);
        });
    },function(error){
        console.log('error:'+error);
    });
    

    上面代码上,每一步的处理都使用了相同的错误处理逻辑,然而我们在多个地方重复了相同的代码。在编程领域里,应该努力坚持避免重复代码。通过共享作用域中定义一个错误处理的函数,将重复代码抽象出来。

    function onError(error){
        console.log('Error:'+error);
    }
    downloadAsync('a.txt',function(a){
        downloadAsync('b.txt',function(b){
            downloadAsync('c.txt',function(c){
                console.log('Contents:'+a+b+c);
            },onError);
        },onError);
    },onError);
    

    如果使用工具函数downloadAllAsync将多个步骤合并到一个复合的操作中,那么,只需要提供一个错误处理的回调函数。

    downloadAllAsync(['a.txt','b.txt','c.txt'],function(abc){
        console.log('Contents:'+abc[0]+abc[1]+abc[2]);
    },function(error){
       console.log('Error:'+error); 
    });
    

    回调函数错误参数

    另一种错误处理API的风格是Node.js平台使用的。该风格只需要一个回调函数,该回调函数的第一个参数如果有错误发生就表示一个错误。否则就是一个假值,比如null。对于这类API,我们可以定义一个通用的错误处理函数,需要使用if语句来控制每个回调函数。

    function onError(error){
        console.log('Error:'+error);
    }
    downloadAsync('a.txt',function(error,a){
        if(error){
            onError(error);
            return;
        }
        downloadAsync('b.txt',function(error,b){
            if(error){
                onError(error);
                return;
            }
            downloadAsync('c.txt',function(error,c){
                if(error){
                    onError(error);
                    return;
                }
                console.log('Contents:'+a+b+c);
            });
        });
    });
    

    程序员通常会放弃if语句而使用大括号结构跨越多行的约定,以使得错误处理更简洁、更集中。

    function onError(error){
        console.log('Error:'+error);
    }
    downloadAsync('a.txt',function(error,a){
        if(error)return onError(error);
        downloadAsync('b.txt',function(error,b){
            if(error)return onError(error);
            downloadAsync('c.txt',function(error,c){
                if(error)return onError(error);
                console.log('Contents:'+a+b+c);
            });
        });
    });
    

    也可以使用一个抽象合并步骤来帮助消除重复

    var filenames=['a.txt','b.txt','c.txt'];
    downloadAllAsync(filenames,function(error,abc){
        if(error){
            console.log('Error:'+error);
            return;
        }
        console.log('Contents:'+abc[0]+abc[1]+abc[2]);
    });
    

    try...catch语句和在异步API中典型的错误处理逻辑的一个实际差异是,try语句使得定义一个"捕获所有"的逻辑很容易导致程序员难以忘怀整个代码区的错误处理。而上面给出的异步API,非常容易忘记在进程的任意一步提供错误处理。这将导致错误被丢弃。忽视错误处理的程序会令用户非常沮丧:应用程序出错时没有任何的反馈。类似的,默认的错误不好调试。因为没有提供问题来源的线索。最好是做好防御,即使用异步API需要警惕,确保明确地处理所有的错误状态条件。

    提示

    • 通过编写共享的错误处理函数来避免复制和粘贴错误处理代码

    • 确保明确地处理所有的错误条件以避免丢弃错误

  • 相关阅读:
    NES游戏历史
    NES资料
    Spring的自动装配
    springmvc框架如何将模型数据传递给视图 也就是Model>view参数的传递
    拆分Spring的配置文件
    Springmvc框架前台传值给controller @Requestparam @RequestMapping
    SpringMVC框架传入Map集合
    SpringMVC框架使用注解编写的处理请求和映射@Controller @RequestMapping
    SpringMVC初尝试
    MVC设计模式
  • 原文地址:https://www.cnblogs.com/wengxuesong/p/5694695.html
Copyright © 2011-2022 走看看