这是我的计算器上的第一篇文章,所以请不要火焰我太辛苦,如果我遇到像一个总傻子,或者如果我无法OT让自己非常清楚。 : - )

下面是我的问题。我试图写一个JavaScript函数“关系”两个功能到另一个通过检查第一个的完成,然后执行第二个

最简单的解决方案,这显然是写它的范围内调用这两个函数的元函数。然而,如果第一功能是异步的(具体AJAX调用)和第二功能要求的第一个的结果数据,即根本不会工作。

我的解决方案的想法是,得到第一功能的“标志”,即使它创建一个公共属性“this.trigger”(初始化为“0”,一旦完成设置为“1”),一旦它被称为;这样做,应该有可能使另一个功能检查标志的值([0,1])。如果条件被满足(“触发== 1”),第二函数应该被调用。

下面是一个抽象的示例代码,我已经用于测试:

<script type="text/javascript" >

/**/function cllFnc(tgt) { //!! first function

    this.trigger = 0 ;
    var trigger = this.trigger ;

    var _tgt = document.getElementById(tgt) ; //!! changes the color of the target div to signalize the function's execution
        _tgt.style.background = '#66f' ;

    alert('Calling! ...') ;

    setTimeout(function() { //!! in place of an AJAX call, duration 5000ms

            trigger = 1 ;

    },5000) ;

}

/**/function rcvFnc(tgt) { //!! second function that should get called upon the first function's completion

    var _tgt = document.getElementById(tgt) ; //!! changes color of the target div to signalize the function's execution
        _tgt.style.background = '#f63' ;

    alert('... Someone picked up!') ;

}

/**/function callCheck(obj) {   

            //alert(obj.trigger ) ;      //!! correctly returns initial "0"                         

    if(obj.trigger == 1) {              //!! here's the problem: trigger never receives change from function on success and thus function two never fires 

                        alert('trigger is one') ;
                        return true ;
                    } else if(obj.trigger == 0) {
                        return false ;
                    }


}

/**/function tieExc(fncA,fncB,prms) {

        if(fncA == 'cllFnc') {
            var objA = new cllFnc(prms) ;   
            alert(typeof objA + '\n' + objA.trigger) ;  //!! returns expected values "object" and "0"
        } 

        //room for more case definitions

    var myItv = window.setInterval(function() {

        document.getElementById(prms).innerHTML = new Date() ; //!! displays date in target div to signalize the interval increments


        var myCallCheck = new callCheck(objA) ; 

            if( myCallCheck == true ) { 

                    if(fncB == 'rcvFnc') {
                        var objB = new rcvFnc(prms) ;
                    }

                    //room for more case definitions

                    window.clearInterval(myItv) ;

            } else if( myCallCheck == false ) {
                return ;
            }

    },500) ;

}

</script>

在HTML部分来进行测试:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/strict.dtd >

<html>

<head>

    <script type="text/javascript" >
       <!-- see above -->
    </script>

    <title>

      Test page

    </title>


</head>

<body>

    <!-- !! testing area -->

        <div id='target' style='float:left ; height:6em ; width:8em ; padding:0.1em 0 0 0; font-size:5em ; text-align:center ; font-weight:bold ; color:#eee ; background:#fff;border:0.1em solid #555 ; -webkit-border-radius:0.5em ;' >
            Test Div
        </div>

        <div style="float:left;" >
            <input type="button" value="tie calls" onmousedown="tieExc('cllFnc','rcvFnc','target') ;" />
        </div>

<body>


</html>

我敢肯定,这是一些问题与JavaScript范围,因为我已经检查触发器是否被设置为“1”,正确它。极有可能是“checkCall()”函数没有收到更新的对象,而是只能通过设置“this.trigger”到“1”检查其旧的实例,这显然从未标志完成。如果是这样,我不知道如何解决这个问题。

总之,希望有人有一个想法或经验,用这种特殊的问题。

感谢阅读!

FK

有帮助吗?

解决方案 4

我已经工作了,似乎现在的工作非常清楚。我会后我的代码后后,我已经整理出来。在此期间,非常感谢您帮助!

<强>更新

试图在Webkit的(野生动物园,铬),Mozilla和Opera的代码。似乎工作就好了。期待任何答复。

<强>更新2

我改变了tieExc()方法来整合阿努拉格的链式函数调用的语法。现在,您可以作为很多功能,只要你想在完成检查通过将它们作为参数来调用。

