使用闭包来委派正在运行的回调

时间:2018-03-29 07:01:31

标签: javascript node.js

我正在开发一个模块,其中我有一个带回调的函数,并且在其中调用另一个也需要回调的函数,类似于此

function doSomething(params..., callback){ //Do some work someOtherFunction(params.., callback2) //...??? }

我拥有它的方式是doSomething()是一个模块的入口点,它封装了一些特定于某个任务的逻辑,并通过doSomething()的回调参数与其他组件通信,在someOtherFunction()中它也可以调用其他回调函数。

是否可能 - 如果是这样的好习惯 - 使用闭包来包装提供给doSomething()的第一个回调,第二个使用闭包提供给someOtherFunction(),其方式类似于:

`function wrapCallbacks(err_cb2, arg_to_callback_2){
          function callback(err, res){
                   //first callback logic
          }
          function callback2(err, res){
                   //second callback logic
                   callback(err, res)
          }
          callback2(err_cb2, arg_to_callback_2)
}`

并提供此函数作为someOtherFunction()的回调,并且如果需要,它内部可以对其他回调执行相同的操作,以便回调将以“last-in-first-out”顺序执行,这样我可以在整个模块完成它的工作后执行第一次回调吗?

PS:我是一名新手javascript程序员,我非常感谢我对javascript的理解中任何明显的误解。

我正在研究我的最后一年项目,我正在尝试构建一个点对点系统,允许开发人员以接近常规客户端 - 服务器SPA和REST的方式构建分布式对等应用程序基于应用程序,我试图通过构建一个本地服务器来实现这一点,该服务器将侦听来自本地机器上的浏览器的请求 - 本质上是基于客户端 - 服务器的请求,类似于RESTful API-并将它们转换为检索和存储数据并将其作为结果提供给浏览器发起的第一个API调用的消息。

我正在使用分层架构来分离职责并提供抽象层,而有问题的函数sendMessage_interface()是堆栈最后一层的入口点 - 负责将对等ID解析为套接字以供使用对于通信 - 所以这个函数会从用户那里获取类似'ID'的参数,执行一些数据库操作来检索相关的IP-通过调用resolveID()函数 - resolveID()函数将进行回调并提供它结果 - 对等套接字 - 作为参数,但是sendMessage_interface()函数也提供了上层的回调,以便在从另一个对等方收到响应之后执行,这就是为什么我需要它来执行'LIFO'< / p>

`this.comms_gateway_sendMessage_interface = function({destID, data, 
resolveID, checkMessageObject, callback}){

    if(!(destID && data && resolveID && callback) ||
    !(typeof(destID) === 'number') ||
    !(typeof(resolveID) === 'function') ||
    !(typeof(callback) === 'function'))
    {
        throw new TypeError('Invalid or missing Argument');
    };
    if(checkMessageObject && typeof(checkMessageObject) === 'function'){
        checkMessageObject(data);
    };

    resolveID({ID : destID, data : data, callback : wrapCallback });
};`

1 个答案:

答案 0 :(得分:1)

回调hilight是JavaScript的一个主要特性。函数是数据的事实使得使用函数作为其他函数的参数变得容易。在交易中,这通常被称为高阶函数。

闭包是另一个主要特征:

  • 内部函数继承外部函数的范围,这使得管理变量范围变得更加容易
  • 如果外部函数已完成,但内部函数尚未运行,则保留外部作用域变量,因此在内部函数运行时可以使用它们的数据。

当外部函数内部函数定义时,闭包特征可用。在另一个函数内引用函数不足以使闭包变量可用。我们说JavaScript有词汇范围:范围是严格定义代码的地方。

使用多个回调总是很尴尬。如果没有必要持久化闭包变量,你可以这样做:

window.setTimeout(fn1,1000);

function fn1() {
    alert('one');
    window.setTimeout(fn2,1000);
}
function fn2() {
    alert('two');
    window.setTimeout(fn3,1000);
}
function fn3() {
    alert('three');
}

不涉及嵌套,并且完全可维护。

但是,如果你想在下一个函数中使用来自一个函数的数据,那么下一个函数将需要在里面第一个函数来访问它的变量:

window.setTimeout(fn1,1000);

function fn1() {
    var data=0;
    alert(`data ${++data}`);
    window.setTimeout(fn2,1000);
    function fn2() {
        alert(`data ${++data}`);
        window.setTimeout(fn3,1000);
    }
    function fn3() {
        alert(`data ${data++}`);
    }
}

如果第三个函数需要使用第二个函数生成的数据,情况会变得更糟:

window.setTimeout(fn1,1000);

function fn1() {
    var data=0;
    alert(`data ${++data}`);
    window.setTimeout(fn2,1000);
    function fn2() {
        var stuff=3;
        alert(`data ${++data + stuff}`);
        window.setTimeout(fn3,1000);
        function fn3() {
            alert(`data ${++data + stuff}`);
        }
    }
}

这被称为回调地狱,你可以理解为什么要尽可能避免它。但是,它是回调可以从闭包变量中受益的唯一方法 - 如果函数是在另一个内部定义的。

所以,简短的回答是肯定的,这是可能的,是的,这是一种很好的做法,因为这是做这类事情的唯一传统方式。

更现代的JavaScript有一个叫做promises的替代方案:它们允许你链接回调函数而不是嵌套它们,所以你可以用更线性的方式编写代码。