Asynchronous iterator for-await-of
Iterator interface (iterator)
Collection concepts include strings, arrays, objects, Maps, and Sets. There needs to be a unified interface mechanism to handle all different data structures.
What
Iterator iterator
is an interface that provides a unified access mechanism for different data structures.
Benefits
- Provide a unified and simple access interface for various data structures
- As long as any data structure deploys the
Iterator
interface (the value of this interface is an iterator object), it can complete thefor..of
traversal operation. - Enables the members of a data structure to be arranged in a certain order
Usage scenarios
for-of
traverses,Array.from
creates a shallow copy array- The spread operator
(…)
also calls the default Iterator interface. - When destructuring and assigning values to arrays and
Set
structures, the Symbol.iterator method will be called by default.
Principle
Iterator object
Objects that satisfy subordinate conditions can be called iterator objects
- There is a
next
method, and each call to thenext
method will return a result. The result value is anobject {value:xxx,done}
,value
represents the specific return value, anddone
is of Boolean type, indicating whether the collection The traversal is complete. - A pointer is maintained internally to point to the position of the current collection. Each time the
next
method is called, the pointer will move backward one position.
Deployment iterator interface
- Iterable data interfaces all have
[Symbol.iterator]
attributes internally, which is also known as implementing the Iterator interface. - The attribute of
[Symbol.iterator]
will return a functioncreateIterator
function, a method of creating an iterator object.- There is a method named
next
in the iterator object - The
next
method will return an object every time it is executed{value: value, done: boolean}
- There is a method named
The data structure that deploys the iterator interface is called an iterable object
String, Array, TypedArray, Map and Set all deploy the iterator interface because their prototype objects have a [Symbol.iterator]
method.
Case: Create an iterator object
/* Deploy the iterator interface to the data structure [Symbol.iterator] = createIterator */ // createIterator method: Create an iterator object // If you need to implement reverse order: i is initialized to items.length-1, followed by i-- function createIterator(items) {<!-- --> let i = 0; // internal pointer //Iterator object, which has a next method, which returns an object containing two properties: value and done return {<!-- --> next: function () {<!-- --> let done = i >= items.length; let val = !done ? items[i + + ] : undefined; return {<!-- --> done: done, value:val } } } } //test var it = createIterator(['a', 'b', 'c']); console.log(it.next());// {value: "a", done: false} console.log(it.next());// {value: "b", done: false} console.log(it.next());// {value: "c", done: false} console.log(it.next());// "{ value: undefined, done: true }" console.log(it.next());// "{ value: undefined, done: true }" console.log(it.next());// "{ value: undefined, done: true }"
Asynchronous iterator
If the loop is a promise array, the value of the promise is obtained asynchronously, so its value cannot be obtained at the current position.
Deploy asynchronous iterator interface
[Symbol.asyncIterator]
Asynchronous iterator interface
function createIterator(items) {<!-- --> let i = 0; // internal pointer //Iterator object, which has a next method, which returns an object containing two properties: value and done return {<!-- --> next: function () {<!-- --> let done = i >= items.length; const value = done ? undefined : i + + ; return Promise.resolve({<!-- --> value, done }); } } }
Synchronous iterators and asynchronous iterators
Synchronized iterator
//Iterator object interface Iterator {<!-- --> next(value) : IteratorResult; [optional] throw(value) : IteratorResult; [optional] return(value) : IteratorResult; } //Iterate results interface IteratorResult {<!-- --> value : any; done : bool; }
Asynchronous iterator
//Asynchronous iterator interface AsyncIterator {<!-- --> next(value): Promise<IteratorResult>; [optional] throw(value) : Promise<IteratorResult>; [optional] return(value) : Promise<IteratorResult>; } //Iterate results interface IteratorResult {<!-- --> value : any; done : bool; }
Traversal of asynchronous iterator for-await-of
The for await of
loop can pause the loop. When the first asynchronous execution is completed, the next one will be executed. Finally, the output results will be output in synchronous order.
How to obtain the value in the promise array in a loop sequence
For promise arrays, Promise.all()
is generally used to obtain the results in order, so that the result of each promise can only be obtained from the last returned array (provided that all promises are successful).
In actual development, assuming that each promise is a request, then perform some operations at the place where the request returns.
So how to obtain the value
values in the promise
array in a loop order?
//Simulate some data obtained from backend requests, etc. function Gen(time) {<!-- --> return new Promise((resolve) => {<!-- --> setTimeout(function () {<!-- --> // Simulate that the execution time of each task is different, and the results of task execution are returned by resolve. resolve(time); }, time); }); } async function test() {<!-- --> const arr = [Gen(2000), Gen(1000), Gen(3000)]; // let i = 0; for (const item of arr) {<!-- --> console.log( Date.now(), await item, //The printing here will be put into the micro queue ); } } test(); //1698219031697 2000 //1698219033701 1000 //1698219033701 3000
Although this way of writing can get results, the time is not quite correct. If you imagine the asynchronous task as a back-end request, then when the result of 2000 comes out, 1000 has already been executed. So the final solutionfor-await-of
function Gen(time) {<!-- --> return new Promise((resolve, reject) => {<!-- --> setTimeout(function () {<!-- --> resolve(time) }, time) }) } async function test() {<!-- --> let arr = [Gen(2000), Gen(1000), Gen(3000)] for await(let item of arr) {<!-- --> console.log(Date.now(), item) //item is directly the value of promise } } test() //1698218308077 2000 //1698218308077 1000 //1698218309080 3000 //Equivalent to const p1 = await Gen[2000]; console.log(p1); const p2 = await Gen[1000]; console.log(p2); const p3 = await Gen[3000]; console.log(p3);