Skip to content

Latest commit

 

History

History
140 lines (121 loc) · 4.1 KB

27异步遍历器.md

File metadata and controls

140 lines (121 loc) · 4.1 KB

异步遍历器

1.同步遍历器的问题

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这两个属性都是异步产生。

2.异步遍历的接口

异步遍历器的最大的语法特点,就是调用遍历器的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 }
}

3.for await...of

  • 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的循环体

4.异步 Generator 函数

异步 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 }

5.yield* 语句

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