哪种写回调更好?

时间:2012-12-20 04:09:52

标签: javascript asynchronous callback

只是看到我现在写的东西,我可以看到一个小得多,所以就code golf Option 2来说是更好的选择,但就哪个更干净,我更喜欢Option 1。我真的很喜欢社区对此的意见。

选项1

something_async({
    success: function(data) {
        console.log(data);
    },
    error: function(error) {
        console.log(error);
    }
});

选项2

something_async(function(error,data){
    if(error){
        console.log(error);
    }else{
        console.log(data);
    }
});

4 个答案:

答案 0 :(得分:6)

它们并不完全相同。选项2仍将记录(数据),而选项1仅记录成功数据。 (编辑:至少在更改代码之前就是这样)

那就是说,选项1更具可读性。编程不是/不应该是一个竞争,看谁能写出做最多事情的最少的线。我的目标应该始终是创建可维护的,可扩展的(如果必要的)代码 - 以我的拙见。

答案 1 :(得分:2)

许多人会发现选项#1更易于阅读和维护 - 两种不同的回调函数可用于两种不同的目的。它通常由所有Promise Libraries使用,其中将传递两个参数。当然,问题Multiple arguments vs. options object与此无关(虽然该对象在jQuery.ajax中很有用,但对promise.then没有意义。)

但是,选项#2是Node.js convention(另请参阅NodeGuide)并在许多受其影响的库中使用,例如着名的async.js。但是,这个约定是可以讨论的,我发现的最高谷歌搜索结果是WekeRoad: NodeJS Callback ConventionsStackoverflow: What is the suggested callback style for Node.js libraries?

带有错误参数的单回调函数的原因是它总是提醒开发人员处理错误,这在服务器端应用程序中尤其重要。许多初学者在客户端ajax函数不关心忘记错误处理,例如,问自己为什么不调用成功回调。另一方面,then - 链接的承诺是基于错误回调的可选性,将它们传播到下一个级别 - 当然它仍然需要被捕获。

答案 2 :(得分:0)

说实话,我更倾向于将它们更进一步,进入Promises / Futures / Deferreds / etc ...... 或者(/和)使用主持人(或观察者/子酒吧)进入“自定义事件”队列,如果有充分理由让一个特定对象 < / strong> for data)。

这不是百分之百的时间。有时,您只需要一次回调。但是,如果您有多个视图需要对更改做出反应(在模型数据中,或者可视化用户交互),那么使用一堆硬编码结果的单个回调是不合适的。

moderator.listen("my-model:timeline_update", myView.update);
moderator.listen("ui:data_request", myModel.request);
button.onclick = function () { moderator.notify("ui:data_request", button.value); }

现在很少依赖于一个大的回调,你可以混合和匹配并重用代码。

如果您想隐藏主持人,可以将其作为对象的一部分:

var A = function () {
        var sys = null,
            notify = function (msg, data) {
                if (sys && sys.notify) { sys.notify(msg, data); }
            },
            listen = function (msg, callback) {
                if (sys && sys.listen) { sys.listen(msg, callback); }
            },
            attach = function (messenger) { sys = messenger; };

        return {
            attach : attach
            /* ... */
        };
    },
    B = function () { /* ... */ },

    shell = Moderator(),
    a = A(),
    b = B();

    a.attach(shell);
    b.attach(shell);

    a.listen("do something", a.method.bind(a));
    b.notify("do something", b.property);

如果这看起来有点熟悉,它的行为与Backbone.js相似(除了它们extend()对象的行为,其他人将绑定,我的示例已简化包装器以显示正在发生的事情)

Promise将是可用性,可维护性和易读性代码的另一个重大胜利(只要人们知道“承诺”是什么 - 基本上它传递了一个具有回调订阅的对象。)

// using jQuery's "Deferred"

var ImageLoader = function () {
    var cache = {},

        public_function = function (url) {
            if (cache[url]) { return cache[url].promise(); }
            var img = new Image(),
                loading = $.Deferred(),
                promise = loading.promise();

            img.onload  = function () { loading.resolve(img); };
            img.onerror = function () { loading.reject("error"); };
            img.src = url;
            cache[url] = loading;
            return promise;
        };

    return public_function;
};

// returns promises
var loadImage = ImageLoader(),

    myImg = loadImage("//site.com/img.jpg");


myImg.done( lightbox.showImg );
myImg.done( function (img) { console.log(img.width); } );

或者     var blog_comments = [/ * ... * /],

    comments = BlogComments();

blog_comments.forEach(function (comment) {
    var el = makeComment(comment.author, comment.text),
        img = loadImage(comment.img);

    img.done(el.showAvatar);
    comments.add(el);
});

所有这些都是为了展示 强大的承诺。
看那里的.forEach电话。 我正在使用Image加载而不是AJAX,因为在这种情况下它似乎更明显:

我可以加载数百个博客评论,如果同一个用户发多个帖子,图像被缓存,如果没有,我不必等待加载图像,或编写嵌套回调。图像以任何顺序加载,但仍然出现在正确的位置。

这也是100%适用于AJAX调用。

答案 3 :(得分:0)

Promises已被证明是异步的方式,像bluebird这样的库包含节点式回调(使用(err, value)签名)。因此,利用节点式回调似乎是有益的。

但问题中的示例可以通过以下函数轻松转换为任一格式。 (另)

function mapToNodeStyleCallback(callback) {
  return {
    success: function(data) {
      return callback(null, data)
    },
    error: function(error) {
      return callback(error)
    }
  }
}

function alterNodeStyleCallback(propertyFuncs) {
  return function () {
    var args = Array.prototype.slice.call(arguments)
    var err = args.shift()
    if (err) return propertyFuncs.err.apply(null, [err])
    return propertyFuncs.success.apply(null, args)
  }
}