Node.js中的 "for await ...of "語句的簡單解釋。

嘿,大家好!javascript

幾個月前,Deno--一種Node.js的後繼者--發佈了,在主頁上有一個如何使用它的小演示。java

import { serve } from "https://deno.land/std@0.69.0/http/server.ts";
const s = serve({ port: 8000 });
console.log("http://localhost:8000/");
for await (const req of s) {
  req.respond({ body: "Hello Worldn" });
}

忽然,當看到第4行的await調用在for以後,但在(const req of s)以前時,個人眼睛就 "那是什麼?"?node

我歷來沒有見過這樣的東西,個人第一個想法是 "這是一個很是酷和奇怪的事情,deno作"....。python

想象一下個人驚訝,當我閱讀了更多關於deno的資料後,我發現那一小段代碼實際上是有效的javascript,並且_它在Node.js中也是有效的,而我對它一無所知_。設計模式

那麼,這是什麼呢,爲何我歷來沒有見過,我應該用在哪裏呢,我是否是已經錯過了?數組

若是你也有一樣的疑問,那麼好!dom

這篇文章將嘗試回答這些問題!異步

首先,先說一下。async

迭代器

你見過這樣的東西嗎?函數

class RandomNumberGenerator {
  [Symbol.iterator]() {
    return {
      next: () => {
        return { value: Math.random() };
      },
    };
  }
}

若是你作了,那麼對你來講很好,你能夠跳到下一節!

若是你尚未,那麼讓咱們深刻了解一下這個類的做用。

這個類RandomNumberGenerator實現了[Symbol.iterator]@@iterator方法(當該方法經過Symbol屬性定義時,咱們用雙@@來表示該方法)。

[Symbol.iterator]@@iterator方法定義在一個對象上時,容許對象進行迭代!

因爲如今咱們將@@iterator方法定義爲RandomNumberGenerator類的一個實例方法,因此這個類的全部實例如今都是可迭代的。如今你能夠經過運行下面的代碼來測試它。

class RandomNumberGenerator {
  [Symbol.iterator]() {
    return {
      next: () => {
        return { value: Math.random() };
      },
    };
  }
}

const rand = new RandomNumberGenerator();

for (const random of rand) {
  console.log(random);
  if (random < 0.1) break;
}

爲了讓一切都能正常工做,"@@iterator "方法必須返回一個包含 "next "方法的對象,而且 "next "方法須要返回另外一個具備 "value "和 "done "屬性的對象。

value將包含返回的值,而done將是一個布爾值,若是它被設置爲true將結束迭代。

雖然 "value "是必須的,但 "done "能夠省略,就像上面的例子同樣(這容許咱們定義_無限的迭代)。

好吧,酷!咱們如今可讓事情變得可迭代了。

咱們如今可讓事情變得可迭代了!

這在何時纔有用呢?

我相信這高度依賴於你正在建立的業務邏輯的類型。

例如Node.js設計模式這本書--我強烈推薦--給出了一個迭代矩陣元素的例子(你可能已經把它定義爲一個數組)。

另外我相信這篇文章強調了一些很酷的用法。它定義了一些很是酷的方法,看起來頗有python風格。

然而,若是你想知道個人誠實和我的意見,我尚未遇到過 "這是迭代器的一個偉大的用例 "的狀況。

不管如何,讓咱們回到咱們文章的主題:咱們還須要在for循環中添加 await什麼?

異步迭代器

顧名思義,異步迭代器是咱們在上面的例子中所作的異步版本。

想象一下,咱們不是返回一個隨機數,而是返回承諾。那會是怎樣的呢?

若是咱們把上面的例子改爲這樣,它就會是這樣的。

const simulateDelay = (val, delay) =>
  new Promise((resolve) => setTimeout(() => resolve(val), delay));

class RandomNumberGenerator {
  [Symbol.asyncIterator]() {
    return {
      next: async () => {
        return simulateDelay({ value: Math.random() }, 200); //return the value after 200ms of delay
      },
    };
  }
}

const rand = new RandomNumberGenerator();

(async () => {
  for await (const random of rand) {
    console.log(random);
    if (random < 0.1) break;
  }
})();

變化有哪些?

  1. 咱們首先將Symbol屬性改成 "asyncIterator",而不只僅是 "iterator"。
  2. 咱們把 "next "方法作成了一個異步函數。
  3. 我建立了simulateDelay函數,該函數返回一個承諾,在給定時間後解析給定值。
  4. 咱們在for循環中加入了await
  5. 咱們把循環放在Inmediately調用的函數表達式裏面,是爲了避免出現頂層 await調用的問題。(注意:在Node.js 14+版本中再也不須要這個功能)

因而咱們作了一個簡單的程序,可以對一個對象進行迭代,以異步的方式獲取其元素。

若是你知道除了主頁上的小deno例子以外,還有其餘的異步迭代器的實現,請發郵件給我,或者在下面留言

相關文章
相關標籤/搜索