Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

前端异步发展 #1

Open
SunShinewyf opened this issue May 5, 2017 · 0 comments
Open

前端异步发展 #1

SunShinewyf opened this issue May 5, 2017 · 0 comments

Comments

@SunShinewyf
Copy link
Owner

SunShinewyf commented May 5, 2017

异步在前端中的发展历史不是很长,但是发展的速度还是很快的

什么是异步

所谓异步,简单点说就是在做一件事情的过程中中断去做另外一件事情。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 扩展性更好,generatorco结合时候,要求在yield语句后面是一个thunk函数或者promise,而await后面则可以是任何数据类型,比如StringNumber
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant