ES6에서는 동기 반복 개념이 도입되었습니다. ES8의 Async 연산자를 참조하여 비동기 작업에서 순회할 수 있나요?
오늘 저는 ES9의 비동기 탐색의 새로운 기능인 Async iteration에 대해 말씀드리고 싶습니다.
비동기 순회를 설명하기 전에 먼저 ES6의 동기 순회를 떠올려 보겠습니다.
ES6의 정의에 따르면 반복은 주로 세 부분으로 구성됩니다.
1. Iterable
먼저 Iterable의 정의를 살펴보겠습니다.
interface Iterable { [Symbol.iterator]() : Iterator; }
Iterable은 이 객체에 탐색 가능한 데이터가 있음을 의미합니다. Iterator를 생성하려면 Factory 메소드를 구현해야 합니다.
2. Iterator
interface Iterator { next() : IteratorResult; }
Iterator는 Iterable에서 빌드할 수 있습니다. Iterator는 커서와 유사한 개념으로, IteratorResult는 next를 통해 접근할 수 있습니다.
3. IteratorResult
IteratorResult는 다음 메서드가 호출될 때마다 얻은 데이터입니다.
interface IteratorResult { value: any; done: boolean; }
얻을 데이터를 나타내는 값 외에도 IteratorResult에는 순회 완료 여부를 나타내는 완료도 있습니다.
다음은 배열을 순회하는 예입니다.
> const iterable = ['a', 'b']; > const iterator = iterable[Symbol.iterator](); > iterator.next() { value: 'a', done: false } > iterator.next() { value: 'b', done: false } > iterator.next() { value: undefined, done: true }
그러나 위의 예는 동기 데이터를 순회합니다. http 측에서 다운로드한 파일과 같은 비동기 데이터를 얻는 경우 파일을 한 줄씩 순회하려고 합니다. 데이터 행을 읽는 것은 비동기 작업이므로 여기에는 비동기 데이터 순회가 포함됩니다.
파일의 비동기 읽기를 추가하는 방법은 readLinesFromFile이므로 동기 순회 방법은 더 이상 비동기에 적용할 수 없습니다.
//不再适用 for (const line of readLinesFromFile(fileName)) { console.log(line); }
아마도 Promise에서 한 줄의 비동기 읽기를 캡슐화한 다음 이를 순회할 수 있을까?라고 생각하실 수도 있습니다. 동기적으로?
아이디어는 좋지만 이 경우 비동기 작업이 완료되었는지 감지하는 것이 불가능합니다. 따라서 해당 방법은 실현 가능하지 않습니다.
그래서 ES9에서는 비동기 순회 개념을 도입했습니다.
Symbol.asyncIterator를 통해 비동기 반복 가능 항목에서 반복자를 가져올 수 있습니다.
비동기 반복자의 next() 메서드는 IteratorResults가 포함된 Promises 개체를 반환합니다.
그러므로 비동기 순회에 대한 API 정의를 살펴보겠습니다.
interface AsyncIterable { [Symbol.asyncIterator]() : AsyncIterator; } interface AsyncIterator { next() : Promise<IteratorResult>; } interface IteratorResult { value: any; done: boolean; }
비동기 순회 응용 프로그램을 살펴보겠습니다.
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 } });
그중 createAsyncIterable은 동기 반복 가능 항목을 비동기 반복 가능 항목으로 변환합니다. 이에 대해서는 아래에서 설명하겠습니다. 이 섹션에서는 어떻게 생성되는지 살펴보겠습니다.
여기에서는 주로 asyncIterator의 순회 작업에 중점을 둡니다.
Async 연산자가 ES8에 도입되었기 때문에 Async 함수를 사용하여 위 코드를 다시 작성할 수도 있습니다.
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를 사용하고, for-await -of can을 사용하세요. 비동기 반복 가능 트래버스.
async function f() { for await (const x of createAsyncIterable(['a', 'b'])) { console.log(x); } } // Output: // a // b
await는 async 함수에 배치되어야 한다는 점에 유의하세요.
비동기 순회 중에 예외가 발생하면 for-await-of에서 try catch를 사용하여 예외를 잡을 수 있습니다.
function createRejectingIterable() { return { [Symbol.asyncIterator]() { return this; }, next() { return Promise.reject(new Error('Problem!')); }, }; } (async function () { try { for await (const x of createRejectingIterable()) { console.log(x); } } catch (e) { console.error(e); // Error: Problem! } })();
Synchronized iterable은 동기 반복자를 반환하고 다음 메서드는 {value, done }을 반환합니다.
for-await-of를 사용하면 동기 반복자가 비동기 반복자로 변환됩니다. 그런 다음 반환된 값은 Promise로 변환됩니다.
동기식 next 자체가 반환한 값이 Promise 개체인 경우 비동기 반환 값은 여전히 동일한 Promise입니다.
즉, 다음 예와 같이 Iterableea14b2e011575f0c7465d02dc55e095c>
转换成为 AsyncIterable8742468051c85b06f0a0af9e3e506b5c
가 됩니다.
async function main() { const syncIterable = [ Promise.resolve('a'), Promise.resolve('b'), ]; for await (const x of syncIterable) { console.log(x); } } main(); // Output: // a // b
위 예는 동기 Promise를 비동기 Promise로 변환합니다.
async function main() { for await (const x of ['a', 'b']) { console.log(x); } } main(); // Output: // c // d
위의 예는 동기화된 상수를 Promise로 변환합니다. 둘의 결과는 동일함을 알 수 있다.
위의 예로 돌아가서 createAsyncIterable(syncIterable)을 사용하여 syncIterable을 AsyncIterable로 변환합니다.
이 메서드가 어떻게 구현되는지 살펴보겠습니다.
async function* createAsyncIterable(syncIterable) { for (const elem of syncIterable) { yield elem; } }
위 코드에서는 비동기 생성기를 나타내는 일반 생성기 함수 앞에 async를 추가합니다.
일반 생성기의 경우 다음 메서드가 호출될 때마다 {value,done} 개체가 반환됩니다. 이 개체 개체는 항복 값을 캡슐화합니다.
비동기 생성기의 경우 다음 메서드가 호출될 때마다 {value,done} 개체가 포함된 Promise 개체가 반환됩니다. 이 개체 개체는 항복 값을 캡슐화한 것입니다.
Promise 객체가 반환되기 때문에 다음 메서드를 다시 호출하기 전에 비동기 실행 결과가 완료될 때까지 기다릴 필요가 없습니다.
Promise.all을 통해 모든 비동기 Promise 작업을 동시에 실행할 수 있습니다.
const asyncGenObj = createAsyncIterable(['a', 'b']); const [{value:v1},{value:v2}] = await Promise.all([ asyncGenObj.next(), asyncGenObj.next() ]); console.log(v1, v2); // a b
createAsyncIterable에서는 동기 Iterable에서 비동기 Iterable을 생성합니다.
다음으로 비동기 Iterable에서 비동기 Iterable을 생성하는 방법을 살펴보겠습니다.
앞 섹션에서 for-await-of를 사용하여 비동기 Iterable 데이터를 읽을 수 있다는 것을 알았으므로 다음과 같이 사용할 수 있습니다.
async function* prefixLines(asyncIterable) { for await (const line of asyncIterable) { yield '> ' + line; } }
在generator一文中,我们讲到了在generator中调用generator。也就是在一个生产器中通过使用yield*来调用另外一个生成器。
同样的,如果是在异步生成器中,我们可以做同样的事情:
async function* gen1() { yield 'a'; yield 'b'; return 2; } async function* gen2() { const result = yield* gen1(); // result === 2 } (async function () { for await (const x of gen2()) { console.log(x); } })(); // Output: // a // b
如果在异步生成器中抛出异常,这个异常也会被封装在Promise中:
async function* asyncGenerator() { throw new Error('Problem!'); } asyncGenerator().next() .catch(err => console.log(err)); // Error: Problem!
异步方法是使用async function 声明的方法,它会返回一个Promise对象。
function中的return或throw异常会作为返回的Promise中的value。
(async function () { return 'hello'; })() .then(x => console.log(x)); // hello (async function () { throw new Error('Problem!'); })() .catch(x => console.error(x)); // Error: Problem!
异步生成器是使用 async function * 申明的方法。它会返回一个异步的iterable。
通过调用iterable的next方法,将会返回一个Promise。异步生成器中yield 的值会用来填充Promise的值。如果在生成器中抛出了异常,同样会被Promise捕获到。
async function* gen() { yield 'hello'; } const genObj = gen(); genObj.next().then(x => console.log(x)); // { value: 'hello', done: false }
本文作者:flydean程序那些事
本文链接:http://www.flydean.com/es9-async-iteration/
更多编程相关知识,请访问:编程视频!!
위 내용은 ES9의 새로운 기능 비동기 반복에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!