Преобразование дублированного кода JS в функцию более высокого порядка
У меня есть блок кода, который используется повторно, и я хочу использовать функциональное программирование, чтобы удалить это дублирование.
Мой код принимает массив элементов, разбивает их на пакеты по 500 и затем выполняет над ними какую-то работу.
В первой функции он удаляет элементы из базы данных:
Функция удаления:
const deleteDocuments = async (documentReferences) => {
const batchesOf500 = Math.ceil(documentReferences.length / 500);
for(let batchNumber = 0; batchNumber < batchesOf500; batchNumber += 1) {
const batch = getBatchWriter();
const startingIndex = batchNumber * 500;
const maxIndex = startingIndex + 500;
for(let index = startingIndex; index < maxIndex; index += 1) {
if(index < documentReferences.length) {
const documentPath = documentReferences[index];
batch.delete(documentPath);
}
}
await batch.commit();
}
}
Вторая функция почти идентична, но вместо удаления из базы данных она записывает в базу данных:
Добавить функцию:
const writeToCollection = async (dataArray, collectionRef) => {
const batchesOf500 = Math.ceil(dataArray.length / 500);
for(let batchNumber = 0; batchNumber < batchesOf500; batchNumber += 1) {
const batch = getBatchWriter();
const startingIndex = batchNumber * 500;
const maxIndex = startingIndex + 500;
for(let index = startingIndex; index < maxIndex; index += 1) {
if(index < dataArray.length) {
const [key, value] = dataArray[index];
const doc = getDocFromPath(key);
batch.set(doc, value);
}
}
}
await batch.commit();
}
}
Эти функции почти идентичны, поэтому я написал функцию более высокого порядка, которая выполняет большую часть работы.
Функция высшего порядка:
const runFunctionInBatchesOf500 = (func, dataArray) => {
const batchesOf500 = Math.ceil(dataArray.length / 500);
for(let batchNumber = 0; batchNumber < batchesOf500; batchNumber += 1) {
const batch = this.firestore.batch();
const startingIndex = batchNumber * 500;
const maxIndex = startingIndex + 500;
for(let index = startingIndex; index < maxIndex; index += 1) {
const document = dataArray[index];
func(document, batch);
}
}
await batch.commit();
}
И для него вы можете создать свой собственный функционал, который будет применяться к каждому документу и использовать его следующим образом:
const write = (document, batch) => {
const doc = getDocFromPath(key);
batch.set(doc, value);
};
await runFunctionInBatchesOf500(write, dataArray);
Все это работает, но я думаю, что мне что-то не хватает. Эффективно ли это использование функций высшего порядка? Что могло бы быть более элегантным решением в стиле FP?
Ответы
Из небольшого обзора;
- Зачем жестко кодировать длину пакета до 500?
- Почему бы не сделать длину пакета постоянной величиной?
- Вы даже жестко указали длину в имени функции, что действительно прискорбно.
batchNumber++
более каноничен, чемbatchNumber += 1
- Я пошел бы за ,
maxIndex = Math.min(startingIndex + 500, dataArray.length);
потому что теперь у вас есть много звонков , чтобыfunc
сundefined
какdocument
значение await
требуетrunFunctionInBatchesOf500
бытьasync
(сейчас отсутствует)- Я бы использовал
Array.prototype.slice()
для создания пакетов в виде массива, а затем использовал быforEach
для каждого фрагмента / пакета const doc = getDocFromPath(key);
<- откудаkey
взялся злой глобал?
Я лично поступил бы мягко, если бы настроил прототип Array так, чтобы я мог продолжать связывание в стиле FP;
Array.prototype.mapSlice = function arrrayMapSlice(n){
//Just return `this` if we get a non-sensical parameter
if(isNaN(n) || n <= 0){
return this;
}
let start = 0, out = [];
while(start < this.length){
out.push(this.slice(start, start+=n));
}
return out;
}
async function runBatches(list, f, batchSize){
batchSize = batchSize || 500;
list.mapSlice(batchSize).forEach(batch => {
const firestoreBatch = this.firestore.batch();
batch.forEach(document => f(document, firestoreBatch ));
});
await batch.commit();
}