The traversal methods referred to here include: Map, reduce, reduceRight, forEach, filter, some, and every. Since we are going to perform some data summarization recently, node version is 8.11.1, so I directly wrote an async/await script. But when we did some traversal of the array, we found that some of the traversal methods didn’t give us the desired results for the Promise. The original source: www.cnblogs.com/jiasm/p/894… Author: Jia Shunming

Of course, some are not strictly ergodic, like some, every, etc. Make multiple calls to the incoming callback based on the elements of our array.

These methods are fairly common, but when your callback function is a Promise, everything changes.

preface

Async /await is the syntactic candy for Promise. Async /await is used directly to replace the Promise

letResult = await func() // => equivalent to func().then(result => {// code here}) // ====== asyncfunction func () {
  return1} // => Equivalent tofunction func () {
  return new Promise(resolve => resolve(1))
}
Copy the code

Map 1. Map is arguably the most promise-friendly function available. 2. As we all know, map takes two parameters:

For each element, the return value of the callback is referred to by an optional callback function called this for the corresponding subscript element in the array

[1, 2, 3]. The map (item = > item * * 2) / / to square array elements / / > [1, 4, 9]Copy the code

Above is a normal map execution, but when some of our calculations become asynchronous:

[1, 2, 3]. Map (async item => item ** 2) // > [Promise, Promise, Promise]Copy the code

At this point, the return value we get is an array of Promise functions.

All executes an array of promises and returns a Promise object whose result is the set of results that the array produced.

 await Promise.all([1, 2, 3].map(async item => item ** 2))
// > [1, 4, 9]
Copy the code

First wrap the array with promise.all and then get the result with await. ###reduce/reduceRight Reduce function signature is familiar to all, accept two parameters:

For each element, the return value is added to the next function call. The signature of the callback is: CurrentValue Indicates the element being processed. CurrentIndex Indicates the index of the element being processed. Array Indicates the optional initialization value of the array that calls Reduce

[1, 2, 3]. Reduce ((Accumulator, item) => Accumulator + item, 0Copy the code

This code is also fine, and also if we add the sum asynchronously:

[1, 2, 3]. Reduce (async (Accumulator, item) => Accumulator + item, 0)"[object Promise]3"}
Copy the code

This result will return a very strange result, we are looking back at the reduce function signature above

The callback function is executed on each element, and the return value is added to the next function callCopy the code

Async (accumulator, item) => Accumulator += item This is also mentioned in the very start, and is the syntax of Pormise.

 (accumulator, item) => new Promise(resolve =>
  resolve(accumulator += item)
 )
Copy the code

In other words, our Reduce callback returns a Promise object and then we do the += operation on the Promise object, and it makes sense to get that weird return.

Of course, the reduce adjustment is also easy:

 await [1, 2, 3].reduce(async (accumulator, item) => await accumulator + item, 0)
 // > 6
Copy the code

Our accumulator called await, and then added with the current item. In the end, the return value of our reduce must be a Promise, so we added await word on the outermost part, that is to say, we will return a new Promise object each time reduce. The result of the last Promise is retrieved inside the object. We actually get a Promise object that looks something like this when we call Reduce:

new Promise(resolve => {
  let item = 3
  new Promise(resolve => {
      let item = 2
      new Promise(resolve => {
        let item = 1
        Promise.resolve(0).then(result => resolve(item + result))
      }).then(result => resolve(item + result))
  }).then(result => resolve(item + result))
})
Copy the code

reduceRight

There’s nothing more to say about that. This is just the reverse of reduce

ForEach forEach = forEach forEach = forEach

  • Callback, the function that calls each element
  • CurrentValue, the current element
  • Index, the index of the current element
  • Array, call forEach array reference thisArg, an optional callback function this points to, as follows:
/ / get the value of the element after the square array [1, 2, 3] forEach (item = > {the console. The log (item 2) * *}) April / / / / / / > > 1 > 9Copy the code

In the normal version we could just print it like this, but if we hit a Promise

ForEach (async item => {console.log(item ** 2)}) // > nothingCopy the code

ForEach doesn’t care about the return value of the callback function, so forEach just executes three functions that return a Promise, so if we want to get the desired effect, we can only enhance the object properties ourselves:

