Mengonversi kode JS duplikat menjadi fungsi urutan yang lebih tinggi

Aug 20 2020

Saya memiliki blok kode yang digunakan kembali dan saya ingin menggunakan pemrograman fungsional untuk menghapus duplikasi ini.

Kode saya mengambil array item, membagi item menjadi batch 500 dan kemudian melakukan beberapa jenis pekerjaan pada mereka.

Fungsi pertama menghapus item dari database:

Hapus fungsi:

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

Fungsi kedua hampir identik tetapi alih-alih menghapus dari database, ia menulis ke database:

Tambahkan fungsi:

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

Fungsi-fungsi ini hampir identik, jadi saya telah menulis fungsi urutan yang lebih tinggi untuk melakukan sebagian besar pekerjaan kaki.

Fungsi urutan yang lebih tinggi:

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

Dan untuk itu Anda dapat membuat fungsionalitas Anda sendiri untuk diterapkan ke setiap dokumen dan menggunakannya seperti ini:

const write = (document, batch) => {
   const doc = getDocFromPath(key);
   batch.set(doc, value);
};

await runFunctionInBatchesOf500(write, dataArray);

Ini semua berhasil tetapi saya pikir saya melewatkan sesuatu. Apakah ini penggunaan yang efisien dari fungsi orde tinggi? Apa solusi yang lebih elegan dan bergaya FP?

Jawaban

6 konijn Aug 20 2020 at 14:59

Dari ulasan singkat;

  • Mengapa hardcode panjang batch menjadi 500?
  • Mengapa tidak membuat panjang tumpukan menjadi konstanta yang bagus?
  • Anda bahkan memiliki kode keras panjang dalam nama fungsi, yang sangat disayangkan
  • batchNumber++ lebih kanonik daripada batchNumber += 1
  • Saya akan pergi untuk maxIndex = Math.min(startingIndex + 500, dataArray.length);karena sekarang Anda memiliki banyak panggilan untuk funcdengan undefinedsebagai documentnilai
  • awaitmembutuhkan runFunctionInBatchesOf500untuk async(itu hilang sekarang)
  • Saya akan menggunakan Array.prototype.slice()untuk membuat batch sebagai array, dan kemudian menggunakannya forEachpada setiap slice / batch
  • const doc = getDocFromPath(key);<- dari mana keyasalnya, sebuah kejahatan global?

Saya pribadi akan menjadi agak jahat dengan menyesuaikan prototipe Array sehingga saya dapat terus merangkai, gaya 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();
}