>  기사  >  웹 프론트엔드  >  Node.js 비동기 반복자 및 사용 방법에 대한 자세한 설명

Node.js 비동기 반복자 및 사용 방법에 대한 자세한 설명

青灯夜游
青灯夜游앞으로
2021-03-23 10:09:171818검색

이 글에서는 Node.js의 비동기 반복자를 소개합니다. 도움이 필요한 친구들이 모두 참고할 수 있기를 바랍니다.

Node.js 비동기 반복자 및 사용 방법에 대한 자세한 설명

비동기 반복자는 버전 10.0.0부터 Node에서 사용할 수 있습니다. 이 기사에서는 비동기 반복자의 역할과 사용할 수 있는 위치에 대해 설명합니다.

비동기 반복기란 무엇인가요?

비동기 반복기는 실제로 이전 반복기의 비동기 버전입니다. 비동기 반복자는 반복의 값과 최종 상태를 알 수 없을 때 사용할 수 있습니다. 둘 사이의 차이점은 우리가 얻는 promise가 결국 일반 { value: any, done: boolean } 객체로 분해된다는 것입니다. 또한 for-await-로 전달할 수도 있습니다. of 비동기 반복자를 처리하는 루프입니다. for-of 루프가 반복자를 동기화하는 데 사용되는 것과 같습니다. [관련 권장사항: "nodejs tutorial{ value: any, done: boolean } 对象,另外可以通过  for-await-of 循环来处理异步迭代器。就像 for-of 循环用于同步迭代器一样。【相关推荐:《nodejs 教程》】

const asyncIterable = [1, 2, 3];
asyncIterable[Symbol.asyncIterator] = async function*() {
  for (let i = 0; i < asyncIterable.length; i++) {
    yield { value: asyncIterable[i], done: false }
  }
  yield { done: true };
};

(async function() {
  for await (const part of asyncIterable) {
    console.log(part);
  }
})();

与通常的 for-of 循环相反,`for-await-of 循环将会等待它收到的每个 promise 解析之后再继续执行下一个。

除了流之外,还在还没有什么能够支持异步迭代的结构,但是可以将 asyncIterator 符号手动添加到任何一种可迭代的结构中。

在流上使用异步迭代器

异步迭代器在处理流时非常有用。可读流、可写流、双工流和转换流上都带有 asyncIterator 符号。

async function printFileToConsole(path) {
  try {
    const readStream = fs.createReadStream(path, { encoding: &#39;utf-8&#39; });

    for await (const chunk of readStream) {
      console.log(chunk);
    }

    console.log(&#39;EOF&#39;);
  } catch(error) {
    console.log(error);
  }
}

如果以这种方式写代码,就不需要在通过迭代获取每个数据块时监听 enddata 事件了,并且 for-await-of 循环会随着流的结束而结束。

用于有分页功能的 API

你还可以通过异步迭代从使用分页的源中轻松获取数据。为了实现这个功能,还需要一种从Node https 请求方法提供给的流中重构响应主体的方法。在这里也可以使用异步迭代器,因为 https 请求和响应在 Node 中都是流:

const https = require(&#39;https&#39;);

function homebrewFetch(url) {
  return new Promise(async (resolve, reject) => {
    const req = https.get(url, async function(res) {
      if (res.statusCode >= 400) {
        return reject(new Error(`HTTP Status: ${res.statusCode}`));
      }

      try {
        let body = '';

        /*
          代替 res.on 侦听流中的数据,
          可以使用 for-await-of,
          并把数据块附加到到响应体的剩余部分
        */
        for await (const chunk of res) {
          body += chunk;
        }
    
        // 处理响应没有响应体的情况
        if (!body) resolve({});
        // 需要解析正文来获取 json,因为它是一个字符串
        const result = JSON.parse(body);
        resolve(result);
      } catch(error) {
        reject(error)
      }
    });

    await req;
    req.end();
  });
}

代码通过向 Cat API(https://thecatapi.com/)发出请求,来获取一些猫的图片。另外还添加了 7 秒钟的延迟防止对 cat API 的访问过与频繁,因为那样是极其不道德的。

function fetchCatPics({ limit, page, done }) {
  return homebrewFetch(`https://api.thecatapi.com/v1/images/search?limit=${limit}&page=${page}&order=DESC`)
    .then(body => ({ value: body, done }));
}

