如何实现可重用的callback函数

我相当新的JavaScript,我在节点工作,需要很好的理解asynchronous编程和callbackdevise。 我发现使用embedded式函数很容易,即使你的callback是多层次的。 您的embedded式callback只是最终被closures。

但是,如果在执行路由中有许多callback类似的callback,则最终会在不同的callback链中反复重写大量的callback代码。 例如,如果下面的mycb1和mycb2定义被移到A之外,那么它们不再具有对A的variables的隐式访问,因此不再作为闭包。

带有embedded式定义的示例,它们用作闭包。

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函数的variables作用域,以便它们可以被用作closures被调用的地方。 例如:

 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); } 

我知道我可以实现一个devise,或者在mod级别设置variables,以便他们可以访问mod级别的函数。 但是,这似乎有点污染的变数范围与variables,可能只能使用其中的几个方法。 我也知道我可以传入variables来使它们在执行时可以被callback访问。 但是,如果我明白JS和callback函数是如何工作的,那么我必须把它们传递给fooX,然后让foo把它们传递给callback函数。 这似乎也不是一个好的计划。 一个函数的variables范围是否可以改变,使得它在执行点而不是定义点方面起到闭包的作用? 如果不是,那么模块化callback代码的最好方法是什么?

一般来说,没有必要创build另一个可以访问闭包的内联函数。 你可以通过一个简单的匿名函数来创build这个函数,这个函数将一些参数作为parameter passing给父callback函数,而接受其余的函数(即部分函数),或者使用Function.bind()来创build部分函数本身。

例如,如果您最初有:

 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); ); } 

这是一个嵌套的callback示例,没有closures和嵌套。 抓取指定的页面,find第三个链接,然后显示该链接的来源。

在这种情况下,当在控制台中从这里运行并馈送主页时,注销页面是第三个链接,并且其内容被警告。

所有的callback是兄弟姐妹,没有外部状态variables,只是纯粹的functionasynchronous:

 // 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帮助程序使用非嵌套函数将responseText提供给“core”callback,而不是事件或整个xhr对象。