foreword
async/await
Promise
Syntactic sugar for the
text will use the async/await
substitution directlyPromise
let result = await func()
// => 等价于
func().then(result => {
// code here
})
// ======
async function func () {
return 1
}
// => 等价与
function func () {
return new Promise(resolve => resolve(1))
}
map
map
It can be said to be the Promise
most friendly function.
As we all know, map
receive two parameters:
- 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
- an optional callback function
this
to point to as an argument
[1, 2, 3].map(item => item ** 2) // 对数组元素进行求平方
// > [1, 4, 9]
The above is a normal map
execution, 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 Promise
array of functions.
So why is it said that map
the function is the most friendly, because we know that Promise
there is a function that Promise.all
will Promise
execute an array consisting of in turn, and return an Promise
object, the result of which is the result set generated by the array.
await Promise.all([1, 2, 3].map(async item => item ** 2))
// > [1, 4, 9]
First Promise.all
wrap the array with , then await
get the result with .
reduce/reduceRight
reduce
You must be familiar with the function signature of , which accepts two parameters:
-
The callback function executed for each element, the return value will be accumulated in the next function call, the signature of the callback function:
accumulator
accumulated valuecurrentValue
element currently being processedcurrentIndex
The subscript of the element currently being processedarray
reduce
array of calls
- optional initialized value to be used as
accumulator
the 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 reduce
the 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 Pormise
syntactic sugar, in order to see it more clearly, we can write it like this:
(accumulator, item) => new Promise(resolve =>
resolve(accumulator += item)
)
That is to say, reduce
the return value of our callback function is actually an Promise
object ,
and then we operate on the Promise
object +=
and get such a weird return value is very reasonable.
Of course, reduce
the adjustment is also very easy:
await [1, 2, 3].reduce(async (accumulator, item) => await accumulator + item, 0)
// > 6
We call the accumulator
call await
, and then item
add it to the current one. At the end, our reduce
return value must also be one , so we also added the words Promise
on the outermost side. That is to say, we will return a new object every time , and we will get it inside the object. last result. What we call actually get is an object like this:await
reduce
Promise
Promise
reduce
Promise
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 reduce
the reverse of the order of execution
forEach
forEach
, this should be the most used traversal method, the corresponding function signature:
-
callback
, a function to call for each elementcurrentValue
, the current elementindex
, the current element subscriptarray
, the callingforEach
array reference
thisArg
, an optional callback functionthis
pointing 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
forEach
I don't care about the return value of the callback function, so I forEach
just execute three Promise
functions 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
await
Promise
Non- values will be ignored , await 0
, await undefined
is no different from normal code
filter
filter
As a function for filtering arrays, it also has the function of traversing: the
function signature is the same forEach
, but the element callback
whose return value true
is will be placed in the filter
return 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 Promise
version:
[1, 2, 3].filter(async item => item % 2 !== 0)
// > [1, 2, 3]
This will cause our filtering function to fail, because filter
the 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.
Promise
The object must be true
, so the filter fails.
So our processing method is forEach
similar 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 map
because we know we map
will return all return values as a new array.
This also means that we map
can get item
the results of all our filters, true
or false
.
Next, return the result of the corresponding subscript to each item of the original array.
some
some
As a function to detect whether an array satisfies some conditions, it can also be used for traversal. The
function signature is the same forEach
, the difference is that when any callback
return value matches, true
it will return directly true
, and if all callback
matches 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 async
returned Promise
object 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 some
the traversal is terminated after the first one is matched true
, what we use here forEach
is a waste of performance.
It also takes advantage of await
ignoring ordinary expressions and uses it internally for-of
to achieve our needs
every
And our last every
function signature is the forEach
same,
but callback
there are still some differences in the processing:
In fact, from another perspective, every
a reverse some
some
will terminate when the first one is obtained, and will be true
terminated when the first one is obtained. Terminate, return if all elements areevery
false
true
true
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 Promise
version:
[1, 2, 3].every(async => item > 3)
// > true
This must be true
, because we are judging the Promise
object
, so we take the above someSync
implementation 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 false
terminate the traversal.