Web 前端开发

回调

2018-08-20  本文已影响12人  小红依

回调函数包裹或者说封装了程序的延续

顺序的大脑

大脑对于事情的计划方式是线性的、阻塞的、单线程的语义,但是回调表达异步流程的方式是非线性的、非顺序的,这使得正确推导这样的代码难度太大。

我们需要一种更同步、更顺序、更阻塞的方式来表达异步,想我们的大脑一样。

信任问题

回调会受到控制反转的影响,因为回调把控制权交给了第三方来调用你代码中的continuation。这会导致一系列麻烦,比如:

我们可以用一些方法(可能并不是很好的方法)来解决这些问题。

为了更优雅的处理错误,有些api设计提供了分离回调

function success(data) {
    console.log(data)
}
function failure(err) {
    console.log(err)
}
ajax('url',success,failure)

另外一种经常处理错误的方式被称做“error-first 风格”

function response(err,data) {
    if(err) {
        console.err(err)
    }
    else {
        console.log(data)
    }
}
ajax('url',response)

如果产生了错误,第一个参数就会被置真。

这种做法并没有真正的解决信任问题。这并为涉及阻止或过滤不想要的重复调用回调函数的问题。而现在的情况是,你可能同时得到成功或者失败的的结果,或者也可能两种都得不到。

完全不调用的信任问题

如果有完全不调用的情况,我们应该设着一个超时来取消事件。

function timeoutify() {
    var intv = setTimeout(function(){
        intv = null;
        fn(new Error("Timeout"))
    },delay)
    return function() {
        if(intv) {
            clearTimeout(intv);
            fn.apply(this.argument)
        }
    }
}

function foo(err,data){
    if(err) {
        console.log(err)
    } else {
        console.log(data)
    }
}
ajax(url,timeoutify(foo,500))

还有一个是信任过早的问题
看这样一段代码

var a = 0;
function result(data) {
    console.log(a)
}
ajax(url,result)
a++

打印出来的a是什么呢?我们知道,可能是0也可能是1。

如果是打印出来0,那很有可能是信任过早的问题。因为ajax的请求需要一点时间。如果是0则说明函数没有异步执行。

我们可以用这样的办法来保证函数的异步执行。

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)
        }
    }
}
ajax(url,asyncify(result))

这样做之后,a的输出只有1。

虽然这些解决问题的办法都没有很完美,但是解决问题的思路是值得借鉴的。理解这些方法,对今后的工作会很有用。

上一篇 下一篇

猜你喜欢

热点阅读