如何强制顺序JavaScript执行?

我只find相当复杂的答案,涉及类,事件处理程序和callback(这似乎是一个有点大锤的方法)。 我认为callback可能是有用的,但我似乎不能在最简单的情况下应用这些。 看到这个例子:

<html> <head> <script type="text/javascript"> function myfunction() { longfunctionfirst(); shortfunctionsecond(); } function longfunctionfirst() { setTimeout('alert("first function finished");',3000); } function shortfunctionsecond() { setTimeout('alert("second function finished");',200); } </script> </head> <body> <a href="#" onclick="javascript:myfunction();return false;">Call my function</a> </body> </html> 

在此,第二个函数在第一个函数之前完成; 什么是最简单的方法(或者是否有)?强制第二个函数延迟执行,直到第一个函数完成?

– -编辑 – –

所以这是一个垃圾的例子,但感谢大卫Hedlund我看到这个新的例子,它确实是同步的(与我的浏览器在testing过程中崩溃!):

 <html> <head> <script type="text/javascript"> function myfunction() { longfunctionfirst(); shortfunctionsecond(); } function longfunctionfirst() { var j = 10000; for (var i=0; i<j; i++) { document.body.innerHTML += i; } alert("first function finished"); } function shortfunctionsecond() { var j = 10; for (var i=0; i<j; i++) { document.body.innerHTML += i; } alert("second function finished"); } </script> </head> <body> <a href="#" onclick="javascript:myfunction();return false;">Call my function</a> </body> </html> 

由于我的实际问题是使用jQuery和IE,我将不得不单独发布一个关于这个问题的问题,如果我自己无法得到任何东西!

那么, setTimeout ,根据它的定义,将不会妨碍该线程。 这是可取的,因为如果这样做,它会冻结整个用户界面等待的时间。 如果你真的需要使用setTimeout ,那么你应该使用callback函数:

 function myfunction() { longfunctionfirst(shortfunctionsecond); } function longfunctionfirst(callback) { setTimeout(function() { alert('first function finished'); if(typeof callback == 'function') callback(); }, 3000); }; function shortfunctionsecond() { setTimeout('alert("second function finished");', 200); }; 

如果你使用setTimeout ,而只是有很长的执行时间的函数,并且使用setTimeout来模拟,那么你的函数实际上是同步的,你根本就没有这个问题。 但是,应该注意的是,AJAX请求是asynchronous的,并且像setTimeout ,在完成之前不会setTimeout UI线程。 有了AJAX,和setTimeout ,你必须使用callback。

我经常回到这个问题,因为花了我很长时间才发现我认为是一个干净的解决scheme:我知道强制执行javascript顺序执行的唯一方法就是使用promise。 Promise / A和Promises / A +的承诺有详尽的解释

唯一的库实现承诺我知道的是jQuery所以这里是我将如何解决使用jQuery的承诺问题:

 <html> <head> <script src="jquery-1.9.1.min.js"></script> <script type="text/javascript"> function myfunction() { promise = longfunctionfirst().then(shortfunctionsecond); } function longfunctionfirst() { d = new $.Deferred(); setTimeout('alert("first function finished");d.resolve()',3000); return d.promise() } function shortfunctionsecond() { d = new $.Deferred(); setTimeout('alert("second function finished");d.resolve()',200); return d.promise() } </script> </head> <body> <a href="#" onclick="javascript:myfunction();return false;">Call my function</a> </body> </html> 

通过使用.then()来实现promise和链接函数,你可以确保第二个函数只有在第一个函数执行后才会被执行。这是longfunctionfirst()中的d.resolve()命令,它让信号开始下一个function。

从技术上讲,shortfunctionsecond()不需要创build一个延期并返回一个承诺,但我爱上了承诺,倾向于用承诺来实现一切,抱歉。

我是一个编程的老手,最近回到我的旧激情,并努力适应这个面向对象,事件驱动的明亮的新世界,而我看到的JavaScript的非顺序行为的优点有时间,它真的得到以简单和可重用的方式。 我曾经做过一个简单的例子,就是拍摄一张照片(用javascript,HTML,phonegap等编程的手机),resize并上传到网站上。 理想的顺序是:

  1. 拍个照
  2. 将照片加载到img元素中
  3. 调整图片大小(使用Pixastic)
  4. 将其上传到网站
  5. 通知用户成功失败

所有这些都是一个非常简单的顺序程序,如果每一步完成时都要把控制权交给下一个控制权,但实际上:

  1. 拍一张照片是asynchronous的,所以程序试图在img元素存在之前加载它
  2. 加载照片是asynchronous的,所以在img完全加载之前resize图片
  3. resize是asynchronous的,所以上传到网站开始之前,图片是完全resize
  4. 上传到网站是asyn,所以程序继续之前照片是完全上传。

顺便说一句,5个步骤中的4个涉及callback函数。

因此,我的解决scheme是嵌套在前一个步骤,并使用.onload和其他类似的策略,它看起来像这样:

 takeAPhoto(takeaphotocallback(photo) { photo.onload = function () { resizePhoto(photo, resizePhotoCallback(photo) { uploadPhoto(photo, uploadPhotoCallback(status) { informUserOnOutcome(); }); }); }; loadPhoto(photo); }); 

(我希望我没有犯太多的错误,把代码带到真正重要的地方,太过分了)

