Javascript知识整理——回调

作者: 俗三疯 | 来源:发表于2017-09-13 22:36 被阅读66次

    嵌套回调与链式回调

    嵌套回调
    listen('click',function hadler(evt){
        setTimeout(function request(){
            ajax('http://some.url.1',function response(text){
                if(text == 'hello'){
                    handler();
                }else if(text == 'world'){
                    request();
                }
            })
        },500);
    })
    

    这种代码常常被称为回调地狱,但并不是嵌套导致跟踪异步如此之难。

    链式回调
    listen('click',handler);
    function handler(){
        setTimeout(request,500)
    }
    function request(){
        ajax('http://some.url.1',response);
    }
    function response(text){
        if(text == 'hello'){
            handler();
        }else if(text == 'world'){
            request();
        }
    }
    

    尽管把代码编码成线性的,但在整个代码跳来跳去来“查看”流程,使追踪的难度增高。

    信任问题

    控制反转

    有时候如ajax(...)这样的第三方提供的代码不是你编写的代码,也不在你的直接控制之下,也就是把自己程序一部分的执行控制交给某个第三方,这种情况称为控制反转

    控制反转的问题
    • 调用回调过早(在追踪之前)
    • 调用回调过晚(或没有调用)
    • 调用回调的次数太少或太多
    • 没有吧所需的环境/参数成功传给你的回调函数
    • 吞掉可能呈现的错误或异常

    鉴于上面出现的这些问题,我们不得已构建全部的安全机制,进行相关值的检测,而且通常为每个异步回调重复这样的工作最后成为了负担

    回调设计的变体

    分离回调

    即一个用于成功通知,一个用于出错通知

    function succuess(data){
        console.log(data)
    }
    function failure(err){
        console.error(err);
    }
    ajax('http://some.url.1',success,failure)
    

    ES6 Promise API使用的就是这种分离回调

    error-first风格(Node风格)

    回调的第一个参数保留用作错误对象(如果有的话),成功的话,这个参数就会被清空/置假(后续的参数就是成功的数据),如果产生了错误结果,那么第一个参数就会被置起/置真

    fucntion response(err,data){
        if(err){
            console.error(err);
        }else{
            console.log(data)
        }
    }
    ajax('http://some.url.1',response)
    
    解决完全不调用问题
    function timeoutify(fn,delay){
        var intv = setTimeout(function(){
            intv = null;
            fn(new Error("Timeout!"));
        },delay);
        return function(){
            if(intv){
                clearTimeout(intv);
                fn.apply(this,arguments);
            }
        }
    }
    function foo(err,data){
        if(err){
            console.error(err);
        }else{
            console.log(data)
        }
    }
    ajax('http://some.url.1',timeoutify(foo,500));
    
    解决调用过早(缓存)
    function asyncify(fn){
        var orig_fn = fn,
            intv = setTimeout(function(){
                intv = null;
                if(fn) fn();
            },0);
            fn = null;
            return function(){
                if(intv){
                    fn = orig_fn.bind.apply(orig_fn,[this].concat([].slice.call(arguments)));
                }
            }
            else{
                orig_fn.apply(this,arguments);
            }
    }
    function result(data){
        console.log(a);
    }
    var a = 0;
    ajax('..pre-cached-url..',asyncify(result));
    a++;
    

    不管这个Ajax请求已经在缓存中并试图对回调立即调用,还是要从网络上取得,进而在将来异步完成,这段代码总是会输出1.

    上文为学习《你不知道的JS中卷》记录的笔记

    相关文章

      网友评论

        本文标题:Javascript知识整理——回调

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