【问题标题】:How to support 2 types of callback in Javascript如何在 Javascript 中支持 2 种类型的回调
【发布时间】:2016-05-18 04:31:10
【问题描述】:

intercom-client github 我看到了这段代码:

client.users.list(function (d) {
  // d is the response from the server
});

// Or

client.users.list(function (err, d) {
  // err is an error response object, or null
  // d is a successful response object, or null
});

我的问题是:intercom 如何知道我是通过funcrtion(err,d) 还是只是通过function(data)

我检查了源代码,发现他们使用bluebird 库。蓝鸟是怎么做到的?

我希望我的函数也能做到这一点。

换句话说:

function myFunction(data,callback){
  if (callbackListenToErrArgument(callback)) 
       callback(null,data)
   else
       callback(data)

}

callbackListenToErrArgument功能如何实现?

【问题讨论】:

    标签: javascript node.js bluebird intercom


    【解决方案1】:

    可以检查正在传递的函数的.length 属性。 .length 属性是为函数定义的参数数量。

    function hasErrorArgument(callback) {
      if (callback.length < 2) { return false; } // Has 1 or 0.
      else return true; // has 2 or more
    } // Yes, I know it can be reduced to one line. Sue me.
    

    请注意:这是不好的做法。您应该为您接受的回调提供统一的签名。 (err, data) =&gt; {} 是一个很好的签名。

    或者更好的是,让您的 list() 函数返回一个 Promise 对象:(仅在某些浏览器中原生支持 Promise。使用前检查兼容性,或使用 polyfill 或库) .

    client.users.list()
      .then(listOfUsers => {
        // Use data here
      })
      .catch(err => {
        // Handle errors here
      });
    

    【讨论】:

    • 谢谢。请解释一下:(err, data) =&gt; {} (function(){}).length 在大多数浏览器中都有效吗?这是新事物吗?你知道IE6吗?
    • (err, data) =&gt; {} 是 ES6 等价于 function(err, data) {}fn.length 从我记事起就存在,如果您仍需要 IE6 支持,愿上帝怜悯您的灵魂。
    • IE6,是一种询问这是 JavaScript 基础还是来自革命的一种方式……我不是在问 IE5.5,谁不支持 @ 987654334@, 和call...
    • fn.length 在任何地方都受支持。 ()=&gt;{} 语法不是(但与 Babel 一起使用)。
    • ……返回 promise 是一种更好的做法。
    【解决方案2】:

    假设看方法长度:

    fun=function(a,b,c) {
      console.log(a,b,c)
    }
    (a,b,c) {
      console.log(a,b,c)
    }
    fun.prototype.constructor.length
    3
    

    可能被认为是一种不好的做法,正如@madara-uchiha 所说,bluebird 库有一个方法调用函数:

    var makeMethodCaller = function (methodName) {
        return new Function("ensureMethod", "                                    \n\
            return function(obj) {                                               \n\
                'use strict'                                                     \n\
                var len = this.length;                                           \n\
                ensureMethod(obj, 'methodName');                                 \n\
                switch(len) {                                                    \n\
                    case 1: return obj.methodName(this[0]);                      \n\
                    case 2: return obj.methodName(this[0], this[1]);             \n\
                    case 3: return obj.methodName(this[0], this[1], this[2]);    \n\
                    case 0: return obj.methodName();                             \n\
                    default:                                                     \n\
                        return obj.methodName.apply(obj, this);                  \n\
                }                                                                \n\
            };                                                                   \n\
            ".replace(/methodName/g, methodName))(ensureMethod);
    };
    

    [更新] 我添加了 Bluebird 代码的工作 sn-p 来讨论它。正如有人所说,这似乎适用于其他东西,即使在 switch 案例中有一个方法长度保护。检查代码:

    var console={}
    console.log=function(msgs) { document.writeln(msgs)};
    
    var makeMethodCaller = function (methodName) {
        return new Function("ensureMethod", "                                    \n\
            return function(obj) {                                               \n\
                var len = this.length;                                           \n\
                console.log(\"Who is this\"+this);                                           \n\
                ensureMethod(obj, 'methodName');                                 \n\
                switch(len) {                                                    \n\
                    case 1: return obj.methodName(this[0]);                      \n\
                    case 2: return obj.methodName(this[0], this[1]);             \n\
                    case 3: return obj.methodName(this[0], this[1], this[2]);    \n\
                    case 0: return obj.methodName();                             \n\
                    default:                                                     \n\
                        return obj.methodName.apply(obj, this);                  \n\
                }                                                                \n\
            };                                                                   \n\
            ".replace(/methodName/g, methodName))(ensureMethod);
    };
    function ensureMethod(obj, methodName) {
        var fn;
        if (obj != null) fn = obj[methodName];
        if (typeof fn !== "function") {
            var message = "Object " + JSON.stringify(obj) + " has no method '" +
                JSON.stringify(methodName) + "'";
            throw new Error(message);
        }
        return fn;
    }
    var fn=makeMethodCaller("callMe");
    
    
    console.log(fn)
    
    var obj0= {
     callMe : function() { console.log("\n\n\ncalled with 0 params")}
    };
    var obj1= {
     callMe : function(a) { console.log("\n\n\ncalled with 1 params")}
    };
    var obj2= {
     callMe : function(a,b) { console.log("\n\n\ncalled 2 params")}
    };
    var obj3= {
     callMe : function(a,b,c) { console.log("\n\n\ncalled 3 params")}
    };
    
    
    [obj0,obj1,obj2,obj3].map(function(e) { 
      return fn( e );
    });

    【讨论】:

    • 为什么它是不好的做法,为什么你的方法更好?你在那里做什么?为什么要以这种方式创建新函数new Function()
    • @Amina 对不起,我澄清一下。 Bluebird 方法与检查长度的方法完全相同。看看那里的switch case。它检查函数参数长度并选择正确的断言...我不争论为什么不好,只是意识到bluebird使用该解决方案;)
    • @loretoparisi:我很确定 this 在你引用的代码中不是一个函数,而是一个数组。
    • 顺便说一句,fun.prototype.constructor === fun
    • 正如我所说,它们是在数组上调用的。那些“methodCaller”函数只是this simple method 的过度优化版本(没有作为最后一个数组元素传递的方法名称)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-29
    • 1970-01-01
    相关资源
    最近更新 更多