如果你不倾向于阅读的代码,试试吧: http://jsfiddle.net/UMuj3/ (顺便说一句,的jsfiddle是一个非常整洁的网站!)。

JS-代码:

/**/function meta() {

var myMeta = this ;

/**  **/this.cllFnc = function(tgt,lgt) { //!! first function

    this.trigger = 0 ;  //!! status flag, initially zero
    var that = this ;   //!! required to access parent scope from inside nested function

    var _tgt = document.getElementById(tgt) ; //!! changes the color of the target div to signalize the function's execution
    _tgt.style.background = '#66f' ;

    alert('Calling! ...') ;

    setTimeout(function() { //!! simulates longer AJAX call, duration 5000ms

        that.trigger = 1 ;  //!! status flag, one upon completion

    },5000) ;

} ;

/**  **/this.rcvFnc = function(tgt) { //!! second function that should get called upon the first function's completion

    var _tgt = document.getElementById(tgt) ; //!! changes color of the target div to signalize the function's execution
    _tgt.style.background = '#f63' ;

    alert('... Someone picked up!') ;

} ;

/**  **/this.callCheck = function(obj) {    

    return (obj.trigger == 1)   ?   true
        :   false
        ;

} ;

/**  **/this.tieExc = function() {

    var functions = arguments ;

    var myItv = window.setInterval(function() {

        document.getElementById('target').innerHTML = new Date() ; //!! displays date in target div to signalize the interval increments

        var myCallCheck = myMeta.callCheck(functions[0]) ; //!! checks property "trigger"

        if(myCallCheck == true) { 

            clearInterval(myItv) ;

            for(var n=1; n < functions.length; n++) {

                functions[n].call() ;

            }

        } else if(myCallCheck == false) { 
            return ;
        }

    },100) ;



} ;

}​

HTML

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/strict.dtd >

<html>

<head>

    <script type='text/javascript'  >
        <!-- see above -->
    </script>
    <title>

      Javascript Phased Execution Test Page

    </title>

</head>

<body>

        <div id='target' style='float:left ; height:7.5em ; width:10em ; padding:0.5em 0 0 0; font-size:4em ; text-align:center ; font-weight:bold ; color:#eee ; background:#fff;border:0.1em solid #555 ; -webkit-border-radius:0.5em ;' >
            Test Div
        </div>

        <div style="float:left;" >
            <input type="button" value="tieCalls()" onmousedown="var myMeta = new meta() ; var myCll = new myMeta.cllFnc('target') ; new myMeta.tieExc(myCll, function() { myMeta.rcvFnc('target') ; }, function() { alert('this is fun stuff!') ; } ) ;" /><br />
        </div>

<body>


</html>

其他提示

您可以采取JS的功能的优势被称为闭合。再加上所谓的“延续传递风格”的一种很常见的JS模式,你有你的解决方案。 (这些都不东西都是原始到JS,但在JS大量使用)。

// a function
function foo(some_input_for_foo, callback)
{
    // do some stuff to get results

    callback(results); // call our callback when finished
}

// same again
function bar(some_input_for_bar, callback)
{
    // do some stuff to get results

    callback(results); // call our callback when finished
}

在“延续通过式”指的是回调。而不是返回值,每个函数调用的回调(继续),并赋予它的结果。

可以再配合两个一起容易地:

foo(input1, function(results1) {

    bar(results1, function(results2) {

        alert(results2);
    });
});

在嵌套的匿名函数可以“看到”变量从他们居住的范围。所以没有必要使用特殊的属性是传递信息。

<强>更新

要澄清一下,在你的问题的代码片段,很显然,你大致想是这样的:

  

我有一个长期运行的异步   操作,所以我需要知道它的时候   完成以开始下一   操作。所以,我需要做的是   声明作为属性可见。然后   在其他地方,我可以在一个循环中运行,   反复审查其财产   看的时候它更改为“已完成”   状态,所以我知道何时继续。

(然后作为一个复杂的因素,循环必须使用setInterval开始运行,并clearInterval退出,允许其他JS代码运行 - 但它基本上是一个“轮询循环”不过)。

您不需要做!

而不是使你的第一个功能设置上完成的属性,使其调用一个函数。

为了使这绝对清楚的,让我们来重构你的原代码:

