Conversione del codice JS duplicato in una funzione di ordine superiore
Ho un blocco di codice che viene riutilizzato e desidero utilizzare la programmazione funzionale per rimuovere questa duplicazione.
Il mio codice prende una serie di elementi, divide gli elementi in lotti di 500 e quindi esegue una sorta di lavoro su di essi.
Nella prima funzione cancella gli elementi da un database:
Elimina funzione:
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();
}
}
La seconda funzione è quasi identica ma invece di cancellare da un database, scrive nel database:
Aggiungi funzione:
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();
}
}
Queste funzioni sono quasi identiche, quindi ho scritto una funzione di ordine superiore per fare la maggior parte del lavoro sulle gambe.
Funzione di ordine superiore:
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();
}
E ad esso puoi creare la tua funzionalità da applicare a ciascun documento e usarlo in questo modo:
const write = (document, batch) => {
const doc = getDocFromPath(key);
batch.set(doc, value);
};
await runFunctionInBatchesOf500(write, dataArray);
Funziona tutto ma penso che mi manchi qualcosa. È un uso efficiente delle funzioni di ordine superiore? Quale sarebbe una soluzione più elegante, in stile FP?
Risposte
Da una breve recensione;
- Perché codificare la lunghezza del batch a 500?
- Perché non fare in modo che la lunghezza del lotto sia una bella costante?
- Hai persino codificato la lunghezza nel nome della funzione, il che è davvero un peccato
batchNumber++
è più canonico dibatchNumber += 1
- Avrei scelto
maxIndex = Math.min(startingIndex + 500, dataArray.length);
perché ora hai molte chiamate afunc
conundefined
comedocument
valore await
richiederunFunctionInBatchesOf500
di essereasync
(manca ora)- Lo userei
Array.prototype.slice()
per creare batch come array e quindi utilizzarliforEach
su ogni slice / batch const doc = getDocFromPath(key);
<- da dovekey
viene, un malvagio globale?
Personalmente sarei leggermente malvagio adattando il prototipo Array in modo da poter continuare a concatenare, stile 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();
}