javascript traversal

You can use the traversal of the array, what about the Promise version?

The traversal methods referred to here include: map , reduce , reduceRight , forEach , filter , some , every
because some data aggregation is going to be done recently, the node version is already 8.11.1, so I wrote async/await a .
However, when performing some traversal operations on the array, it is found that Promise the not the result we want.

Of course, some are not strictly traversal, such as somethese every.
But indeed, these will call the incoming callback multiple times depending on the elements of our array.

These methods are relatively common, but when your callback function is one Promise, everything changes.

foreword

async/awaitReplacement will be used directly in Promisethe syntactic sugar for
async/awaitPromise

let result = await func()
// => 等价于
func().then(result => { // code here }) // ====== async function func () { return 1 } // => 等价与 function func () { return new Promise(resolve => resolve(1)) }

map

mapIt can be said to be the Promisemost friendly function.
As we all know, mapreceive two parameters:

  1. The callback executed for each element, the return value of the callback result will be used as the element of the corresponding subscript in the array
  2. an optional callback function thisto point to as an argument
[1, 2, 3].map(item => item ** 2) // 对数组元素进行求平方 // > [1, 4, 9]

The above is a normal mapexecution, but when some of our computational operations become asynchronous:

[1, 2, 3].map(async item => item ** 2) // 对数组元素进行求平方 // > [Promise, Promise, Promise]

At this time, the return value we get is actually an Promisearray of functions.

So why is it said that mapthe function is the most friendly, because we know that Promisethere is a function that Promise.all
will Promiseexecute an array of components in sequence and return an Promiseobject, and the result of the object is the result set generated by the array.

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

First Promise.allwrap the array with , then awaitget the result with .

reduce/reduceRight

reduceYou must be familiar with the function signature of , which accepts two parameters:

  1. The callback function executed for each element, the return value will be accumulated in the next function call, the signature of the callback function:

    1. accumulatoraccumulated value
    2. currentValueelement currently being processed
    3. currentIndexThe subscript of the element currently being processed
    4. arrayreducearray of calls
  2. optional initialized value to be used as accumulatorthe initial value of
[1, 2, 3].reduce((accumulator, item) => accumulator + item, 0) // 进行加和 // > 6

There is nothing wrong with this code, as if our addition operation is also asynchronous:

[1, 2, 3].reduce(async (accumulator, item) => accumulator + item, 0) // 进行加和 // > Promise {<resolved>: "[object Promise]3"}

The result returned will be very strange, we are looking back at reducethe function signature above

The callback function executed for each element, the return value will be accumulated to the next function call

Then let's look at the code, async (accumulator, item) => accumulator += item
which was also mentioned at the beginning, yes Pormisesyntactic sugar, in order to see it more clearly, we can write it like this:

(accumulator, item) => new Promise(resolve =>
  resolve(accumulator += item)
)

In other words, reducethe return value of our callback function is actually an Promiseobject ,
and then we operate on the Promiseobject +=, and it is very reasonable to get such a weird return value.

Of course, reducethe adjustment is also very easy:

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

We make the accumulatorcall await, and then itemadd it to the current one. At the end, our reducereturn value must also be one , so we also added the words Promiseon the outermost side, which means that we will return a new object every time, which will be obtained inside the object. last result. What we call actually get is an object like this:await
reducePromisePromise
reducePromise

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)) })

reduceRight

There is nothing to say about this. . It's just reducethe reverse of the order of execution

forEach

forEach, this should be the most used traversal method, the corresponding function signature:

  1. callback, a function to call for each element

    1. currentValue, the current element
    2. index, the current element subscript
    3. array, the calling forEacharray reference
  2. thisArg, an optional callback function thispointing to

We have the following operations:

// 获取数组元素求平方后的值
[1, 2, 3].forEach(item => { console.log(item ** 2) }) // > 1 // > 4 // > 9

In the normal version, we can directly output this way, but if we encounterPromise

// 获取数组元素求平方后的值
[1, 2, 3].forEach(async item => { console.log(item ** 2) }) // > nothing

forEachI don't care about the return value of the callback function, so I forEachjust execute three Promisefunctions that will return.
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) } } await [1, 2, 3].forEachSync(async item => { console.log(item ** 2) }) // > 1 // > 4 // > 9

awaitPromiseNon- values ​​will be ignored , await 0, await undefinedis no different from normal code

filter

filterAs a function for filtering arrays, it also has the function of traversing: the
function signature is the same forEach, but the element callbackwhose return value trueis will be placed in the filterreturn value of the function.

We want to do an odd filter, so we write:

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

Then we change to Promiseversion:

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

This will cause our filtering function to fail, because filterthe return value of the match is not an exact match, as long as the return value can be converted to true, it will be considered to pass the filter.
PromiseThe object must be true, so the filter fails.
So our processing method is forEachsimilar to the above, and we also need to perform object enhancement by ourselves,
but we directly choose a tricky method here:

Array.prototype.filterSync = async function (callback, thisArg) { let filterResult = await Promise.all(this.map(callback)) // > [true, false, true] return this.filter((_, index) => filterResult[index]) } await [1, 2, 3].filterSync(item => item % 2 !== 0)

We can call the method directly inside mapbecause we know we mapwill return all return values ​​as a new array.
This also means that we mapcan get itemthe results of all our filters, trueor false.
Next, return the result of the corresponding subscript to each item of the original array.

some

someAs a function to detect whether an array satisfies some conditions, it can also be used for traversal with the
same function signature forEach. The difference is that when any callbackreturn value matches, trueit will return directly true. If all callbackmatches are false, returnfalse

We want to check if any element in the array is equal to 2:

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

Then we change it toPromise

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

The function will still return true, but it's not what we want, because this is what the asyncreturned Promiseobject is identified as true.

So, we have 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 } return false } await [1, 2, 3].someSync(async item => item === 2) // > true

Since somethe traversal is terminated after the first one is matched true, what we use here forEachis a waste of performance.
It also takes advantage of awaitignoring ordinary expressions and uses it internally for-ofto achieve our needs

every

And our last every
function signature is the forEachsame,
but callbackthere are some differences in the processing:
In fact, from another perspective, everya reverse some
somewill terminate when the first one is obtained and will be trueterminated when the first one is obtained. Terminate, return if all elements are
everyfalsetruetrue

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

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

Obviously, none of them are matched, and the callback function has terminated when it is executed for the first time and will not continue to execute.
We change to Promiseversion:

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

This must be true, because we are judging the Promiseobject
, so we take the above someSyncimplementation 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 } return true } await [1, 2, 3].everySync(async item => item === 2) // > false

When any one is matched false, return directly to falseterminate the traversal.

 

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324979090&siteId=291194637