如何仅在多个其他函数完成后执行Javascript函数?

如何仅在多个其他函数完成后执行Javascript函数?,javascript,node.js,design-patterns,asynchronous,Javascript,Node.js,Design Patterns,Asynchronous,我的具体问题是,我需要执行(可能)大量Javascript函数来准备批处理文件(每个函数调用都会向同一批处理文件添加一些信息),然后在所有这些调用完成后,执行最后一个函数来发送批处理文件(例如,作为HTML响应发送)。我正在为此寻找一种通用的Javascript编程模式 概括问题: 给定Javascript函数funcA()、funcB()和funcC(),我想找出排序执行的最佳方法,以便funcC只能在funcA和funcB执行之后执行。我知道我可以使用这样的嵌套回调函数: funcA = f

我的具体问题是,我需要执行(可能)大量Javascript函数来准备批处理文件(每个函数调用都会向同一批处理文件添加一些信息),然后在所有这些调用完成后,执行最后一个函数来发送批处理文件(例如,作为HTML响应发送)。我正在为此寻找一种通用的Javascript编程模式

概括问题: 给定Javascript函数funcA()、funcB()和funcC(),我想找出排序执行的最佳方法,以便funcC只能在funcA和funcB执行之后执行。我知道我可以使用这样的嵌套回调函数:

funcA = function() {
    //Does funcA stuff
    funcB();
}
funcB = function() {
    //Does funcB stuff
    funcC();
}

funcA();
我甚至可以通过传入回调参数使这个模式更通用一些,但是,这个解决方案变得非常冗长

我还熟悉Javascript函数链接,其中的解决方案可能如下所示:

myObj = {}
myObj.answer = ""
myObj.funcA = function() {
    //Do some work on this.answer
    return this;
}
myObj.funcB = function() {
    //Do some more work on this.answer
    return this;
}
myObj.funcC = function() {
    //Use the value of this.answer now that funcA and funcB have made their modifications
    return this;
}
myObj.funcA().funcB().funcC();
虽然这个解决方案对我来说似乎有点干净,但随着计算步骤的增加,函数执行链会越来越长

对于我的具体问题,funcA、funcB等的执行顺序并不重要。因此,在我上面的解决方案中,我在技术上做了比所需更多的工作,因为我将所有函数按顺序排列。对我来说,重要的是funcC(用于发送结果或触发请求的函数)只有在funcA和funcB都完成执行后才被调用。理想情况下,funcC可以以某种方式侦听所有中间函数调用的完成,然后执行?我希望学习一种通用的Javascript模式来解决这样的问题

谢谢你的帮助

另一个想法是: 可能会将共享对象传递给funcA和funcB,当它们完成执行时,将共享对象标记为sharedThing.funcA=“complete”或sharedThing.funcB=“complete”,然后不知何故?当共享对象达到所有字段都标记为完成的状态时,让func执行。我不知道你怎么能让funcC等这个

编辑:
我应该注意,我使用的是服务器端Javascript(Node.js),我想学习一种模式,仅使用普通的旧Javascript(不使用jQuery或其他库)来解决它。当然这个问题已经足够普遍了,有一个干净的纯Javascript解决方案吗

查看jQuery的延迟对象。这提供了一种复杂的方法来控制在异步环境中发生的情况

这方面显而易见的用例是AJAX,但并不限于此

资源:


如果您想保持简单,可以使用基于计数器的回调系统。下面是一个系统的草稿,它允许
当(a,B)时,然后(C)
语法。(
/
时,那么
实际上只是糖,但整个系统也可以说是糖。)


如果您不使用任何异步函数,并且您的脚本没有破坏执行顺序,那么最简单的解决方案是,如Pointy和其他人所述:

funcA(); 
funcB();
funcC();
但是,由于您使用的是node.js,我相信您将使用异步函数,并希望在异步IO请求完成后执行
func
,因此您必须使用某种计数机制,例如:

var call_after_completion = function(callback){
    this._callback = callback;
    this._args = [].slice.call(arguments,1);
    this._queue = {};
    this._count = 0;
    this._run = false;
}

call_after_completion.prototype.add_condition = function(str){
    if(this._queue[str] !== undefined)
        throw new TypeError("Identifier '"+str+"' used twice");
    else if(typeof str !== "String" && str.toString === undefined)
        throw new TypeError("Identifier has to be a string or needs a toString method");

    this._queue[str] = 1;
    this._count++;
    return str;
}

