Javascript 如何实现可重用的回调函数

Javascript 如何实现可重用的回调函数,javascript,node.js,callback,reusability,asynccallback,Javascript,Node.js,Callback,Reusability,Asynccallback,我对JavaScript相当陌生,我在node工作,这需要对异步编程和回调设计有很好的理解。我发现,即使回调是多层次的,使用嵌入式函数也非常容易。您的嵌入式回调最终只是闭包 mod.A=function(){ var mycb1=function(err){ if (!err){ var mycb2=function(err){ cb(err); }; mod.foo2(args,mycb2); } else{cb(

我对JavaScript相当陌生,我在node工作,这需要对异步编程和回调设计有很好的理解。我发现,即使回调是多层次的,使用嵌入式函数也非常容易。您的嵌入式回调最终只是闭包

mod.A=function(){
  var mycb1=function(err){
    if (!err){
      var mycb2=function(err){
        cb(err);
      };
      mod.foo2(args,mycb2);
    }
    else{cb(err);}
  };
  mod.foo1(args,mycb1);
}

mod.foo1 = function(args,cb){
  //do some work
  cb(err);
};

mod.foo2 = function(args,cb){
  //do some work
  cb(err);
} 
//execute
mod.A();
然而,当您有多个回调层,其中许多回调在执行路由中是相似的时,您最终会在单独的回调链中反复重写大量回调代码。例如,如果将下面的mycb1和mycb2定义移到A之外,则它们不再具有对A变量的隐式访问权限,因此不再作为闭包使用

具有嵌入定义的示例,其中它们用作闭包

mod.A=function(){
  var mycb1=function(err){
    if (!err){
      var mycb2=function(err){
        cb(err);
      };
      mod.foo2(args,mycb2);
    }
    else{cb(err);}
  };
  mod.foo1(args,mycb1);
}

mod.foo1 = function(args,cb){
  //do some work
  cb(err);
};

mod.foo2 = function(args,cb){
  //do some work
  cb(err);
} 
//execute
mod.A();
我希望执行以下操作,但是能够更改mycb1和mycb2函数的变量范围,以便它们可以从调用它们的任何地方用作闭包。 例如:

var mycb2=function(err){
  ...
  cb(err);
};

var mycb1=function(err){
  if (!err){        
    mod.foo2(args,mycb2);  //but have it act like a closure to mycb1
  }
  else{cb(err);}
};

mod.A=function(){
  ...
  mod.foo1(args,mycb1);  //but have it act like a closure to A
} 

mod.foo1 = function(args,cb){
  //do some work
  cb(err);
}

mod.foo2 = function(args,cb){
  //do some work
  cb(err);
}
我知道我可以实现一种设计,即在mod级别设置变量,以便mod级别的函数可以访问它们。然而,这似乎在某种程度上污染了mod作用域,变量只能由它的一些方法使用。我还知道,我可以传入变量,使回调在执行时可以访问它们。然而,如果我了解JS和回调是如何工作的,我就必须将它们传递给fooX,然后让foo将它们传递给回调。这似乎也不是一个好计划。
函数的变量范围是否可以更改,使其在执行点而不是定义点起到闭包的作用?如果没有,模块化回调代码以便重用的最佳方法是什么?

一般来说,不必创建另一个可以访问闭包的函数。您可以使用一个简单的匿名函数,在接受其余参数(即部分函数)的同时,将一些参数作为参数传递给父回调函数,或者使用创建部分函数本身,从而在线创建函数

例如,如果您最初有:

function(...) {
    // closure vars x1, y1
    foo.bar( function(result) {
        // do something with x1 and y1
    });
}
您可以将其提取到:

var callback = function(x1, y1, result) {
    // do something with x1 and y1
};

function(...) {
    // closure vars x1, y1

    // option 1: make your own partial function
    foo.bar( function(result) { return callback(x1, y1, result); });
    // with ES6: foo.bar( (result) => callback(x1, y1, result); });

    // option 2: use Function.bind
    foo.bar( callback.bind(this, x1, y1); );
}

下面是一个没有闭包和嵌套的嵌套回调示例。 它抓取指定的页面,找到第三个链接,然后向用户显示该链接的来源

在这种情况下,当在控制台中从这里运行并输入主页时,注销页面是第三个链接,它的内容会被警告

所有回调都是同级的,没有外部状态变量,只有纯函数异步:

// look ma, no nesting!
function ajax(a, c) {
    var e = new XMLHttpRequest;
    e.onload= ajaxOnload.bind(this, c, e);
    e.open( "GET", a, !0);
    e.send();
    return e
}

function ajaxOnload(c, e) {
    c(e.responseText, e);
}

function cbFind3(cb, s){
    var t=document.createElement("body");
    t.innerHTML=s;
    var lnk= t.getElementsByTagName("a")[3].href;
    ajax(lnk, cb);    
}

function grabThirdLinkSource(url, cb){
  ajax(url, cbFind3.bind(this, cb));
}

grabThirdLinkSource("/", alert);

这不是最有用的示例,但它确实展示了如何使用bind()跨调用链接函数。我使用香草ajax和避免承诺,只是为了展示这种风格的交互是如何执行的,没有任何复杂性。甚至ajax助手也使用非嵌套函数将responseText提供给“核心”回调,而不是事件或整个xhr对象

可以使用Function.bind()在运行时将已知值固定到命名回调中。如果我没弄错的话,这差不多接近于“从执行点关闭”。你也可以使用承诺来保持状态,而不会过度拥挤模块关闭提示。谢谢,这是我需要的。谢谢你详细说明答案。这对新手真的很有帮助:)谢谢。您的示例有助于确认前两位用户的建议。事实上,我想强制回调使用调用代码在其中执行的相同变量作用域执行,但在javascript中不能这样做。您可以使用分部函数或绑定强制对象作用域,但变量访问只能通过向函数参数传递参数来实现。您可以通过eval或,但从长远来看,使用参数传递的函数式方法通常效果更好,并且通过实施至少部分封装、可重用性和内置的“内存管理”来提高性能。一开始似乎有点不同,确实如此,但这种延续样式对于依赖/相关的异步进程非常有效。