回调

作者: 小红依 | 来源:发表于2018-08-20 19:16 被阅读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。

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

相关文章

  • Promise

    回调 把一个函数A传给另一个函数B调用,那么A就是回调函数。 回调地狱 回调套回调套回调套回调套回调套回调套回调....

  • 回调、同步回调、异步回调

    异步消息的传递-回调机制 原文地址:https://www.ibm.com/developerworks/cn/l...

  • 前端入门11 -- JavaScript之Promise

    回调函数 回调函数分为两种类型,分别为同步回调与异步回调; 同步回调:会立即执行,完全执行完了才结束,不会放入回调...

  • 回调函数与promise

    回调 把一个函数A传给另一个函数B调用,那么A就是回调函数 具名回调写法 匿名回调写法 多层嵌套的匿名回调(回调地...

  • 回调函数与promise

    回调 把一个函数A传给另一个函数B调用,那么A就是回调函数 具名回调写法 匿名回调写法 多层嵌套的匿名回调(回调地...

  • Kotlin使用接口回调

    1.Java中的接口回调实现(支持多方法回调) 声明回调接口,初始化接口 使用接口回调(无参数) 使用接口回调(带...

  • Promise

    回调 把一个函数A传给另一个函数B调用,那么A就是回调函数一个最基本的具名回调匿名回调 回调地狱匿名回调嵌套过多层...

  • [swift]回调block回调

    在OC中习惯应用block进行事件回调,到swift中依然想找到这种简洁的回调事件,下面将介绍如何在swift中使...

  • 回调函数,优化回调

    $.Callbacks(['once']或者['memory']或者['unique']或者['stopOnFal...

  • Dart 语法

    回调 dart定义回调 dart使用回调 延时 异步

网友评论

    本文标题:回调

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