function cllFnc(tgt) { //!! first function

    this.trigger = 0 ;
    var trigger = this.trigger ;

    var _tgt = document.getElementById(tgt) ; //!! changes the color...
    _tgt.style.background = '#66f' ;

    alert('Calling! ...') ;

    setTimeout(function() { //!! in place of an AJAX call, duration 5000ms

        trigger = 1 ;

    },5000) ;
}

[<强>更新2 :顺便提及,有一个错误存在。您复制trigger属性的当前值到名为trigger一个新的局部变量。那么,在年底分配1到局部变量。没有人是要能够看到这一点。局部变量是私有的功能。 但你并不需要做任何这无论如何,所以请继续阅读...

所有我们所要做的就是告诉函数调用什么当它完成,并摆脱了财产设置的:

function cllFnc(tgt, finishedFunction) { //!! first function

    var _tgt = document.getElementById(tgt) ; //!! changes the color...
    _tgt.style.background = '#66f' ;

    alert('Calling! ...') ;

    setTimeout(function() { //!! in place of an AJAX call, duration 5000ms

        finishedFunction(); // <-------- call function instead of set property

    },5000) ;
}

现在有没有必要为您的“呼叫检查”或您的特殊tieExc帮手。可以方便地与非常少的代码扎两个函数在一起。

var mySpan = "#myspan";

cllFnc(mySpan, function() { rcvFnc(mySpan); });

的这另一优点是,我们可以通过不同的参数到所述第二功能。你的方法,同样的参数传递到两个。

例如,第一功能可以做了几个呼叫到AJAX服务(使用jQuery为了简洁):

function getCustomerBillAmount(name, callback) {

    $.get("/ajax/getCustomerIdByName/" + name, function(id) {

        $.get("/ajax/getCustomerBillAmountById/" + id), callback);

    });
}

下面,callback接受客户帐单量和AJAX get呼叫传递接收到的值,以我们通过它的功能,所以callback已兼容,因此可以直接作为回调用于第二AJAX调用。因此,这是在本身出现什么(从外侧)依次尝试将两个异步调用一起和它们包装的一个例子是一个单一的异步函数。

然后,我们可以用另一操作连锁这样:

function displayBillAmount(amount) {

    $("#billAmount").text(amount); 
}

getCustomerBillAmount("Simpson, Homer J.", displayBillAmount);

或者,我们可以(再次)已经使用了匿名功能:

getCustomerBillAmount("Simpson, Homer J.", function(amount) {

    $("#billAmount").text(amount); 
});

因此,通过链接函数调用这样的,每一个步骤可以向前将信息传递给下一个步骤,只要它是可用的。

通过使他们完成时,功能执行的回调,你是从什么限制中解脱出来,每一个功能的内部工作原理。它可以做AJAX调用,定时器,等等。只要“延续”回调被传递正向,可以有任何数目的异步工作层。

基本上,在异步系统中,如果你发现自己写一个循环来检查变量,看看它是否已经改变状态,然后出了问题的地方。取而代之的应该是提供一个函数T的方式帽子将被称为当状态改变时。

<强>更新3

我在别处看到在评论你提到的实际问题是缓存的结果,所以我所有的工作说明,这是浪费时间。这是什么样的事情,你应该把在的问题。

<强>更新4

最近我写很短的博客文章上在JavaScript 缓存异步调用的结果的主题。

(更新4的端部)

另一种方式共享的结果是给一个回调提供一种方式来“广播”或“发布”到几个用户:

function pubsub() {
    var subscribers = [];

    return {
        subscribe: function(s) {
            subscribers.push(s);
        },
        publish: function(arg1, arg2, arg3, arg4) {
            for (var n = 0; n < subscribers.length; n++) {
                subscribers[n](arg1, arg2, arg3, arg4);
            }
        }
    };
}

所以:

finished = pubsub();

// subscribe as many times as you want:

finished.subscribe(function(msg) {
    alert(msg);
});

finished.subscribe(function(msg) {
    window.title = msg;
});

finished.subscribe(function(msg) {
    sendMail("admin@mysite.com", "finished", msg);
});

然后让一些慢的操作发布其结果:

lookupTaxRecords("Homer J. Simpson", finished.publish);

当一个呼叫完成,它将现在请所有三个订户。

在明确的答案,这“给我打电话,当你准备好”的问题是一个的回调的。回调基本上是分配给对象属性(如“onload事件”)的功能。当对象的状态改变时,函数被调用。例如,该功能使一个AJAX请求到给定URL时,它的完整的惨叫:

