Javascript语言的执行环境是”单线程”(single thread)。所谓”单线程”,就是指一次只能完成一件任务。如果有多个任务,就必须排队,前面一个任务完成,再执行后面一个任务,以此类推。 Javascript语言将任务的执行模式分成两种:同步(Synchronous)和异步(Asynchronous)。 “异步模式”非常重要。在浏览器端,耗时很长的操作都应该异步执行,避免浏览器失去响应,最好的例子就是Ajax操作。在服务器端,”异步模式”甚至是唯一的模式,因为执行环境是单线程的,如果允许同步执行所有http请求,服务器性能会急剧下降,很快就会失去响应。 然而,异步执行最大的问题就是执行顺序。 假定有两个函数f1和f2,后者等待前者的执行结果。
function f2() {
console.log("f2");
}
function f1(callback) {
console.log("f1");
setTimeout(function(){
callback();
}, 1000);
}
// 执行
f1(f2);
优点是简单、容易理解和部署; 缺点是不利于代码的阅读和维护,各个部分之间高度耦合(Coupling),流程会很混乱,而且每个任务只能指定一个回调函数。
这里采用的jQuery的写法
var eventable = {
on: function(event, cb) {
$(this).on(event, cb);
},
trigger: function (event, args) {
$(this).trigger(event, args);
}
}
var f1 = {
run: function() {
setTimeout(function(){
// f1执行逻辑
console.log("f1");
f1.trigger("done");
}, 1000);
}
};
$.extend(f1, eventable);
f1.on("done", f2);
f1.run();
优点是比较容易理解,可以绑定多个事件,每个事件可以指定多个回调函数,而且可以”去耦合”(Decoupling),有利于实现模块化; 缺点是整个程序都要变成事件驱动型,运行流程会变得很不清晰。
补充:<注意上述f1的写法> 当使用eval()函数或者是Function构造函数以及使用setTimeout()传一个字符串参数时都会发生“双重解释”。
eval("console.log('Hello Eval!')");
var sayHello = new Function("console.log('Hello Function!')");
setTimeout("console.log('Hello setTimeout!')", 1000);
这些操作不能在初始化的解析过程中完成的,也就是说在JavaScript代码运行的同时必须新启动一个解析器来解析新的代码。性能消耗较大。
console.log('Hello Eval!')
var sayHello = function() {
console.log('Hello Function!')
};
setTimeout(function(){
console.log('Hello Function!')
}, 1000)
使用jQuery插件https://github.com/cowboy/jquery-tiny-pubsub
jQuery.subscribe("done", f2);
function f1(){
// f1执行逻辑
console.log("f1");
setTimeout(function(){
jQuery.publish("done");
}, 1000);
}
f1();
jQuery.unsubscribe("done", f2); // 取消订阅
这种方法的性质与”事件监听”类似,但是明显优于后者。因为我们可以通过查看”消息中心”,了解存在多少信号、每个信号有多少订阅者,从而监控程序的运行。
function f1(){
var dfd = $.Deferred();
setTimeout(function () {
// f1的任务代码
console.log("f1");
dfd.resolve();
}, 500);
// 在原来的deferred对象上返回另一个deferred对象,后者只开放与改变执行状态无关的方法(比如done()方法和fail()方法),屏蔽与改变执行状态有关的方法(比如resolve()方法和reject()方法),从而使得执行状态不能被改变。
return dfd.promise();
}
f1().then(f2);
好处:如果一个任务已经完成,再添加回调函数,该回调函数会立即执行。所以,你不用担心是否错过了某个事件或信号。这种方法的缺点就是编写和理解,都相对比较难。
参考地址:http://www.ruanyifeng.com/blog/2012/12/asynchronous%EF%BC%BFjavascript.html