What is a synchronous iterator?

Here’s an example:

var obj = {
  *[Symbol.iterator]() {
    yield 1;
    yield 2;
    yield 3; }}var iterator = obj[Symbol.iterator]()

iterator.next() // {value: 1, done: false}
iterator.next() // {value: 2, done: false}
iterator.next() // {value: 3, done: false}
iterator.next() // {value: undefined, done: true}
Copy the code

Each time the next method is called, it returns an object of the form {value: xx, done: xx}.

What is an asynchronous iterator?

Here’s another example:

var obj = {
  async* [Symbol.asyncIterator]() {
    yield 1;
    yield 2;
    yield 3; }}var asyncIterator = obj[Symbol.asyncIterator]()

asyncIterator.next().then(data= > console.log(data)) // {value: 1, done: false}
asyncIterator.next().then(data= > console.log(data)) // {value: 2, done: false}
asyncIterator.next().then(data= > console.log(data)) // {value: 3, done: false}
asyncIterator.next().then(data= > console.log(data)) // {value: undefined, done: true}
Copy the code

Unlike synchronous iterables where the [symbol. iterator] property is deployed, asynchronous iterables are marked by the [symbol. asyncIterator] property being deployed.

AsyncIterator is an asynchronous iterator. Unlike synchronous iterators, calling next on asyncIterator yields a Promise object with internal values {value: xx, done: Resolve ({value: xx, done: xx}).

Why do we have asynchronous iterators?

Synchronous iterators have data that can be retrieved immediately (without delay), whereas asynchronous iterators have data that can be retrieved over time (with delay).

Here are a few examples of why asynchronous iterators are used and how they can be used.

  1. Synchronous iterator data is given immediately, in order of processing equal to traversal order.
var obj = {
  *[Symbol.iterator]() {
    yield 1;
    yield 2;
    yield 3; }}for (let item of obj) {
	console.log(item) // 1 -> 2 -> 3. The processing order equals the traversal order
}
Copy the code
  1. If synchronizing iterator data acquisition takes time, use it againfor-ofTraversal, there’s a problem.
var obj = {
  *[Symbol.iterator]() {
    yield new Promise(resolve= > setTimeout((a)= > resolve(1), 5000));
    yield new Promise(resolve= > setTimeout((a)= > resolve(2), 2000));
    yield new Promise(resolve= > setTimeout((a)= > resolve(3), 500)); }}console.log(Date.now())
for (let item of obj) {
    item.then(data= > console.log(Date.now(), data))
}

/ / 1579253648926
// 1579253649427 3 // 1579253649427-1579253648926 = 501
// 1579253650927 2 // 1579253650927-1579253648926 = 2001
// 1579253653927 1 // 1579253653927-1579253648926 = 5001
Copy the code

Each item here can be treated as an interface request, and the return time of the data may not be determined. The print above illustrates the problem — we have no control over the order in which the data is processed.

  1. Consider asynchronous iterators
var obj = {
  async* [Symbol.asyncIterator]() {
    yield new Promise(resolve= > setTimeout((a)= > resolve(1), 5000));
    yield new Promise(resolve= > setTimeout((a)= > resolve(2), 3000));
    yield new Promise(resolve= > setTimeout((a)= > resolve(3), 500)); }}console.log(Date.now())
for await (let item of obj) {
	console.log(Date.now(), item)
}

/ / 1579256590699
// 1579256595700 1 // 1579256595700-1579256590699 = 5001
// 1579256598702 2 // 1579256598702-1579256590699 = 8003
// 1579256599203 3 // 1579256599203-1579256590699 = 8504
Copy the code

Note that asynchronous iterators are declared in the [symbol. asyncIterator] property, handled with a for-await-of loop. The end result is that tasks are handled one by one, with the previous task waiting for completion before moving on to the next.

Therefore, asynchronous iterators are designed to handle cases where the data is not available in real time and ensure that the final processing order is equal to the traversal order, but requires queueing.

for-await-of

For-await-of can be used with synchronous iterables as well as asynchronous iterables.

var obj = {
  *[Symbol.iterator]() {
    yield 1;
    yield 2;
    yield 3; }}for await(let item of obj) {
	console.log(item) // 1 -> 2 -> 3
}
Copy the code

If for-await-of finds no Symbol. AsyncIterator on the iterator, it calls Symbol. Iterator. The result, as we all know, is a synchronous iterator, on which the next method, when called, returns a plain object with a structure similar to {value: xx, done: xx}.

The result of await obj is still obj, as evidenced by the following example:

(async function() {
    var obj = { value: 1.done: false }
    console.log((await obj) === obj) // true}) ()Copy the code

That’s why we got this.

Also, note that if both [symbol.asynciterator] and [symbol.iterator] are deployed on an object, the asynchronous iterator generated by [symbol.Asynciterator] will be used in preference. This makes sense, because for-await-of was built for asynchronous iterators.

var obj = {
  *[Symbol.iterator]() {
    yield 1;
    yield 2;
    yield 3;
  },
  async* [Symbol.asyncIterator]() {
    yield 4;
    yield 5;
    yield 6; }}for await(let item of obj) {
	console.log(item) // 4 -> 5 -> 6. Asynchronous iterators generated by [symbol.asynciterator] are preferred
}
Copy the code

(End of text)


Advertising time (long term)

I have a good friend who owns a cattery, and I’m here to promote it for her. Now the cattery is full of Muppets. If you are also a cat lover and have the need, scan her FREE fish QR code. It doesn’t matter if you don’t buy it. You can just look at it.

(after)