异步:
异步指的是一个任务分成两部分,先执行第一部分,然后再执行其他的任务,等第一部分执行完毕,再回来执行第二段
相应的,连续的执行就叫做同步,由于是连续执行,不能插入其他任务,所以执行时只能等前面的任务完成之后才能执行后面的的任务。
js中对异步编程的实现就是通过回调函数。回调函数就是把第二段单独写在一个函数里面,等到重新执行这个任务的时候,就直接调用这个函数
如果要依次调用多个函数,就会出现多重嵌套。为了解决这种回调地狱的问题,可以使用Promise方法
Promise提供then方法加载回调函数,catch方法捕捉执行过程中抛出的错误。
Promise最大的问题是代码冗余,原来的任务被Promise包装之后,不管什么操作,看起来就是一堆的then,语句不够清晰。
因此又出现了Generator函数
执行Generator函数会返回一个遍历器对象,也就是说,Generator函数除了状态机,还是一个遍历器对象生成函数。返回的遍历器对象,
可以依次遍历Generator函数内部的每一个状态
形式上,Generator函数是一个普通函数,但是有两个特征:
1.function关键字与函数名之间有一个星号*
2.函数体内部使用yield语句,定义不同的状态
function* helloWorldGenerator() { yield 'hello'; yield 'world'; return 'ending'; } var hw = helloWorldGenerator();
上述代码定义了一个Generator函数helloWorldGenerator,内部有两个yield语句“hello”和“world”,即该函数有三个状态 分别是 :hello,world和return语句(结束执行)
Generator函数的调用方法与普通函数一样,也是在函数名后面加上一对圆括号。不同的是,调用Generator函数后,该函数并不执行,返回的也不是函数运行结果,而是一个指向内部状态的指针对象,也就是遍历器对象(Iterator Object)。
所以必须调用遍历器对象的next方法,使得指针移向下一个状态。也就是说每次调用next方法,内部指针就从函数头部或上一次停下来的地方开始执行,直到遇到下一个yield语句或return语句为止。
Generator函数是分段执行的,yield语句是暂时执行的标记,而next方法可以恢复执行
hw.next() // { value: 'hello', done: false } hw.next() // { value: 'world', done: false } hw.next() // { value: 'ending', done: true } hw.next() // { value: undefined, done: true }
上面代码一共调用了四次next
方法。
第一次调用,Generator函数开始执行,直到遇到第一个yield
语句为止。next
方法返回一个对象,它的value
属性就是当前yield
语句的值hello,done
属性的值false,表示遍历还没有结束。
第二次调用,Generator函数从上次yield
语句停下的地方,一直执行到下一个yield
语句。next
方法返回的对象的value
属性就是当前yield
语句的值world,done
属性的值false,表示遍历还没有结束。
第三次调用,Generator函数从上次yield
语句停下的地方,一直执行到return
语句(如果没有return语句,就执行到函数结束)。next
方法返回的对象的value
属性,就是紧跟在return
语句后面的表达式的值(如果没有return
语句,则value
属性的值为undefined),done
属性的值true,表示遍历已经结束。
第四次调用,此时Generator函数已经运行完毕,next
方法返回对象的value
属性为undefined,done
属性为true。以后再调用next
方法,返回的都是这个值。
总结一下,调用Generator函数,返回一个遍历器对象,代表Generator函数的内部指针。以后,每次调用遍历器对象的next
方法,就会返回一个有着value
和done
两个属性的对象。value
属性表示当前的内部状态的值,是yield
语句后面那个表达式的值;done
属性是一个布尔值,表示是否遍历结束。
ES6没有规定,function
关键字与函数名之间的星号,写在哪个位置。这导致下面的写法都能通过。但是一般使用第三种,星号紧跟在function关键字后面。
function * foo(x, y) { ··· } function *foo(x, y) { ··· } function* foo(x, y) { ··· } function*foo(x, y) { ··· }