ES6知識點整理之----async----異步遍歷器

asyncIterator

ES2018 引入了」異步遍歷器「(Async Iterator),爲異步操做提供原生的遍歷器接口,即valuedone這兩個屬性都是異步產生。javascript

異步遍歷器的最大的語法特色,就是調用遍歷器的next方法,返回的是一個 Promise 對象。java

asyncIterator
.next() .then( ({ value, done })
=> /* ... */ );

對象的異步遍歷器接口,部署在Symbol.asyncIterator屬性上面。無論是什麼樣的對象,只要它的Symbol.asyncIterator屬性有值,就表示應該對它進行異步遍歷。git

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 }
});

異步遍歷器與同步遍歷器最終行爲是一致的,只是會先返回 Promise 對象,做爲中介。github

因爲異步遍歷器的next方法,返回的是一個 Promise 對象。所以,能夠把它放在await命令後面。數據結構

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

異步遍歷器的next方法是能夠連續調用的,沒必要等到上一步產生的 Promise 對象resolve之後再調用。這種狀況下,next方法會累積起來,自動按照每一步的順序運行下去。下面是一個例子,把全部的next方法放在Promise.all方法裏面。異步

const asyncIterable = createAsyncIterable(['a', 'b']);
const asyncIterator = asyncIterable[Symbol.asyncIterator]();
const [{value: v1}, {value: v2}] = await Promise.all([
  asyncIterator.next(), asyncIterator.next()
]);

console.log(v1, v2); // a b

另外一種用法是一次性調用全部的next方法,而後await最後一步操做。async

async function runner() {
  const writer = openFile('someFile.txt');
  writer.next('hello');
  writer.next('world');
  await writer.return();
}

runner();

for await...of

用於遍歷異步的 Iterator 接口。函數

async function f() {
  for await (const x of createAsyncIterable(['a', 'b'])) {
    console.log(x);
  }
}
// a
// b

for await...of循環的一個用途,是部署了 asyncIterable 操做的異步接口,能夠直接放入這個循環。spa

若是next方法返回的 Promise 對象被rejectfor await...of就會報錯,要用try...catch捕捉。設計

注意,for await...of循環也能夠用於同步遍歷器。

異步 Generator 函數

返回一個異步遍歷器對象。

在語法上,異步 Generator 函數就是async函數與 Generator 函數的結合。

async function* gen() {
  yield 'hello';
}
const genObj = gen();
genObj.next().then(x => console.log(x));
// { value: 'hello', done: false }

異步遍歷器的設計目的之一,就是 Generator 函數處理同步操做和異步操做時,可以使用同一套接口。

異步 Generator 函數能夠與for await...of循環結合起來使用。

async function* prefixLines(asyncIterable) {
  for await (const line of asyncIterable) {
    yield '> ' + line;
  }
}

注意,普通的 async 函數返回的是一個 Promise 對象,而異步 Generator 函數返回的是一個異步 Iterator 對象。

javascript如今一共有4種函數形式:

  • 普通函數
  • async 函數
  • Generator 函數
  • 異步 Generator 函數

若是是一系列按照順序執行的異步操做(好比讀取文件,而後寫入新內容,再存入硬盤),可使用 async 函數;

若是是一系列產生相同數據結構的異步操做(好比一行一行讀取文件),可使用異步 Generator 函數。

同步的數據結構,也可使用異步 Generator 函數。

yield* 語句

yield*語句也能夠跟一個異步遍歷器。

async function* gen1() {
  yield 'a';
  yield 'b';
  return 2;
}

async function* gen2() {
  // result 最終會等於 2
  const result = yield* gen1();
}

與同步 Generator 函數同樣,for await...of循環會展開yield*

(async function () {
  for await (const x of gen2()) {
    console.log(x);
  }
})();
// a
// b
相關文章
相關標籤/搜索