ES6中引入的一种新的函数类型,叫做Generator生成器函数,它的特点是可以暂停执行和恢复执行。通过yield表达式能够中断函数的执行,通过next()方法可以恢复执行。
在普通的函数通过return指定返回值,如果函数被调用,会一直不间断的执行到return终止,如果没有显示return语句,会默认添加到函数的末尾。
Generator函数
生成器函数如何定义
使用function*作为声明标识符,表示这是一个生成器函数
function* f() {}
普通函数和生成器函数的区别:
- 普通函数和生成器函数的构造函数分别是Function和GeneratorFunction,
- 调用普通函数执行函数体返回返回值,调用生成器函数时,不会执行函数体,而是返回一个迭代器对象。
function f1() {console.log('执行了f1')}
function* f2() {console.log('执行了f2')}
console.dir(f1);
console.dir(f2);
console.dir(f1());
console.dir(f2());
如何调用生成器函数
上文说了,调用生成器函数时,不会执行函数体,而是返回一个迭代器对象
。
迭代器对象有一个next方法,该方法返回一个对象,称之为迭代结果对象
,该对象包含以下两个属性:
- value:本次迭代的结果
- done: 布尔值,如果为true,表示无法再继续迭代,如果为false,表示可以继续迭代。
调用next函数,将会让生成器函数真正的执行,一直执行到遇见yield,并返回迭代结果对象;
构造函数内部,yield用来在生成器函数中定义暂停位置和进行数值的返回。
生成器函数中可以使用return,但是return之后将不可再迭代
function* gen(){
yield 1;
return 2;
yield 3;
}
let iterator = gen();
console.log(iterator.next()); //{value: 1, done: false}
console.log(iterator.next()); //{value: 2, done: true}
console.log(iterator.next()); //{value: undefined, done: true}
async 函数
和生成器函数类似,在ES2017(ES8)标准中引入的 async 函数,使异步操作更加方便。async 函数是建立在 Promise 和 Generator的基础之上,它是 Generator函数的语法糖。
async函数返回一个 Promise 实例对象
- return语句返回的值,会成为then方法回调函数的参数;
- 函数内部抛出错误,会导致返回的 Promise对象变成reject状态,错误会被catch方法回调函数接收到
- 只有async函数内部的异步操作执行完,才会执行 then方法指定的回调函数
async function foo () {
return 'ok'
}
console.log(foo())
foo().then(res => {
console.log(res)
})
async function foo () {
return new Error('error')
}
foo().then(res => {
console.log(res)
}).catch(err => {
console.log(err)
})
await命令
await 命令只能在一个 async函数内部使用,用于等待一个 Promise对象的处理結果。
- 如果 await 命令后的表达式的值不是一个 Promise,则返回该值本身。
- await命令会暂停当前 async函数的执行,等待 Promise处理完成。
① Promise正常处理,其回调的 resolve函数的参数会作为 await表达式的返回值,继续执行 async函数;
② Promise处理异常,await表达式会把 Promise的异常原因抛出,任何一个 await语句后面的 Promise对象变为 reject状态,那么整个 async函数都会中断执行。如果希望当前面的异步操作失败时,不要中断后面的异步操作,可以把前面的 await放在try…catch结构里面。
function first () {
console.log('first')
return '1'
}
function second () {
return new Promise((resolve,reject) => {
console.log('second')
setTimeout(reject(new Error('second出错啦......')), 1000)
})
}
async function foo () {
console.log('start')
console.log(await first ())
try {
await second()
} catch (err) {
console.log(err)
}
let result = await new Promise(resolve => {
console.log('third')
setTimeout(resolve(3), 2000)
})
console.log('end')
return result
}
foo().then((res) => {
console.log(res)
}).catch(err => {
console.log(err)
})
本例中如果不适用try…catch语句, async函数执行到second()将会终止