gpt4 book ai didi

javascript - "Phased"在javascript中执行函数

转载 作者:数据小太阳 更新时间:2023-10-29 05:46:03 25 4
gpt4 key购买 nike

这是我在 stackoverflow 上的第一篇文章,所以如果我遇到一个彻头彻尾的傻瓜,或者如果我无法让自己完全清楚,请不要对我发火。 :-)

这是我的问题:我正在尝试编写一个 javascript 函数,通过检查第一个函数的完成然后执行第二个函数来将两个函数“绑定(bind)”到另一个函数。

显然,解决这个问题的简单方法是编写一个元函数,在其范围内调用这两个函数。但是,如果第一个函数是异步的(特别是 AJAX 调用),而第二个函数需要第一个函数的结果数据,那根本行不通。

我对解决方案的想法是给第一个函数一个“标志”,即一旦调用它就创建一个公共(public)属性“this.trigger”(初始化为“0”,完成后设置为“1”);这样做应该可以让另一个函数检查标志的值([0,1])。如果满足条件(“trigger == 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

最佳答案

您可以利用 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);
});
});

嵌套的匿名函数可以从它们所在的范围内“看到”变量。因此无需使用特殊属性来传递信息。

更新

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

I have a long-running asynchronous operation, so I need to know when it finishes in order to start the next operation. So I need to make that state visible as a property. Then elsewhere I can run in a loop, repeatedly examining that property to see when it changes to the "completed" state, so I know when to continue.



(然后作为一个复杂因素,循环必须使用 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 分配给该局部变量。没有其他人能够看到这一点。局部变量是函数私有(private)的。但无论如何你都不需要这样做,所以请继续阅读......]

我们所要做的就是告诉该函数在完成后调用什么,并摆脱属性设置:
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 helper 。只需很少的代码,您就可以轻松地将两个函数绑定(bind)在一起。
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 call 将接收到的值传递给我们传递它的函数,所以 callback已经兼容,因此可以直接充当第二个 AJAX 调用的回调。因此,这本身就是将两个异步调用按顺序捆绑在一起并将它们包装在(从外部)看起来是单个异步函数的示例。

然后我们可以将它与另一个操作链接起来:
function displayBillAmount(amount) {

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

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

或者我们可以(再次)使用匿名函数:
getCustomerBillAmount("Simpson, Homer J.", function(amount) {

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

因此,通过像这样链接函数调用,每个步骤都可以在信息可用时立即将信息传递到下一步。

通过让函数在完成时执行回调,您可以摆脱对每个函数内部工作方式的任何限制。它可以做 AJAX 调用、定时器等等。只要“继续”回调向前传递,就可以有任意数量的异步工作层。

基本上,在异步系统中,如果您发现自己编写了一个循环来检查变量并确定它是否改变了状态,那么某处出现了问题。相反,应该有一种方法来提供将在状态更改时调用的函数。

更新 3

我在评论的其他地方看到你提到实际问题是缓存结果,所以我解释这一切的所有工作都是浪费时间。这是你应该提出的问题。

更新 4

最近我写了 a short blog post on the subject of caching asynchronous call results in 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);

当一个调用结束时,它现在将调用所有三个订阅者。

关于javascript - "Phased"在javascript中执行函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2552792/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com