前端异步发展
SunShinewyf opened this issue · 0 comments
异步在前端中的发展历史不是很长,但是发展的速度还是很快的
什么是异步
所谓异步,简单点说就是在做一件事情的过程中中断去做另外一件事情。js是单线程的,当然也有异步的概念。异步和同步的区别用图示表示如下:
由图示可以得出,同步过程时:业务二必须等待业务一的请求结果返回之后才可以开始,而异步过程中,在业务一的请求过程中,当前线程可以先去处理业务二,免去了等待过程中的时间浪费。
为什么要异步
为什么要引入异步的,异步有下面几点优点:
- cpu利用率高
- 用户体验更好
- 性能更高
从上面图示可以看出,在异步过程中,没有等待数据返回的过程,在请求数据的时候,当前线程又去处理其他业务了,这样就提高了cpu的利用率,cpu的性能必定也会提升。其次,在之前的网站中,我们时常要处理ajax请求,一旦采用同步思路,那么在请求数据返回之前,网页都是一片空白而得不到相应,那样会给用户一种相应很慢的感觉,导致用户体验很差。而异步就使得页面在请求数据的空隙也可以渲染页面,大大提升了用户体验。
异步的发展历程
####callback
时代
回调函数是异步发展的起源,最初源自ajax
,对于下面的代码,相信每一个FEer都不会感到陌生:
$.ajax('url',function () {
//do something
})
但是这样的请求一旦嵌套过多,就会出现下面的callbacks hell
asyncOperation1(data1,function (result1) {
asyncOperation2(data2,function(result2){
asyncOperation3(data3,function (result3) {
asyncOperation4(data4,function (result4) {
//do something
})
})
})
})
这种代码不仅可读性很差,而且在团队中很不好维护。
之后还衍生中一种事件监听事件,比如:
element.addEventListener('click',function(){
//response to user click
});
也就是click事情的回调函数只在触发了click事件之后才执行,当然了,这也是回调函数的一种变种。
Promise
时代
promise,顾名思义,就是承诺,这个承诺有成功初始(pending
)(fulfilled
)和失败(rejected
)三种状态。当由pending
->fulfilled
状态时,会触发resolved
,当由pending
->rejected
状态时,会触发rejected
.具体规范可以参见promise/A+
规范。
promise有一个then
函数,它返回一个promise
对象,就是因为这样,promise
才可以实现链式调用。promise
的链式调用可以用如下图示表示:
根据promise
的概念,上面的回调函数嵌套过深的问题可以写成如下:
asyncOperation1(data)
.then(function (data1) {
return asyncOperation2(data1)
}).then(function(data2){
return asyncOperation3(data2)
}).then(function(data3){
return asyncOperation(data3)
})
generator/yield
时代
ES6语法中引入了generator
,一个普通的generator
函数表示如下:
function* gen(){
yield 1;
yield 2;
return 'ending';
}
var g = gen();
g.next(); //{value:1,done:false}
g.next(); //{value:2,done:false}
g.next(); //{value:ending,done:true}
调用 Generator
函数,会返回一个内部指针 。即执行它不会返回结果,返回的是指针对象。调用指针 gnext
方法,将会指向第一个遇到的 yield
语句,yield
的作用是暂停此处,只有调用next
函数才会执行下一个yield
。每次调用 next
方法,会返回一个对象,表示当前阶段的信息( value
属性和 done
属性)。value
属性是yield
语句后面表达式的值,表示当前阶段的值;done
属性是一个布尔值,表示 Generator
函数是否执行完毕,即是否还有下一个阶段。上面的深度嵌套的例子改写为generator
如下:
function* generateOperation(data1) {
var result1 = yield asyncOperation1(data1);
var result2 = yield asyncOperation2(result1);
var result3 = yield asyncOperation3(result2);
var result4 = yield asyncOperation4(result3);
//more
}
async/await
ES7出现了async/await
,从字面意思就可以看出来代码在执行过程中等待,上面的代码变成async./await
形式如下:
async generateOperation(data1) {
var result1 = await asyncOperation1(data1);
var result2 = await asyncOperation2(result1);
var result3 = await asyncOperation3(result2);
var result4 = await asyncOperation4(result3);
//more
}
generator和async虽然在形式和代码结构上很相似,但是两者还是有区别的:
async
的语义化更好async
内置了自动执行器,之前我们说过generator
需要手动调用next()
方法来执行下一个yield
语句,但是async
会自动执行内部的异步函数,而generator
需要结合co
来实现自动执行所有的异步函数
-async
扩展性更好,generator
和co
结合时候,要求在yield语句后面是一个thunk
函数或者promise
,而await
后面则可以是任何数据类型,比如String
,Number
等