Iterator 接口是一种数据遍历的协议,只要调用遍历器对象的next方法,就会得到一个对象,表示当前遍历指针所在的那个位置的信息 目前的解决方法是,将异步操作包装成 Thunk 函数或者 Promise 对象 即next()方法返回值的value属性是一个 Thunk 函数或者 Promise 对象,等待以后返回真正的值,而done属性则还是同步产生的。
function idMaker() {
let index = 0;
return {
next: function() {
return {
value: new Promise(resolve => setTimeout(() => resolve(index++), 1000)),
done: false
};
}
};
}
const it = idMaker();
it.next().value.then(o => console.log(o)) // 1
it.next().value.then(o => console.log(o)) // 2
it.next().value.then(o => console.log(o)) // 3
ES2018 引入了“异步遍历器”(Async Iterator),为异步操作提供原生的遍历器接口,即value和done这两个属性都是异步产生。
异步遍历器的最大的语法特点,就是调用遍历器的next方法,返回的是一个 Promise 对象。可以用await或者then
const asyncIterable = createAsyncIterable(['a', 'b']);
const asyncIterator = asyncIterable[Symbol.asyncIterator]();
asyncIterator
.next()
.then(iterResult1 => {
console.log(iterResult1); // { value: 'a', done: false }
return asyncIterator.next();
})
.then(iterResult2 => {
console.log(iterResult2); // { value: 'b', done: false }
return asyncIterator.next();
})
.then(iterResult3 => {
console.log(iterResult3); // { value: undefined, done: true }
});
async function f() {
const asyncIterable = createAsyncIterable(['a', 'b']);
const asyncIterator = asyncIterable[Symbol.asyncIterator]();
console.log(await asyncIterator.next());
// { value: 'a', done: false }
console.log(await asyncIterator.next());
// { value: 'b', done: false }
console.log(await asyncIterator.next());
// { value: undefined, done: true }
}
- for...of循环用于遍历同步的 Iterator 接口
- for await...of循环用于遍历异步的 Iterator 接口。
async function f() {
for await (const x of createAsyncIterable(['a', 'b'])) {
console.log(x);
}
}
// a
// b
for...of循环自动调用这个对象的异步遍历器的next方法,会得到一个 Promise 对象。await用来处理这个 Promise 对象,一旦resolve,就把得到的值(x)传入for...of的循环体
异步 Generator 函数的作用,是返回一个异步遍历器对象。
异步 Generator 函数内部,能够同时使用await和yield命令
- await命令用于将外部操作产生的值输入函数内部(处理promise)
- yield命令用于将函数内部的值输出(等待输出)
异步 Generator 函数和await函数区别
- await函数
- 返回:Promise
- 自带执行器
- 异步 Generator 函数
- 返回:异步 Iterator 对象
- 通过for await...of执行,或者自己编写执行器
异步 Generator 函数和await函数使用场景:
- 如果是一系列按照顺序执行的异步操作(比如读取文件,然后写入新内容,再存入硬盘),可以使用 async 函数;
- 如果是一系列产生相同数据结构的异步操作(比如一行一行读取文件),可以使用异步 Generator 函数。
var fetch = function(){
return new Promise((resolve, reject) => {
setTimeout(() => resolve('hello'), 1000)
})
}
async function* gen() {
yield await fetch();
}
// 手动执行
var genObj = gen();
genObj.next().then(x => console.log(x));
// { value: 'hello', done: false }
// for await...of执行
(async () => {
for await (const x of gen()) {
console.log(x);
}
})()
// { value: 'hello', done: false }
yield* 语句也可以跟一个异步遍历器。
async function* gen1() {
yield 'a';
yield 'b';
return 2;
}
async function* gen2() {
// result 最终会等于 2
const result = yield* gen1();
}
(async function () {
for await (const x of gen2()) {
console.log(x);
}
})();
// a
// b