JavaScript异步操作进化史

JavaScript是一种“单线程”的语言,同一时刻,有且仅有一处代码正在执行。执行的时候要一个一个进行,如果遇见ajax请求网络阻塞则会影响下一个任务的继续,所以产生了异步操作的需求。

异步概念

JS为了防止在不同线程同时操作DOM产生冲突,没有多线程。在HTML5中引入的Web Worker允许JavaScript脚本创建多个线程,但是子线程完全受主线程控制,且不得操作DOM。所以,这个新标准并没有改变JavaScript单线程的本质。

同步和异步与以前的认知不太相符。在主线程上排队执行的任务通过同步进行,不在主线程的任务保存在任务队列中,等待主线程“召唤”才会进入主线程并被执行。

同步:只有前一个任务执行完毕,才能执行后一个任务。

异步:不会立即执行,在未来被“召唤”才会被执行。

简单介绍下进程和线程:

进程(process)是指在系统中正在运行的一个应用程序,是系统资源分配的基本单位,在内存中有其完备的数据空间和代码空间,拥有完整的虚拟空间地址。一个进程所拥有的数据和变量只属于它自己。

线程(thread)是进程内相对独立的可执行单元,所以也被称为轻量进程(lightweight processes);是操作系统进行任务调度的基本单元。它与父进程的其它线程共享该进程所拥有的全部代码空间和全局变量,但拥有独立的堆栈(即局部变量对于线程来说是私有的)。

进程和线程都具有就绪、阻塞和运行三种基本状态。

回调函数:每个任务只能指定一个回调函数。

function f1(f2) {
// f1 的代码
// f1 执行完成后,调用回调函数
f2();
}

事件监听:任务的执行不取决于代码的顺序,而取决于某个事件是否发生。

var eventOne = function(){
alert("第一个监听事件");
}
function eventTwo(){
alert("第二个监听事件");
}
window.onload = function(){
var btn = document.getElementById("test");
btn.addEventListener("click",eventOne);
btn.addEventListener("click",eventTwo);
btn.removeEventListener("click",eventOne); //移除事件一,最后只会输出事件二
}

封装函数写法:

//事件监听
function addEventHandler(target,type,func){
if(target.addEventListener){
//监听IE9,谷歌和火狐
target.addEventListener(type, func, false);
}else if(target.attachEvent){
target.attachEvent("on" + type, func);
}else{
target["on" + type] = func;
}
}
//移除监听
function removeEventHandler(target, type, func) {
if (target.removeEventListener){
//监听IE9,谷歌和火狐
target.removeEventListener(type, func, false);
} else if (target.detachEvent){
target.detachEvent("on" + type, func);
}else {
delete target["on" + type];
}
}

jQuery写法:

function f1(){
// f1的任务代码
f1.trigger('done');//执行完成后,立即触发done事件
}
//绑定事件,当f1发生done事件,就执行f2
f1.on('done', f2);

观察者模式(发布/订阅):

将“事件”理解成”信号”,如果存在一个”信号中心”,某个任务执行完成,就向信号中心”发布”(publish)一个信号,其他任务可以向信号中心”订阅”(subscribe)这个信号,从而知道什么时候自己可以开始执行。

使用场景:当一个对象的改变需要同时改变其它对象,并且它不知道具体有多少对象需要改变的时候,就应该考虑使用观察者模式。

//伪代码实现获取ajax数据并渲染页面
//请求
function getData () {
var xhr = new XMLHttpRequest ()
xhr.open('get',url)
xhr.onreadystatechange = function () {
if(this.readyState !== 4) return
if(this.status === 200) {
this.emit('渲染')//emit是nodejs的函数
// 发布
}
}
xhr.responseType = 'json'
xhr.send(null)
}
//渲染
function view () {}
xhr.on('渲染',view)
//如果多个渲染函数情况:
function view1 () {}
function view2 () {}
function view3 () {}
function view4 () {}
if(我要渲染view1) {
xhr.on('渲染',view1) //订阅
xhr.on('渲染',view2)
}else{
xhr.on('渲染',view3)
xhr.on('渲染',view4)
}

接下来是Promise和async/await,下文再说。

参考:http://javascript.ruanyifeng.com/advanced/promise.html