Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/466.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
&引用;分阶段“;javascript中函数的执行_Javascript_Function_Execution_Phase - Fatal编程技术网

&引用;分阶段“;javascript中函数的执行

&引用;分阶段“;javascript中函数的执行,javascript,function,execution,phase,Javascript,Function,Execution,Phase,这是我在stackoverflow上的第一篇文章,所以如果我像一个十足的傻瓜一样遇到我,或者如果我不能完全清楚地表达自己,请不要太严厉地批评我。:-) 我的问题是:我试图编写一个javascript函数,通过检查第一个函数的完成情况,然后执行第二个函数,将两个函数“绑定”到另一个函数 显然,解决这个问题的简单方法是编写一个元函数,在其作用域内调用这两个函数。但是,如果第一个函数是异步的(特别是一个AJAX调用),而第二个函数需要第一个函数的结果数据,那么这根本不起作用 我的解决方案是在调用第一个

这是我在stackoverflow上的第一篇文章,所以如果我像一个十足的傻瓜一样遇到我,或者如果我不能完全清楚地表达自己,请不要太严厉地批评我。:-)

我的问题是:我试图编写一个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>
<!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>

/**/函数cllFnc(tgt){/!!第一个函数
这个.trigger=0;
var trigger=this.trigger;
var _tgt=document.getElementById(tgt);/!!更改目标div的颜色以表示函数的执行
_tgt.style.background='#66f';
警报(“呼叫!”);
setTimeout(function(){/!!代替AJAX调用,持续时间5000ms
触发器=1;
},5000) ;
}
/**/函数rcvFnc(tgt){/!!第一个函数完成时应调用的第二个函数
var _tgt=document.getElementById(tgt);/!!更改目标div的颜色以表示函数的执行
_tgt.style.background='#f63';
警惕(“……有人捡到了!”);
}
/**/函数调用检查(obj){
//警报(obj.trigger);/!!正确返回初始值“0”
如果(obj.trigger==1){/!!问题是:trigger在成功时从不从函数接收更改,因此函数2从不触发
警报(“触发器是一个”);
返回true;
}else if(obj.trigger==0){
返回false;
}
}
/**/功能TIEXC(fncA、fncB、prms){
如果(fncA=='cllFnc'){
var objA=新的cllFnc(prms);
警报(类型为objA+'\n'+objA.trigger);/!!返回预期值“object”和“0”
} 
//更多案例定义的空间
var myItv=window.setInterval(函数(){
document.getElementById(prms).innerHTML=new Date();/!!在目标div中显示日期以表示间隔增量
var myCallCheck=newcallcheck(objA);
如果(myCallCheck==true){
如果(fncB=='rcvFnc'){
var objB=新的rcvFnc(prms);
}
//更多案例定义的空间
窗口清除间隔(myItv);
}else if(myCallCheck==false){
返回;
}
},500) ;
}
用于测试的HTML部分:

<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>
<!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>

您可以利用JS的一个名为closure的功能。将其与一个非常常见的JS模式“continuation passing style”结合起来,您就有了解决方案。(这两种东西都不是JS的原创,但在JS中大量使用)

“延续传递样式”指的是回调。每个函数都调用回调(continuation)并给出结果,而不是返回值

然后,您可以轻松地将这两者捆绑在一起:

foo(input1, function(results1) {

    bar(results1, function(results2) {

        alert(results2);
    });
});
嵌套的匿名函数可以从它们所在的作用域中“查看”变量。因此,不需要使用特殊属性来传递信息

更新

为了澄清,在您的问题代码片段中,很明显您的想法大致如下:

 ajax("http://...", function(text) {
      do something with ajax response  
 });
我有一个长期运行的异步 手术,所以我需要知道什么时候开始 完成,以便开始下一步 活动所以我需要这样做 作为属性可见的状态。然后 在其他地方我可以循环运行, 反复检查该属性 查看何时更改为“已完成” 状态,以便我知道何时继续

(然后,作为一个复杂因素,循环必须使用
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:顺便说一句,那里有一个bug。您将
触发器
属性的当前值复制到一个名为
触发器
的新局部变量中。然后在最后为该局部变量指定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) ;
}
这种方法的另一个优点是,我们可以将不同的参数传递给第二个函数

例如,第一个函数可能对AJAX服务进行几次调用(为了简洁起见,使用jQuery):

这里,
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); 
});
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);
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);  
}
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  
 });
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://....");
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;
    }
}
​var chained = new Chain(
    function(a) { return a + " wo"; },
    function(a) { return a + "r"; },
    function(a) { return a + "ld!"; }
);

alert(chained('hello')); // hello world!
​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);  
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('<url>', function(response) { .. }); // HTTP
// assuming the first call has returned by now
Request.get('<url>', function(response) { .. }); // Cache
Request.get('<url>', function(response) { .. }); // Cache
/**/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) ;



} ;

}​
<!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>