Array.prototype.forEachSync = async function (callback, thisArg) {
  for (let[index, item] of object. entries(this)) {await callback(item, index, this)} 864305860 // For 1-3 years of front-end personnel // to help break the technical bottleneck, } await [1, 2, 3]. ForEachSync (async item => {console.log(item ** 2)}) // > 1 // > 4 // > 9Copy the code

Await ignores non-promise values, and await 0 and await undefined are the same as normal code

Filter filter is a function that filters arrays and has the same traversal function: the function signature is the same as forEach, but the elements that return true will be placed in the filter function.

We’re going to do an odd filter, so we’ll write it like this:

[1, 2, 3].filter(item => item % 2 ! == 0) // > [1, 3]Copy the code

Then we changed it to the Promise version:

[1, 2, 3].filter(async item => item % 2 ! == 0) // > [1, 2, 3]Copy the code

This invalidates our filter function because the return value matches of filter are not exactly equal matches and any return value that can be converted to true is considered to have passed the filter. The Promise object must be true, so filtering fails. So we’ll do the same with forEach, we’ll do our own object augmentation, but we’ll do a trick:

Array.prototype.filterSync = async function (callback, thisArg) {
  let filterResult = await Promise.all(this.map(callback))
  // > [true.false.true[// Welcome to join the full stack development communication circle to learn and communicate: 864305860 // For the front end staff of 1-3 years // to help break through the technical bottleneck and improve the thinking abilityreturnthis.filter((_, index) => filterResult[index]) } await [1, 2, 3].filterSync(item => item % 2 ! = = 0)Copy the code

We can call the map method directly internally, because we know that Map will return all the returned values as a new array. This means that our map can get the result of our filtering of all items, true or false. Then return the result of the corresponding index for each item in the original array.

Some Some exists as a function that checks whether an array meets certain criteria, and can also be used as a traversal function signature. Unlike forEach, some returns true if any callback matches true. If all callback matches false, Returns false

We need to check if any elements in the array are equal to 2:

 [1, 2, 3].some(item => item === 2)
 // > true
Copy the code

And then we change it to Promise

 [1, 2, 3].some(async item => item === 2)
 // > true
Copy the code

This function will still return true, but it’s not what we want, because this is the Promise object async returns that is supposed to be true.

Therefore, we need to do the following:

Array.prototype.someSync = async function (callback, thisArg) {
  for (let [index, item] of Object.entries(this)) {
    if (await callback(item, index, this)) return true}// Welcome to join the full stack development communication circle to learn and communicate: 864305860 // For the front-end staff of 1-3 years // to help break through the technical bottleneck and improve the thinking abilityreturn false
}
await [1, 2, 3].someSync(async item => item === 2)
// > true
Copy the code

Since some terminates traversal after the first true match, it is a waste of performance to use forEach here. We also take advantage of the fact that await ignores ordinary expressions and use for-of internally to implement our requirements

Every and our last every signature is the same as forEach, but the callback is handled differently: Or another way to think about it, every is just the inverse some and some terminates when it gets the first true and every terminates when it gets the first false, and if all elements are true, it returns true

We want to see if all the elements in the array are greater than 3

 [1, 2, 3].every(item => item > 3)
 // > false
Copy the code

Obviously, none of them were matched, and the callback function was terminated at the first execution and would not continue. We changed to the Promise version:

[1, 2, 3].every(async => item > 3)
 // > true
Copy the code

This must be true, since we’re judging the Promise object, so we’ll take the someSync implementation above and modify it slightly:

Array.prototype.everySync = async function (callback, thisArg) {
  for (let [index, item] of Object.entries(this)) {
    if(! await callback(item, index, this))return false}// Welcome to join the full stack development communication circle to learn and communicate: 864305860 // For the front-end staff of 1-3 years // to help break through the technical bottleneck and improve the thinking abilityreturn true
}
await [1, 2, 3].everySync(async item => item === 2)
// > false
Copy the code

When any false is matched, false is returned to terminate the traversal.

Postscript to these array traversal methods. Map and Reduce functions are the least altered when async is used due to their nature. The result of reduce is very much like an onion model, but for other traversal functions, they need to be implemented by themselves at present.

conclusion

Thank you for watching, if there are shortcomings, welcome to criticize.

We recommend you a free learning group, which covers mobile application website development, CSS, HTML, Webpack, Vue Node Angular and interview resources. Students interested in web development technology, welcome to join Q group: 864305860, no matter you are small white or Daniel I welcome, and Daniel organized a set of efficient learning routes and tutorials to share with you free, while updating video materials every day. In the end, I wish you all success as soon as possible, get satisfactory offer, fast promotion and salary increase, and walk on the peak of life.