call_after_completion.prototype.remove_condition = function(str){
    if(this._queue[str] === undefined){
        console.log("Removal of condition '"+str+"' has no effect");
        return;
    }
    else if(typeof str !== "String" && str.toString === undefined)
        throw new TypeError("Identifier has to be a string or needs a toString method");

    delete this._queue[str];

    if(--this._count === 0 && this._run === false){
        this._run = true;
        this._callback.apply(null,this._args);
    }
}
您可以通过忽略标识符
str
来简化此对象,只需增加/减少
this.\u count
,但是此系统可能对调试有用

要使用
call\u after\u completion
只需创建一个
new call\u after\u completion
,将所需函数
func
作为参数和
add\u条件
s<代码>函数仅在删除所有条件后才会调用

例子:
var foo=function(){console.log(“foo”);}
var bar=完成后的新调用(foo);
var i;
添加条件(“foo:3秒定时器”);
添加条件(“foo:附加函数”);
添加条件(“foo:for循环完成”);
功能附加功能(cond){
console.log(“其他事项”);
条件移除条件(“foo:附加功能”);
}
对于(i=0;i<1000;++i){
}
console.log(“for循环完成”);
移除_条件(“foo:for loop finished”);
附加_材料(bar);
setTimeout(函数(){
日志(“3秒超时”);
移除_条件(“foo:3秒定时器”);
},3000);

如果您不想使用任何帮助程序库,而需要自己编写一些帮助程序,那么没有简单的单行解决方案

如果您希望以在同步情况下看起来一样可读的内容结束,请尝试一些延迟/承诺概念实现(它仍然是纯JavaScript),例如,使用
deferred
包,您可能会以以下简单内容结束:

// Invoke one after another:
funcA()(funcB)(funcC);

// Invoke funcA and funcB simultaneously and afterwards funcC:
funcA()(funcB())(funcC);

// If want result of both funcA and funcB to be passed to funcC:
deferred(funcA(), funcB())(funcC);

我在寻找同样的图案。我使用的API可以查询多个远程数据源。每个API都要求我向它们传递回调函数。这意味着我不能只启动一组自己的函数,然后等待它们返回。相反,我需要一个解决方案,它可以处理一组回调,这些回调可以根据不同数据源的响应程度以任意顺序调用

我提出了以下解决方案。JS在我最熟悉的语言列表中排名靠后,所以这可能不是一个很好的JS习惯用法

function getCallbackCreator( number_of_data_callbacks, final_callback ) {

    var all_data = {}

    return function ( data_key ) {

        return function( data_value ) {
            all_data[data_key] = data_value;

            if ( Object.keys(all_data).length == number_of_data_callbacks ) {
                final_callback( all_data );
            }
        }
    }
}

var getCallback = getCallbackCreator( 2, inflatePage );

myGoogleDataFetcher( getCallback( 'google' ) );
myCartoDataFetcher( getCallback( 'cartodb' ) );
编辑:这个问题是用node.js标记的,但是OP说,“我正在寻找一个通用的Javascript编程模式”,所以我已经发布了这个问题,尽管我没有使用node

how about:
funcC(funcB(funcA)));

我认为问题是因为有些函数运行时间更长,当funcA或funcB没有完成执行时,我们运行funcC可能会出现这样的情况。

现在,人们可以这样做:

funcA = function() {
    //Does funcA stuff
    funcB();
}
funcB = function() {
    //Does funcB stuff
    funcC();
}

funcA();
假设我们有funcA,funcB和funcC: 如果希望传递funcA和funcB结果
function getCallbackCreator( number_of_data_callbacks, final_callback ) {

    var all_data = {}

    return function ( data_key ) {

        return function( data_value ) {
            all_data[data_key] = data_value;

            if ( Object.keys(all_data).length == number_of_data_callbacks ) {
                final_callback( all_data );
            }
        }
    }
}

var getCallback = getCallbackCreator( 2, inflatePage );

myGoogleDataFetcher( getCallback( 'google' ) );
myCartoDataFetcher( getCallback( 'cartodb' ) );
how about:
funcC(funcB(funcA)));
promise.then(result_c => console.log('done.'));