Generator(状态机
,封装了多个内部状态.通过next方法获取)
- 也是es6提供的一种异步编程解决方案.内部因为yield的存在 , 所以可以
封装多个内部的状态
. - 其具有
惰性求值
的特点. 函数调用时并不会执行. 而是调用next方法去执行内部的状态
. - 相似于return , 但又不同于return语句:
- 都返回紧跟在语句后的表达式的值.
- return只能执行一次. 且不具备记忆的功能.而yield可以执行多次,每次next方法,都是
从上次yield的位置执行
.
- yield语句
只能用在 Generator函数中
. 而Generator函数中可以没有yield语句 . 没有该语句, 就是个暂缓执行的函数 . 通过next方法执行. 返回的是一个遍历器对象
. 因此可以赋值给对象的[Symbol.iterator]属性.
function* f() {
yield 1
yield 2
return 3
}
let exec = f()
for (let value of exec) {
console.log(value)
}
console.log(exec.next())
/*
1
2
{value:undefined,done:true}
用for...of遍历,{value:3,done:true}该状态已经遍历到了,但是输出的是done:false的值.
*/
function* f() {
console.log('暂缓')
}
const exec = f();
console.log(exec)
exec.next()
/*
一个含GeneratorState: closed的对象.
暂缓
*/
function* gen(){
// some code
}
var g = gen();
g[Symbol.iterator]() === g
// true . 这个有意思 .
- next方法的参数
- yield 表达式本身没有返回值 . 返回值总是undefined .
- next()方法可以带一个参数. 该参数就是上一个yield表达式的返回值
- 并且当yield前还有表达式 . yield 语句必须用括号括起来.
function* f() {
let x = 2 + (yield 2)
return x
}
let exec = f()
console.log(exec.next())
console.log(exec.next(4))
/*
{value:2,done:false}
{value:6,done:true}
*/
- next() . throw() . return()
- 本质上是同一件事,可以放在一起理解。它们的作用
都是让 Generator 函数恢复执行,并且使用不同的语句替换yield表达式
。 - next()是将yield表达式替换成一个值
- throw()是将yield表达式替换成一个throw语句.
- return()是将yield表达式替换成一个return语句
- 本质上是同一件事,可以放在一起理解。它们的作用
const g = function* (x, y) {
let result = yield x + y;
return result;
};
const gen = g(1, 2);
gen.next(); // Object {value: 3, done: false}
gen.next(1); // Object {value: 1, done: true}
// 相当于将 let result = yield x + y
// 替换成 let result = 1;
gen.throw(new Error('出错了')); // Uncaught Error: 出错了
// 相当于将 let result = yield x + y
// 替换成 let result = throw(new Error('出错了'));
gen.return(2); // Object {value: 2, done: true}
// 相当于将 let result = yield x + y
// 替换成 let result = return 2;
- yield* 表达式 . 用来在一个 Generator 函数里面执行另一个 Generator 函数.
var arr = [1, [[2, 3], 4], [5, 6]];
var flat = function* (a) {
var length = a.length;
for (var i = 0; i < length; i++) {
var item = a[i];
if (typeof item !== 'number') {
yield* flat(item);
} else {
yield item;
}
}
};
for (var f of flat(arr)) {
console.log(f);
}
/* 1, 2, 3, 4, 5, 6
又多了一种扁平化的方法. 真神奇了...
*/
async
- 是Generator 函数的语法糖. 而Generator 函数有一个很有意思的概念:
将函数的执行权交出去.再次执行时, 从暂停处开始.
- async函数就是将 Generator 函数的星号(*)替换成async,将yield替换成await,仅此而已.
- 不同:
- async函数
自带执行器
. 不用通过next方法去调用执行. - 更好的语义. async是异步的意思. await是需要等待的意思.
- yield后只能是Thunk函数 (这个还是第一次见)或 Promise对象 . await 后可以是 Promise 对象和原始类型的值(数值、字符串和布尔值,
但这时会自动转成立即 resolved 的 Promise 对象
) - 其返回值是Promise对象. 可以调用then方法处理.而Generator函数返回值是个iterator对象.
- async函数
function* f() {
yield Promise.resolve('成功了')
}
const exec = f();
console.log(exec.next())
async function f1() {
let p = await Promise.resolve('成功了')
console.log(p)
}
const p = f1()
console.log(p)
- 这里比较关注的是f1函数中的p 与 f1函数外的p的输出顺序 (因为涉及到了
事件循环机制
). 是函数外的p先输出 .
- async函数返回一个promise对象. 且如果内部不抛出错误的情况下 , 其
状态为成功
. - 函数内部的
return值
, 会成为then方法回调时候的参数. - 该函数返回的Promise对象.
必须等到await命令后的异步操作完成后 , 才会确定状态
, 然后执行then方法指定的回调函数. - 若遇到return语句. 则会提前结束函数.
状态为成功
; 而抛出错误 ,状态为失败
. - 对于抛出错误的情况. 若想继续执行, 则要把该命令放在
try...catch...
中
async function f() {
let data = await 1
console.log(data)
return 'then的参数'
}
let p = f()
p.then(res => console.log(res))
/*
1
then的参数
*/
async function f() {
throw new Error('出错了');
}
f().then(
value => console.log('resolve', value),
err => console.log('reject', err)
)
//reject Error: 出错了
自带执行器
. 所以比较好奇的是它是通过什么去判断暂停或继续执行
.- 因为上述说await是替代了yield . 而yield通过next方法去暂停处继续执行.
- 因此这里分await后是promise对象 . 不是promise对象 .
- 不是promise对象的话 . 直接返回语句后的结果
- 是promise对象的话 . 则放回该对象的结果 . 也就是then 方法所需要的参数值
- 最后一个例子. 输出p的语句 , return语句 , 函数外的then方法都没有结果的输出.
因为await会等其后的异步操作有结果后 , 再进行
. 但例子中并没有确定promise对象的状态. 所以其后的代码, 包括then方法都没有执行 .
async function f() {
console.log('async start')
let p = await '111'
console.log('p的值: ', p)
return 'async end'
}
f().then(res => console.log(res))
/*
async start
p的值: 111
async end
*/
async function f() {
console.log('async start')
try {
let p = await Promise.reject('111')
console.log('p的值: ', p)
} catch (err) {
console.log('捕获: ', err)
}
return 'async end'
}
f().then(res => console.log(res))
/*
async start
捕获: 111
async end
*/
async function f() {
console.log('async start')
let p = await new Promise((resolve) => {
console.log('111')
})
console.log('p的值:', p)
return 'async end'
}
f().then(res => console.log(res))
/*
async start
111
*/