การแปลงรหัส JS ที่ซ้ำกันเป็นฟังก์ชันลำดับที่สูงขึ้น

Aug 20 2020

ฉันมีบล็อกของโค้ดที่ใช้ซ้ำและต้องการใช้การเขียนโปรแกรมเชิงฟังก์ชันเพื่อลบการทำซ้ำนี้

รหัสของฉันใช้อาร์เรย์ของรายการแยกรายการออกเป็นชุดละ 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 ที่หรูหรากว่าจะเป็นอย่างไร

คำตอบ

6 konijn Aug 20 2020 at 14:59

จากบทวิจารณ์สั้น ๆ ;

  • ทำไมต้องฮาร์ดโค้ดความยาวแบทช์เป็น 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();
}