function ajax(url) {
    var req = new XMLHttpRequest();  
    req.open('GET', url, true);  
    req.onreadystatechange = function (aEvt) {  
        if(req.readyState == 4)
            alert("Ready!")
    }
    req.send(null);  
}

当然,这是不够灵活,因为我们大概要为不同的Ajax调用不同的操作。幸运的是,JavaScript是一种功能性的语言,所以我们可以简单地传递所需要的动作作为一个参数:

function ajax(url, action) {
    var req = new XMLHttpRequest();  
    req.open('GET', url, true);  
    req.onreadystatechange = function (aEvt) {  
        if(req.readyState == 4)
            action(req.responseText);
    }
    req.send(null);  
}

此第二函数可用于这样的:

 ajax("http://...", function(text) {
      do something with ajax response  
 });

作为每注释,此处作为一例如何在物体内使用AJAX

function someObj() 
{
    this.someVar = 1234;

    this.ajaxCall = function(url) {
        var req = new XMLHttpRequest();  
        req.open('GET', url, true);  

        var me = this; // <-- "close" this

        req.onreadystatechange = function () {  
            if(req.readyState == 4) {
                // save data...
                me.data = req.responseText;     
                // ...and/or process it right away
                me.process(req.responseText);   

            }
        }
        req.send(null);  
    }

    this.process = function(data) {
        alert(this.someVar); // we didn't lost the context
        alert(data);         // and we've got data!
    }
}


o = new someObj;
o.ajaxCall("http://....");

我们的想法是“关闭”(化名)“这个”的事件处理程序,以便它可以进一步通过。

欢迎到SO!顺便说一句,你看起来是一个总的傻子,你的问题是完全不清楚:)

这是对构建@使用continuation的丹尼尔的回答。这是一个简单的函数链多种方法在一起。很像管|在UNIX中是如何工作的。这需要一组函数作为参数将被按顺序执行。每个函数调用的返回值被传递到下一个功能作为一个参数。

function Chain() {
    var functions = arguments;

    return function(seed) {
        var result = seed;

        for(var i = 0; i < functions.length; i++) {
            result = functions[i](result);
        }

        return result;
    }
}

要使用它,创建Chained传递所有函数作为参数的对象。一个例子可以上拨弄测试将是:

​var chained = new Chain(
    function(a) { return a + " wo"; },
    function(a) { return a + "r"; },
    function(a) { return a + "ld!"; }
);

alert(chained('hello')); // hello world!

要与一个AJAX请求使用它,通过链式函数作为成功回调了XMLHttpRequest。

​var callback = new Chain(
    function(response) { /* do something with ajax response */ },
    function(data) { /* do something with filtered ajax data */ }
);

var req = new XMLHttpRequest();  
req.open('GET', url, true);  
req.onreadystatechange = function (aEvt) {  
    if(req.readyState == 4)
        callback(req.responseText);
}
req.send(null);  

重要的是,每个函数依赖于前一功能的输出,所以你必须在每个阶段返回一定的价值。


这仅仅是一个建议 - 给检查数据是否可用本地或必须作出HTTP请求是要增加系统的复杂性的责任。取而代之的是,你可以有一个不透明的请求管理器,就像你有metaFunction,并让数据是否在本地或远程服之决定。

下面是一个样品Request对象处理这一情况,没有任何其它的目的或功能知道其中数据从已送达:

var Request = {
    cache: {},

    get: function(url, callback) {
        // serve from cache, if available
        if(this.cache[url]) {
            console.log('Cache');
            callback(this.cache[url]);
            return;
        }
        // make http request
        var request = new XMLHttpRequest();
        request.open('GET', url, true);
        var self = this;
        request.onreadystatechange = function(event) {
            if(request.readyState == 4) {
                self.cache[url] = request.responseText;
                console.log('HTTP');
                callback(request.responseText);
            }
        };
        request.send(null);
    }
};

要使用它,你会做出Request.get(..)一个电话,它的回报,如果缓存数据可用或使AJAX调用,否则。第三个参数可以被传递到控制数据应该有多长缓存,如果你正在寻找在高速缓存精细的控制。

Request.get('<url>', function(response) { .. }); // HTTP
// assuming the first call has returned by now
Request.get('<url>', function(response) { .. }); // Cache
Request.get('<url>', function(response) { .. }); // Cache

有一个非常简单的解决办法是让你的第一个Ajax调用同步。这是可选的参数中的一个。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top