function catPics({ limit }) {
  return {
    [Symbol.asyncIterator]: async function*() {
      let currentPage = 0;
      // 5 页后停止
      while(currentPage < 5) {
        try {
          const cats = await fetchCatPics({ currentPage, limit, done: false });
          console.log(`Fetched ${limit} cats`);
          yield cats;
          currentPage ++;
        } catch(error) {
          console.log(&#39;There has been an error fetching all the cats!&#39;);
          console.log(error);
        }
      }
    }
  };
}

(async function() {
  try {
    for await (let catPicPage of catPics({ limit: 10 })) {
      console.log(catPicPage);
      // 每次请求之间等待 7 秒
      await new Promise(resolve => setTimeout(resolve, 7000));
    }
  } catch(error) {
    console.log(error);
  }
})()

这样,我们就会每隔7秒钟自动取回一整页的喵星人图片。

一种更常见的页面间导航的方法可实现 nextprevious"]

function actualCatPics({ limit }) {
  return {
    [Symbol.asyncIterator]: () => {
      let page = 0;
      return {
        next: function() {
          page++;
          return fetchCatPics({ page, limit, done: false });
        },
        previous: function() {
          if (page > 0) {
            page--;
            return fetchCatPics({ page, limit, done: false });
          }
          return fetchCatPics({ page: 0, limit, done: true });
        }
      }
    }
  };
}

try {
    const someCatPics = actualCatPics({ limit: 5 });
    const { next, previous } = someCatPics[Symbol.asyncIterator]();
    next().then(console.log);
    next().then(console.log);
    previous().then(console.log);
} catch(error) {
  console.log(error);
}

그리고 일반적으로 for-of 루프와 달리 `for-await-of 루프는 다음 약속을 계속하기 전에 수신한 각 약속이 해결될 때까지 기다립니다.

스트림을 제외하고 비동기 반복을 지원하는 구조는 없지만 asyncIterator 기호는 반복 가능한 구조에 수동으로 추가할 수 있습니다.

스트림에서 비동기 반복자 사용

비동기 반복자는 스트림 작업 시 매우 유용합니다. 읽기 가능한 스트림, 쓰기 가능한 스트림, 이중 스트림 및 변환 스트림은 모두 asyncIterator 기호로 표시됩니다. rrreee 이런 식으로 코드를 작성하면 각 데이터 청크를 반복할 때 enddata 이벤트를 수신할 필요가 없으며 for- 스트림이 끝나면 대기 루프가 종료됩니다.

🎜페이지 매김이 있는 API의 경우🎜🎜비동기 반복을 통해 페이지 매김을 사용하여 소스에서 데이터를 쉽게 가져올 수도 있습니다. 이 기능을 달성하려면 노드 https 요청 메서드에서 제공하는 스트림에서 응답 본문을 재구성하는 방법도 필요합니다. https 요청과 응답은 모두 노드의 스트림이기 때문에 여기에서 비동기 반복자를 사용할 수도 있습니다. 🎜rrreee🎜 코드는 Cat API(https://thecatapi.com/)에 요청하여 고양이 사진을 가져옵니다. 매우 비윤리적인 cat API에 대한 과도하고 빈번한 액세스를 방지하기 위해 7초 지연도 추가되었습니다. 🎜rrreee🎜 이런 식으로 7초마다 고양이 사진 전체 페이지를 자동으로 검색합니다. 🎜🎜페이지 간을 탐색하는 더 일반적인 방법은 nextprevious 메서드를 구현하고 이를 컨트롤로 노출하는 것입니다. 🎜rrreee🎜보시다시피 원할 때 get 비동기 반복자는 데이터 페이지나 프로그램 UI에서 무한 스크롤과 같은 작업을 수행할 때 매우 유용할 수 있습니다. 🎜🎜이 기능은 Chrome 63+, Firefox 57+, Safari 11.1+에서 사용할 수 있습니다. 🎜🎜아직도 비동기 반복자를 어디에 사용할 수 있는지 생각해 볼 수 있나요? 아래에 메시지를 남겨주세요! 🎜🎜더 많은 프로그래밍 관련 지식을 보려면 🎜프로그래밍 비디오🎜를 방문하세요! ! 🎜

위 내용은 Node.js 비동기 반복자 및 사용 방법에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 segmentfault.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제