由于javascript本身是单线程模型,这里主要通过Callbacks,Listeners,Control Flow Libraries
,Promises四种方式来实现异步操作。
Reference:
1.JavaScript异步编程的四种方法(转)
2.JavaScript
Promises
一、Callbacks(函数回调)
让我们首先以函数回调方式来开头,这种方式也是最基本,同时也是大家都知道的异步实现方法。
现在我们有两个函数:Function1,Function2,调用顺序是先调用完Function1,然后调用Function2,如果Function1是一个耗时操作的话,那么Function2就被阻塞住了。
所以在这里我们尝试使用异步试试:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
<script src= "~/Content/jquery.min.js" ></script>
<script type= "text/javascript" >
function
ajaxRequest(container)
{
$.ajax({
url: "Home/GetResult" ,
type: "post" ,
success: function
(data) {
container.append(data.message);
}
});
}
function
Function1(callback) {
setTimeout( function
() {
ajaxRequest($( ".container" ));
callback();
}, 1000);
}
function
Function2()
{
$( ".container" ).append( "Function2执行完毕" );
}
Function1(Function2);
</script> <div class = "container" ></div>
|
最后我们得到的结果是:
先是输出 "Function2执行完毕",等待三秒之后会输出 "Function1执行完毕".
这样做的好处就是方便,但是坏处就是如果执行的函数过多的话,需要一层套一层来进行,代码显得很乱,不容易维护。
顺便提一下,如果规定Funtion1执行完毕,才能执行Function2的话,那么我们就无需这么麻烦的设置回调了。直接利用下面代码:
Function1();
Function2();
即可。但是这样出现一个问题,就是最后输出结果是一块儿输出的。也就是会在同一时刻输出"Function1执行完毕Function2执行完毕"。
这是由于JS内部机制导致的,在JS内部,会将所有的更新UI操作排到最后进行,所以会导致同时输出。
要解决这个问题很简单,只需要利用:
Function1();
setTimeout(Function2,100);即可
二、Listeners(事件监听)
事件监听是Jquery里面非常著名,也是采用的非常多的处理方式。比如说下面代码:
$(".submit").on("click",function(){})
就是通过监听按钮的点击事件来执行后续的操作。
下面看代码模拟:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
<script type= "text/javascript" >
var
eventable = {
on: function
(event, cb) {
$( this ).on(event, cb);
},
trigger: function
(event) {
$( this ).trigger(event);
}
}
var
Function3 = {
run: function
() {
var
self = this ;
setTimeout( function
() {
ajaxRequest($( ".container1" ));
self.trigger( ‘done‘ );
}, 500);
}
}
var
Function4 = {
run: function
() {
var
self = this ;
setTimeout( function
() {
$( ".container1" ).append( "Function4执行完毕" );
self.trigger( ‘done‘ );
},500);
}
}
$.extend(Function3, eventable);
$.extend(Function4, eventable);
Function3.on( ‘done‘ , function
(event) {
Function4.run();
});
Function4.on( ‘done‘ , function
() {
$( ".container1" ).append( "任务完成。" );
});
Function3.run();
</script> <div class = "container1" ></div>
|
同样,我们得出了和第一种方式一样的结果,两个函数均为异步进行。
三、PUB/SUB(发布订阅模式,也就是观察者模式)
所谓的发布订阅模式就是指,源负责发布,然后一个或者多个目标进行接收订阅,一旦有新的信息,会主动推送给订阅者。
下面我们采用Ben
Alman的Tiny Pub/Sub插件来完成,这是一个Jquery插件,你可以在这里下载:https://github.com/cowboy/jquery-tiny-pubsub
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
<script src= "~/Content/ba-tiny-pubsub.min.js" ></script>
<script type= "text/javascript" >
var
Function5 = {
run: function
() {
setTimeout( function
() {
$.ajax({
url: "Home/GetResult" ,
type: "post" ,
success: function
(data) {
$( ".container2" ).append(data.message);
jQuery.publish( "done" );
}
});
}, 500);
}
}
var
Function6 = {
run: function
() {
setTimeout( function
() {
$( ".container2" ).append( "Function6执行完毕" );
}, 500);
}
}
Function5.run();
jQuery.subscribe( "done" , Function6.run);
</script> <div class = "container2" ></div>
|
得到的最终结果是:AjaxFunction执行完毕.Function6执行完毕,这也完全符合我们的预期。
四、Promises对象
首先这个对象的介绍可以follow这个网站:http://wiki.commonjs.org/wiki/Promises/A
还有这个:http://www.html5rocks.com/zh/tutorials/es6/promises/
其目的是为异步编程提供统一接口。
每一个promise 对象都有一个then方法,可以指定回调函数。这样我们只需要以 func1().then(func2) 的形式进行调用即可。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
<script type= "text/javascript" >
var
Function7 = function
() {
var
deferred = $.Deferred();
alert(deferred.state());
setTimeout( function
() {
$.ajax({
url: "Home/GetResult" ,
type: "post" ,
success: function
(data) {
$( ".container3" ).append(data.message);
if
(deferred.state() === "pending" ) {
deferred.notify( "正在处理中...." );
}
deferred.resolve(); //可以带上参数进行传参操作。
}
});
}, 500);
return
deferred.promise();
}
var
Function8 = function
() {
var
deferred = $.Deferred();
setTimeout( function
() {
$( ".container3" ).append( "Function8执行完毕" );
deferred.resolve();
}, 500);
return
deferred.promise();
}
$.when(Function7()).then(Function8).then( function
() {
$( ".container3" ).append( "全部执行完毕" );
});
</script> <div class = "container3" ></div>
|
运行起来的时候,我们发现,事情是按照我们预想的方向发展。依次按顺序输出了: AjaxFunction执行完毕
Function8执行完毕 全部执行完毕。
这样写的功能非常强大,当我们有很多的函数需要规定执行顺序的时候,我们可以利用这种方式进行链式执行。同时由于promise提供的强大的错误处理手段,不用担心整体的崩溃。
后端的请求代码很简单,就是假死3秒,然后返回json串。
1
2
3
4
5
6
7
8
9
10
|
[HttpPost] public
JsonResult GetResult()
{ Thread.Sleep(3000);
var
result = new
{
message = "AjaxFunction执行完毕."
};
return
Json(result, JsonRequestBehavior.AllowGet);
} |
粗略的写道这里,还希望你能够欣赏。有时间的话,准备专门详细研究下JQuery的Promise,敬请期待。