Упомянутые здесь методы обхода включают:
map
,reduce
,reduceRight
,forEach
,filter
,some
,every
Поскольку в последнее время будет выполняться некоторая агрегация данных,node
Версия уже 8.11.1, поэтому и написал прямоasync/await
сценарий.
Однако при выполнении некоторых операций обхода массива обнаруживается, что некоторые методы обхода не подходят дляPromise
обратная связь не была тем результатом, который мы хотели.
Конечно, некоторые из них не являются строго обходными, напримерsome
,every
из этих.
Но на самом деле они будут вызывать входящий обратный вызов несколько раз в зависимости от элементов нашего массива.
Эти методы относительно распространены, но когда ваша функция обратного вызова являетсяPromise
когда все изменилось.
предисловие
async/await
дляPromise
синтаксический сахар для
будет использоваться непосредственно в текстеasync/await
заменятьPromise
let result = await func()
// => 等价于
func().then(result => {
// code here
})
// ======
async function func () {
return 1
}
// => 等价与
function func () {
return new Promise(resolve => resolve(1))
}
map
map
возможно верноPromise
Одна из самых дружественных функций.
мы все знаем,map
Принимает два параметра:
- Обратный вызов выполняется для каждого элемента, возвращаемое значение результата обратного вызова будет использоваться как элемент соответствующего индекса в массиве.
- необязательная функция обратного вызова
this
параметр указывал на
[1, 2, 3].map(item => item ** 2) // 对数组元素进行求平方
// > [1, 4, 9]
Сверху обычныйmap
выполняется, но когда некоторые из наших вычислительных операций становятся асинхронными:
[1, 2, 3].map(async item => item ** 2) // 对数组元素进行求平方
// > [Promise, Promise, Promise]
В настоящее время возвращаемое значение, которое мы получаем, на самом деле являетсяPromise
Массив функций.
Так почему ты говоришьmap
функция самая дружелюбная, потому что мы знаем,Promise
Есть функция дляPromise.all
будетPromise
Сформированный массив последовательно выполняется и возвращаетPromise
Объект, результатом которого является набор результатов, созданный массивом.
await Promise.all([1, 2, 3].map(async item => item ** 2))
// > [1, 4, 9]
первое использованиеPromise.all
оберните массив, затем используйтеawait
Получите результаты.
reduce/reduceRight
reduce
Вы должны быть знакомы с сигнатурой функции , которая принимает два параметра:
- Функция обратного вызова выполняется для каждого элемента, возвращаемое значение будет накапливаться при следующем вызове функции, сигнатура функции обратного вызова:
-
accumulator
накопленная стоимость -
currentValue
элемент в настоящее время обрабатывается -
currentIndex
Нижний индекс элемента, который в данный момент обрабатывается(благодарный@NeurotoxinVXДополнения от друзей) -
array
передачаreduce
массив
-
- необязательное инициализированное значение, которое будет использоваться как
accumulator
начальное значение
[1, 2, 3].reduce((accumulator, item) => accumulator + item, 0) // 进行加和
// > 6
В этом коде нет ничего плохого, как будто наша операция сложения тоже асинхронная:
[1, 2, 3].reduce(async (accumulator, item) => accumulator + item, 0) // 进行加和
// > Promise {<resolved>: "[object Promise]3"}
Возвращаемый результат будет очень странным, мы оглядываемся на вышеприведенноеreduce
сигнатура функции
Функция обратного вызова выполняется для каждого элемента, возвращаемое значение будет накапливаться до следующего вызова функции.
Затем мы снова смотрим на код,async (accumulator, item) => accumulator += item
Об этом было сказано в самом начале, даPormise
Синтаксический сахар , чтобы видеть более ясно, мы можем написать:
(accumulator, item) => new Promise(resolve =>
resolve(accumulator += item)
)
То есть мыreduce
Возвращаемое значение функции обратного вызова на самом деле являетсяPromise
объект
Тогда у нас естьPromise
возражать против выполнения+=
операция, очень разумно получить такое странное возвращаемое значение.
Конечно,reduce
Настройка также очень проста:
await [1, 2, 3].reduce(async (accumulator, item) => await accumulator + item, 0)
// > 6
Мыaccumulator
передачаawait
, а затем с текущимitem
сложить, в конце нашreduce
Возвращаемое значение также должно бытьPromise
, поэтому мы также добавляем самый внешний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
Об этом нечего сказать. . а такжеreduce
Это просто обратный порядок
forEach
forEach
, это должен быть наиболее часто используемый метод обхода, соответствующая сигнатура функции:
-
callback
, функция для вызова каждого элемента-
currentValue
, текущий элемент -
index
, индекс текущего элемента -
array
,передачаforEach
ссылка на массив
-
-
thisArg
, необязательная функция обратного вызоваthis
направление
У нас есть следующие операции:
// 获取数组元素求平方后的值
[1, 2, 3].forEach(item => {
console.log(item ** 2)
})
// > 1
// > 4
// > 9
В обычной версии мы можем напрямую выводить таким образом, но если мы встретимPromise
// 获取数组元素求平方后的值
[1, 2, 3].forEach(async item => {
console.log(item ** 2)
})
// > nothing
forEach
не заботится о возвращаемом значении функции обратного вызова, поэтомуforEach
Просто выполните три, вернетесьPromise
Функция
Поэтому, если мы хотим получить желаемый эффект, мы можем только сами улучшить свойства объекта:
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
стоимость,await 0
,await undefined
такой же, как обычный код
filter
filter
Как функция для фильтрации массивов, она также имеет функцию обхода:
Сигнатура функции такая же, какforEach
,ноcallback
Возвращаемое значениеtrue
элементы будут размещены вfilter
возвращаемое значение функции.
Мы хотим сделать нечетный фильтр, поэтому пишем:
[1, 2, 3].filter(item => item % 2 !== 0)
// > [1, 3]
Затем мы меняем наPromise
Версия:
[1, 2, 3].filter(async item => item % 2 !== 0)
// > [1, 2, 3]
Это делает наши функции фильтрации неэффективными, потому чтоfilter
Возвращаемое значение совпадения не является точным соответствием равенства, если возвращаемое значение может быть преобразовано вtrue
, это будет считаться прохождением фильтра.
Promise
объект должен бытьtrue
, поэтому фильтр не работает.
Итак, наш подход такой же, как и вышеforEach
Точно так же вам также необходимо выполнить улучшение объекта самостоятельно.
Но мы тут прямо выбираем хитрый путь:
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)
Мы можем напрямую позвонить внутрьmap
метод, как известноmap
Все возвращаемые значения будут возвращены в виде нового массива.
Это также означает, что мыmap
может получить нас всехitem
результат фильтрации,true
илиfalse
.
Затем верните результат соответствующего индекса каждому элементу исходного массива.
some
some
В качестве функции для определения того, удовлетворяет ли массив некоторым условиям, ее также можно использовать для обхода
Сигнатура функции такая же, какforEach
, разница в том, что когда либоcallback
Возвращаемое значение соответствуетtrue
вернется прямоtrue
, я упалcallback
спичкиfalse
, затем вернутьсяfalse
Мы хотим проверить, равен ли какой-либо элемент массива2
:
[1, 2, 3].some(item => item === 2)
// > true
Затем мы меняем его наPromise
[1, 2, 3].some(async item => item === 2)
// > true
Эта функция все равно вернетtrue
, но не то, что мы хотим, потому что этоasync
вернутьPromise
объект идентифицируется какtrue
.
Итак, мы должны сделать следующее:
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
потому чтоsome
соответствует первомуtrue
После этого обход будет прекращен, поэтому мы используем его здесьforEach
Это пустая трата производительности.
также используетсяawait
будет игнорировать преимущества обычных выражений и использовать их внутриfor-of
чтобы удовлетворить наши потребности
every
и наш последнийevery
Сигнатура функции такая же, какforEach
Такой же,
ноcallback
Есть еще некоторые отличия в обработке:
На самом деле, с другого ракурса,every
это обратная сторонаsome
some
получит первыйtrue
прекращается, когда
а такжеevery
получит первыйfalse
завершается, если все элементыtrue
, затем вернутьсяtrue
Мы хотим определить, все ли элементы в массиве больше 3
[1, 2, 3].every(item => item > 3)
// > false
Очевидно, что ни одно из них не совпадает, и функция обратного вызова завершилась при первом выполнении и больше не будет выполняться.
мы меняем наPromise
Версия:
[1, 2, 3].every(async => item > 3)
// > true
Это должно бытьtrue
, потому что мы судим, чтоPromise
объект
Итак, мы берем верхsomeSync
Реализация немного изменена:
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
при совпадении с любымfalse
, вернуться напрямуюfalse
, чтобы завершить обход.
постскриптум
Существует несколько методов обхода массивов.
потому чтоmap
а такжеreduce
функции, поэтому используетasync
функционировать с минимальными изменениями.
reduce
Результат очень похож на модель лука
Но для других функций обхода в настоящее время вам нужно реализовать это самостоятельно.
четыре*Sync
Реализация функции:GitHub.com/J IA SM/примечание B…