دوال المُولدات في TypeScript

دوال المُولدات في TypeScript

توضح هذه المقالة دوال المُولدات في TypeScript۔

يمكنك تعلم كل شيء من أساسيات كيفية استخدام دوال المولد إلى أمثلة متقدمة مدمجة مع المعالجة غير المتزامنة، بالإضافة إلى أمثلة برمجية.۔

YouTube Video

دوال المُولدات

تقدم دوال المُولدات في TypeScript وظائف مشابهة لدوال المُولدات في JavaScript۔ يتم تعريف دوال المُولدات باستخدام function* (تصريح دالة مع علامة النجمة) وهي دوال خاصة يمكنها التوقف واستئناف التنفيذ على عكس الدوال العادية۔

عند استدعاء دالة المُولد، يتم إرجاع مكرر يقوم بإنشاء القيم واحدة تلو الأخرى، ويمكنك إيقاف التنفيذ باستخدام كلمة yield المفتاحية أو إرسال قيم من الخارج۔

الصياغة الأساسية لدوال المُولدات

 1function* myGenerator(): Generator<number, void, unknown> {
 2    yield 1;
 3    yield 2;
 4    yield 3;
 5}
 6
 7const gen = myGenerator();
 8
 9console.log(gen.next().value); // 1
10console.log(gen.next().value); // 2
11console.log(gen.next().value); // 3
12console.log(gen.next().done);  // true (Iteration finished)
  • تعريف دالة مُولد باستخدام function* myGenerator()۔
  • توقف كلمة yield المفتاحية تنفيذ الدالة أثناء إرجاع قيمة۔
  • في كل مرة يتم استدعاء طريقة next()، يستأنف تنفيذ دالة المُولد وتتقدم إلى الموضع التالي لـ yield۔

next() تُرجع كائنًا يحتوي على القيمة التالية وخصيصة done۔ عندما تكون done تساوي true، فهذا يشير إلى أنه تم إنشاء جميع القيم وانتهاء معالجة المُولد۔

تطبيقات دوال المُولدات

يتيح استخدام دوال المُولدات تمثيل عملية المعالجة التسلسلية بسهولة۔ في المثال التالي، نُنشئ دالة مُولد تولّد تسلسلًا من الأرقام۔

 1function* sequenceGenerator(start: number = 0, step: number = 1) {
 2    let current = start;
 3    while (true) {
 4        yield current;
 5        current += step;
 6    }
 7}
 8
 9const seq = sequenceGenerator(1, 2);
10
11console.log(seq.next().value); // 1
12console.log(seq.next().value); // 3
13console.log(seq.next().value); // 5
  • في هذا المثال، تولد sequenceGenerator تسلسلًا متزايدًا إلى ما لا نهاية من الأرقام۔ استخدم yield لإرجاع القيم عند كل خطوة، وقم بتوليد القيمة التالية في الاستدعاءات اللاحقة۔

تمرير القيم إلى next

يمكن لطريقة next() استلام قيمة، والتي يمكن إرسالها إلى داخل دالة المُولد۔

 1function* adder() {
 2    const num1 = yield;
 3    const num2 = yield;
 4    yield num1 + num2;
 5}
 6
 7const addGen = adder();
 8addGen.next();          // Initialization
 9addGen.next(5);         // Set 5 to num1
10const result = addGen.next(10).value; // Set 10 to num2 and get result
11console.log(result);    // 15
  • في هذا المثال، تقوم next(5) وnext(10) بإرسال القيم الخاصة بهما إلى داخل دالة المُولد، بينما تعيد yield num1 + num2 مجموعهما۔

return وthrow

  • return(value) يمكن أن تُنهي المُولد وتعيد القيمة المحددة۔
  • throw(error) يمكن أن تولّد استثناءً داخل المُولد، وتُستخدم للتعامل مع الاستثناءات داخله۔
 1function* testGenerator() {
 2    try {
 3        yield 1;
 4        yield 2;
 5    } catch (e) {
 6        console.error("Error caught:", e);
 7    }
 8}
 9
10const gen = testGenerator();
11console.log(gen.next().value); // 1
12gen.throw(new Error("An error occurred!")); // Error caught: An error occurred!
  • في هذا المثال، تُستخدم طريقة throw لتوليد خطأ داخل المُولد، ويتم التقاط ذلك الخطأ داخل المُولد۔

تعريف النوع في TypeScript

يمكن تحديد تعريف النوع لدالة المولد بالتنسيق التالي۔

1// Generator<YieldType, ReturnType, NextType>
2function* myGenerator(): Generator<number, void, unknown> {
3    yield 1;
4    yield 2;
5    yield 3;
6}
  • تقوم بتحديد الأنواع بالشكل Generator<YieldType, ReturnType, NextType>۔
    • YieldType هو نوع القيمة التي يُرجعها yield۔
    • ReturnType هو نوع القيمة التي يُرجعها return۔
    • NextType هو نوع القيمة التي يتم تمريرها إلى next()۔

في المثال التالي، يتم تحديد أنواع محددة لاستخدام المولّد بأمان مع الأنواع۔

 1function* numberGenerator(): Generator<number, void, number> {
 2    const num1 = yield 1;
 3    const num2 = yield num1 + 2;
 4    yield num2 + 3;
 5}
 6
 7const gen = numberGenerator();
 8
 9console.log(gen.next().value);   // 1
10console.log(gen.next(10).value); // 12 (10 + 2)
11console.log(gen.next(20).value); // 23 (20 + 3)

المولدات والمعالجة غير المتزامنة

يمكن أيضًا استخدام المولدات للمعالجة غير المتزامنة۔ على سبيل المثال، يمكنك استخدام yield للانتظار للحصول على نتائج العمليات غير المتزامنة مع الاستمرار في التنفيذ التسلسلي۔ ومع ذلك، فإن async/await تُستخدم بشكل أكثر شيوعًا في TypeScript أو JavaScript۔

1function* asyncTask() {
2    const result1 = yield fetch("https://codesparklab.com/json/example1.json");
3    console.log(result1);
4
5    const result2 = yield fetch("https://codesparklab.com/json/example2.json");
6    console.log(result2);
7}

لذلك، على الرغم من إمكانية معالجة العمليات غير المتزامنة بشكل تسلسلي باستخدام المولدات، إلا أنها لا تُستخدم كثيرًا لهذا الغرض بسبب أن Promises و async/await أكثر ملاءمة۔

الملخص

  • دوال المولد هي دوال خاصة تُعرف باستخدام function* ويمكنها إرجاع قيم باستخدام yield أثناء إيقاف تنفيذ الدالة مؤقتًا۔
  • استخدم next() لاستئناف المولد واستلام القيم۔ بالإضافة إلى ذلك، يمكنك إرسال قيم إلى المولد باستخدام next(value)۔
  • يمكنك استخدام return() و throw() لإنهاء دوال المولد أو لمعالجة الأخطاء۔
  • عند استخدام المولدات في TypeScript، يمكنك الاستفادة من تعريفات النوع لكتابة تعليمات برمجية آمنة من حيث النوع۔

المولدات هي أدوات قوية تتيح لك التحكم بمرونة في التكرار۔

يمكنك متابعة المقالة أعلاه باستخدام Visual Studio Code على قناتنا على YouTube.۔ يرجى التحقق من القناة على YouTube أيضًا.۔

YouTube Video