这是我相信一个完美的例子,asynchronous不好,同步是好的,因为与Ui事件处理相反,我们必须在下一个执行前完成每一步,但代码是一个俄罗斯娃娃build设,它是混乱和不可读的,代码的可重用性是很难实现的,因为所有的嵌套都很难把所有需要的参数都传递给内部函数,而不是依次传递给每个容器或者使用邪恶的全局variables,我会喜欢所有的结果这段代码会给我一个返回代码,但是第一个容器会在返回代码可用之前完成。

现在回到汤姆最初的问题,15年前使用C和愚蠢的电子板怎么会是一个非常简单的程序,聪明,易于阅读,易于重用的解决scheme?

这个要求其实很简单,我的印象是,我必须错过对Javsascript和现代编程的基本理解,当然,技术是为了提高生产力吗?

谢谢你的耐心

雷蒙德恐龙;-)

在JavaScript中,没有办法让代码等待。 我有这个问题,我做的方式是做一个同步SJAX调用服务器,服务器实际上执行睡眠或做一些活动之前,返回和整个时间,js等待。

例如Sync AJAX: http ://www.hunlock.com/blogs/Snippets: _Synchronous_AJAX

在你的例子中,第一个函数在第二个函数启动之前确实完成了。 setTimeout不会保持函数的执行,直到达到超时时间,它只会在后台启动一个计时器,并在指定的时间后执行您的提醒语句。

在JavaScript中没有原生的方式来做“睡眠”。 你可以写一个循环来检查时间,但这会给客户端带来很大的压力。 你也可以像emacsian描述的那样进行同步AJAX调用,但是这会给你的服务器带来额外的负担。 你最好的select是避免这种情况,一旦你了解了setTimeout的工作原理,这对大多数情况来说应该很简单。

我尝试了callback的方式,不能让这个工作,你必须明白的是,即使执行不是,值仍然是primefaces的。 例如:

alert('1'); <—这两个函数将同时执行

alert('2'); <—这两个函数将同时执行

但是这样做会迫使我们知道执行的顺序:

 loop=2; total=0; for(i=0;i<loop;i++) { total+=1; if(total == loop) alert('2'); else alert('1'); } 

我有同样的问题,这是我的解决scheme:

 var functionsToCall = new Array(); function f1() { $.ajax({ type:"POST", url: "/some/url", success: function(data) { doSomethingWith(data); //When done, call the next function.. callAFunction("parameter"); } }); } function f2() { /*...*/ callAFunction("parameter2"); } function f3() { /*...*/ callAFunction("parameter3"); } function f4() { /*...*/ callAFunction("parameter4"); } function f5() { /*...*/ callAFunction("parameter5"); } function f6() { /*...*/ callAFunction("parameter6"); } function f7() { /*...*/ callAFunction("parameter7"); } function f8() { /*...*/ callAFunction("parameter8"); } function f9() { /*...*/ callAFunction("parameter9"); } function callAllFunctionsSy(params) { functionsToCall.push(f1); functionsToCall.push(f2); functionsToCall.push(f3); functionsToCall.push(f4); functionsToCall.push(f5); functionsToCall.push(f6); functionsToCall.push(f7); functionsToCall.push(f8); functionsToCall.push(f9); functionsToCall.reverse(); callAFunction(params); } function callAFunction(params) { if (functionsToCall.length > 0) { var f=functionsToCall.pop(); f(params); } } 

如果你不坚持使用纯Javascript,你可以在Livescript中build立一个连续的代码,它看起来不错 。 你可能想看看这个例子 :

 # application do i = 3 console.log td!, "start" <- :lo(op) -> console.log td!, "hi #{i}" i-- <- wait-for \something if i is 0 return op! # break lo(op) <- sleep 1500ms <- :lo(op) -> console.log td!, "hello #{i}" i++ if i is 3 return op! # break <- sleep 1000ms lo(op) <- sleep 0 console.log td!, "heyy" do a = 8 <- :lo(op) -> console.log td!, "this runs in parallel!", a a-- go \something if a is 0 return op! # break <- sleep 500ms lo(op) 

输出:

 0ms : start 2ms : hi 3 3ms : this runs in parallel! 8 3ms : hi 2 505ms : this runs in parallel! 7 505ms : hi 1 1007ms : this runs in parallel! 6 1508ms : this runs in parallel! 5 2009ms : this runs in parallel! 4 2509ms : hello 0 2509ms : this runs in parallel! 3 3010ms : this runs in parallel! 2 3509ms : hello 1 3510ms : this runs in parallel! 1 4511ms : hello 2 4511ms : heyy 

另一种看待这个问题的方法是从一个function链接到另一个function。 对所有被调用函数都有一个全局函数,例如:

 arrf: [ f_final ,f ,another_f ,f_again ], 

然后设置一个整数数组到特定的'f'你想运行,例如

 var runorder = [1,3,2,0]; 

然后用“runorder”作为参数调用初始函数,例如f_start(runorder);

然后在每个函数结束时,只需将索引popup到下一个“f”就可以执行runorder数组并执行它,仍然将“runorder”作为parameter passing,但数组减1。

 var nextf = runorder.shift(); arrf[nextf].call(runorder); 

显然这终止于一个函数,比如在索引0处,不会链接到另一个函数。 这是完全确定性的,避免了“定时器”。