Async Iterators and Generators

JavaScript Async Iterators and Generators (JavaScript异步迭代器和生成器)

Asynchronous iterators allow iterating over data, which comes asynchronously. For example, downloading something chunk-by-chunk over the network. (异步迭代器允许对异步产生的数据进行迭代。例如,通过网络逐块下载内容。)

With asynchronous generators, it becomes more convenient. To be more precise, let’s start at grasping the syntax. (有了异步发电机,它变得更加方便。更准确地说,让我们从掌握语法开始。)

Async Iterators

Async Iterators (异步迭代器)

Async iterators are, generally, like regular iterators. But, there are several syntactical differences. (异步迭代器通常与常规迭代器类似。但是,有几个句法上的区别。)

A regular iterable object is the following:

let range = {
 from: 1,
 to: 7,
 // for..of calls this method once at the very beginning
(//for.. of在开始时调用此方法一次)
 [Symbol.iterator]() {
   // ...returns the iterator object:
   // go ahead, for..of works only with this object,
(//请继续,因为..仅适用于此对象的作品,)
   // request  for next values using next()
(//使用next ()请求下一个值)
   return {
     current: this.from,
     last: this.to,
     // next() is called on each iteration in the for..of loop
(//在for.. of循环的每次迭代中调用next ())
     next() { // (2)
       // it return the value as an object {done:.., value :...}
       if (this.current <= this.last) {
         return {
           done: false,
           value: this.current++
         };
       } else {
         return {
           done: true
         };
       }
     }
   };
 }
};
for (let value of range) {
 console.log(value); // 1 then 2, then 3, then 4, then 5, then 6, then 7
}

For making the object asynchronously iterable, it is necessary to act in this way:

Using Symbol.asyncIterator rather than Symbol.iterator. A promise should be returned by the next(). It is necessary to use the for await (let item of iterable) loop for iterating over an object like that. (使用Symbol.asyncIterator而不是Symbol.iterator。 一个promise应该由next ()返回。 有必要使用for await ( let item of iterable )循环来迭代这样的对象。)

Let’s check out an example:

let range = {
 from: 1,
 to: 7,
 // for await..of calls this method once at the very beginning
(//for await.. of在开始时调用此方法一次)
 [Symbol.asyncIterator]() {
   // ...returns the iterator object:
   // go ahead, for await..of works only with this object,
(//继续,因为await.. of仅适用于此对象,)
   // request it for next values using next()
(//使用next ()请求它以获取下一个值)
   return {
     current: this.from,
     last: this.to,
     // next() is called on each iteration in the for await..of loop
(//在for await.. of循环中的每个迭代上调用next ())
     async next() {
       // it return the value as an object {done:.., value :...}
       // (automatically wrapped in an async promise)
(//(自动包装在异步promise中))
       // inside you can use await, do async things:
       await new Promise(resolve => setTimeout(resolve, 1000)); 
       if (this.current <= this.last) {
         return {
           done: false,
           value: this.current++
         };
       } else {
         return {
           done: true
         };
       }
     }
   };
 }
};
(async() => {
 for await (let val of range) { 
   console.log(val); // 1,2,3,4,5,6,7
 }
})()

Async Generators

Async Generators (异步生成器)

JavaScript also supports generators. They are also considered iterable. (JavaScript还支持生成器。它们也被认为是可迭代的。)

Let’s consider a regular generator that creates an order of values from the start to the end, like this:

function* generateSequence(start, end) {
 for (let i = start; i <= end; i++) {
   yield i;
 }
}
for (let value of generateSequence(1, 7)) {
 console.log(value); // 1, then 2, then 3, then 4, then 5, then 6, then 7
}

So, await can be used in regular generators. There is no space for a delay in the for..of loop, as all the values should come asynchronously. (因此, await可用于常规生成器。for.. of循环中没有延迟的空间,因为所有值都应异步出现。)

For using await in the generator body, you can prepend it with async in this way:

async function* generateSequence(start, end) {
   for (let i = start; i <= end; i++) {
     await new Promise(resolve => setTimeout(resolve, 1500));
     yield i;
   }
 }
 (async() => {
   let generator = generateSequence(1, 3);
   for await (let val of generator) {
     console.log(val); // 1, then 2, then 3
   }
 })();

There appeared an async generator, which is iterable with for await…of (出现了一个异步生成器,可以使用for await… of进行迭代)

Another difference of the asynchronous generator is that the generator.next() method is asynchronous, too and returns promises. (异步生成器的另一个区别是, generator.next ()方法也是异步的,并返回promise。)

So, in a regular generator,result = generator.next() is applied for getting values. In the async generator, await is added in this way:

results = await generator.next(); // results = {value: ..., done: true/false}

Async Iterables

Async Iterables

To transform an object into an iterable, Symbol.iterator should be added to it, like this:

let range = {
 from: 1,
 to: 3,
 [Symbol.iterator]() {
   return <object with next to make the range iterable>
 }
}

A frequently used practice for the Symbol.iterator is returning a generator, instead of a plain object using next. (Symbol.iterator的常用做法是返回生成器,而不是使用next的普通对象。)

Let’s see an example:

let range = {
 from: 1,
 to: 3,
 * [Symbol.iterator]() { // shorthand for [Symbol.iterator]: function*()
   for (let value = this.from; value <= this.to; value++) {
     yield value;
   }
 }
};
for (let val of range) {
 console.log(val); // 1, then 2, then 3
}

The custom object range is considered iterable. The *[Symbol.iterator] generator performs the logic for the listing values. Here is an example:

let range = {
 from: 1,
 to: 3,
 async * [Symbol.asyncIterator]() { // same [Symbol.asyncIterator]: async function*()
   for (let value = this.from; value <= this.to; value++) {
     //  pause between values, wait for something
(//pause between values, wait for something)
     await new Promise(resolve => setTimeout(resolve, 1500));
     yield value;
   }
 }
};
(async() => {
 for await (let val of range) {
   console.log(val); // 1, then 2, then 3
 }
})();

The values now will come with a delay of a second between them. (现在,这些值之间会有一秒钟的延迟。)

Summary

Summary (概要)

Regular generators and iterators work perfectly with the data that takes no time for generating. (常规生成器和迭代器可以完美地处理不需要时间生成的数据。)

While waiting for the data to come asynchronously with delays. Here for await..of is used rather than for..of. (等待数据异步延迟时。这里for await.. of用于而不是for.. of。)

Also, async generators can be used for processing streams of data that flow chunk-by-chunk. (此外,异步生成器可用于处理逐块流动的数据流。)



请遵守《互联网环境法规》文明发言,欢迎讨论问题
扫码反馈

扫一扫,反馈当前页面

咨询反馈
扫码关注
返回顶部