"إذا أراد العامل أن يؤدي عمله بشكل جيد، فعليه أولاً أن يشحذ أدواته." - كونفوشيوس، "مختارات كونفوشيوس. لو لينجونج"
الصفحة الأمامية > برمجة > الوعود في جافا سكريبت: فهم التعليمات البرمجية غير المتزامنة والتعامل معها وإتقانها

الوعود في جافا سكريبت: فهم التعليمات البرمجية غير المتزامنة والتعامل معها وإتقانها

تم النشر بتاريخ 2024-11-07
تصفح:553

Promises in JavaScript: Understanding, Handling, and Mastering Async Code

مقدمة

كنت أعمل كمطور جافا وأتذكر لأول مرة عندما تواصلت مع وعود في جافا سكريبت. على الرغم من أن المفهوم بدا بسيطًا، إلا أنني ما زلت غير قادر على فهم كيفية عمل الوعود بشكل كامل. لقد تغير الأمر عندما بدأت في استخدامها في المشاريع وفهمت الحالات التي قاموا بحلها. ثم جاءت لحظة AHA وأصبح كل شيء أكثر وضوحًا. بمرور الوقت، أصبحت الوعود سلاحًا قيمًا في حزام أدواتي. إنه أمر مُرضي بشكل غريب عندما أتمكن من استخدامها في العمل وحل مشكلة التعامل غير المتزامن بين الوظائف.

ربما تصادف الوعود لأول مرة عند جلب البيانات من واجهة برمجة التطبيقات، وهو أيضًا المثال الأكثر شيوعًا. لقد أجريت مقابلة مؤخرًا معي، وخمن ما هو السؤال الأول الذي طرحته "هل يمكنك إخباري بالفرق بين Promise وAsync Await؟". وأنا أرحب بذلك لأنني أعتبره نقطة انطلاق جيدة لمعرفة كيفية فهم مقدم الطلب بشكل أفضل لكيفية عمل الآليات. ومع ذلك، فهو يستخدم في الغالب مكتبات وأطر عمل أخرى. اسمحوا لي أن أكتب الاختلافات وأصف الممارسات الجيدة للتعامل مع أخطاء الوظائف غير المتزامنة.

ما هو الوعد

لنبدأ بالسؤال الأولي: "ما هو الوعد؟" الوعد هو عنصر نائب للقيمة التي لا نعرفها بعد ولكننا سنحصل عليها نتيجة للحساب/الوظيفة غير المتزامنة. إذا سار الوعد بشكل جيد، فسوف نحصل على النتيجة. إذا لم يسر الوعد على ما يرام، فسيرجع الوعد خطأً.

مثال أساسي على الوعد

تعريف الوعد

يمكنك تعريف Promise عن طريق استدعاء مُنشئه وتمرير وظيفتي رد اتصال: حل ورفض.

const newPromise = new Promise((resolve, reject) => {
    resolve('Hello');
    // reject('Error');
});

نطلق على وظيفة الحل عندما نريد حل الوعد بنجاح. الرفض هو رفض الوعد في حالة حدوث خطأ أثناء تقييم منطقنا.

استرجاع نتيجة الوعد

نستخدم الوظيفة المضمنة للحصول على نتيجة الوعد. يحتوي على ردي اتصال تم تمريرهما، النتيجة والخطأ. يتم استدعاء النتيجة عندما يتم حل الوعد بنجاح من خلال حل الوظيفة. إذا لم يتم حل الوعد، فسيتم استدعاء خطأ الوظيفة الثاني. يتم تشغيل هذه الوظيفة إما عن طريق الرفض أو عن طريق خطأ آخر تم طرحه.

newPromise.then(result => {
    console.log(result); // Hello
}, error => {
    console.log("There shouldn't be an error");
});

في مثالنا، سنحصل على النتيجة مرحبًا لأننا نجحنا في حل الوعد.

خطأ في التعامل مع الوعود

عندما يتم رفض الوعد، يتم دائمًا استدعاء رد الاتصال الثاني للخطأ.

const newPromise1 = new Promise((resolve, reject) => {
  reject('An error occurred in Promise1');
});

newPromise1.then(
  (result) => {
    console.log(result); // It is not invoked
  },
  (error) => {
    console.log(error); // 'An error occurred in Promise1'
  }
);

الطريقة الموصى بها أكثر لوضوحها هي استخدام طريقة الالتقاط المضمنة.

const newPromise2 = new Promise((resolve, reject) => {
  reject('An error occurred in Promise2');
});

newPromise2
  .then((result) => {
    console.log(result); // It is not invoked
  })
  .catch((error) => {
    console.log(error); // 'An error occurred in Promise2'
  });

طريقة الالتقاط متسلسلة وقد قدمت رد اتصال خطأ خاصًا بها. يتم استدعاؤه عند رفض الوعد.

يعمل كلا الإصدارين بشكل جيد ولكن التسلسل هو IMO أكثر قابلية للقراءة ويكون مفيدًا عند استخدام طرق مدمجة أخرى نغطيها بشكل أكبر.

الوعود المتسلسلة

من المحتمل أن تكون نتيجة الوعد وعدًا آخر. في هذه الحالة، يمكننا تسلسل عدد عشوائي من وظائف ثم.

getJSON('categories.json')
    .then(categories => {
        console.log('Fetched categories:', categories);

        return getJSON(categories[0].itemsUrl);
    })
    .then(items => {
        console.log('Fetched items:', items);

        return getJSON(items[0].detailsUrl);
    })
    .then(details => {
        console.log('Fetched details:', details);
    })
    .catch(error => {
        console.error('An error has occurred:', error.message);
    });

في مثالنا، يعمل هذا على تضييق نطاق نتائج البحث للحصول على بيانات التفاصيل. يمكن أيضًا أن يكون لكل دالة رد اتصال خطأ خاص بها. إذا كنا نهتم فقط برصد أي خطأ في سلسلة المكالمات، فيمكننا الاستفادة من وظيفة الالتقاط. سيتم تقييمه إذا أدى أي من الوعود إلى ظهور خطأ.

وعد الجميع

في بعض الأحيان نريد أن ننتظر نتائج المزيد من الوعود المستقلة ثم نتصرف بناءً على النتائج. يمكننا استخدام الوظيفة المضمنة Promise.all إذا لم نهتم بترتيب كيفية حل الوعود.

Promise.all([
    getJSON('categories.json'),
    getJSON('technology_items.json'),
    getJSON('science_items.json')
])
    .then(results => {
        const categories = results[0];
        const techItems = results[1];
        const scienceItems = results[2];

        console.log('Fetched categories:', categories);
        console.log('Fetched technology items:', techItems);
        console.log('Fetched science items:', scienceItems);

        // Fetch details of the first item in each category
        return Promise.all([
            getJSON(techItems[0].detailsUrl),
            getJSON(scienceItems[0].detailsUrl)
        ]);
    })
    .then(detailsResults => {
        const laptopDetails = detailsResults[0];
        const physicsDetails = detailsResults[1];

        console.log('Fetched laptop details:', laptopDetails);
        console.log('Fetched physics details:', physicsDetails);
    })
    .catch(error => {
        console.error('An error has occurred:', error.message);
    });

يأخذ Promise.all مجموعة من الوعود ويعيد مجموعة من النتائج. إذا تم رفض أحد الوعود، فسيتم رفض Promise.all أيضًا.

وعود السباق

وظيفة أخرى مدمجة هي Promise.race. يتم استخدامه عندما يكون لديك عدة وظائف غير متزامنة - وعود - وتريد التسابق معها.

Promise.race([
    getJSON('technology_items.json'),
    getJSON('science_items.json')
])
    .then(result => {
        console.log('First resolved data:', result);
    })
    .catch(error => {
        console.error('An error has occurred:', error.message);
    });

يمكن أن يستغرق تنفيذ الوعود أوقاتًا مختلفة ويقوم Promise.race بتقييم أول وعد تم حله أو رفضه من المصفوفة. يتم استخدامه عندما لا نهتم بالأمر ولكننا نريد نتيجة أسرع مكالمة غير متزامنة.

ما هو المتزامن في انتظار

كما ترون، تتطلب كتابة الوعود الكثير من التعليمات البرمجية المعيارية. لحسن الحظ، لدينا ميزة Async Await الأصلية، مما يجعل استخدام الوعود أسهل. نضع علامة على دالة بكلمة غير متزامنة وبهذا نقول أننا سنستدعي وظيفة غير متزامنة في مكان ما في الكود ويجب ألا ننتظرها. ثم يتم استدعاء الدالة غير المتزامنة بكلمة الانتظار.

مثال أساسي على Async Await

const fetchData = async () => {
    try {
        // Fetch the categories
        const categories = await getJSON('categories.json');
        console.log('Fetched categories:', categories);

        // Fetch items from the first category (Technology)
        const techItems = await getJSON(categories[0].itemsUrl);
        console.log('Fetched technology items:', techItems);

        // Fetch details of the first item in Technology (Laptops)
        const laptopDetails = await getJSON(techItems[0].detailsUrl);
        console.log('Fetched laptop details:', laptopDetails);
    } catch (error) {
        console.error('An error has occurred:', error.message);
    }
};

fetchData();

تم وضع علامة على بيانات الجلب الخاصة بنا على أنها غير متزامنة وتسمح لنا باستخدام الانتظار للتعامل مع المكالمات غير المتزامنة داخل الوظيفة. نحن نسمي المزيد من الوعود وسيتم تقييمها واحدًا تلو الآخر.

نستخدم كتلة المحاولة...التقاط إذا أردنا التعامل مع الأخطاء. يتم بعد ذلك اكتشاف الخطأ المرفوض في كتلة الالتقاط ويمكننا التصرف بناءً عليه مثل تسجيل الخطأ.

ما هو مختلف

كلاهما من ميزات التعامل مع JavaScript مع التعليمات البرمجية غير المتزامنة. يكمن الاختلاف الرئيسي في بناء الجملة عندما تستخدم الوعود التسلسل مع ثم والقبض ولكن بناء الجملة غير المتزامن في انتظار يكون أكثر تزامنًا. يجعل القراءة أسهل. تعد معالجة الأخطاء في انتظار عدم المزامنة أكثر وضوحًا عندما تستفيد من كتلة المحاولة...التقاط. هذا سؤال يمكنك الحصول عليه بسهولة في المقابلة. أثناء الإجابة، يمكنك التعمق في وصف كليهما وإبراز تلك الاختلافات.

ميزات الوعد

بالطبع، يمكنك استخدام كافة الميزات مع الانتظار غير المتزامن. على سبيل المثال Promise.all.

const fetchAllData = async () => {
    try {
        // Use await with Promise.all to fetch multiple JSON files in parallel
        const [techItems, scienceItems, laptopDetails] = await Promise.all([
            getJSON('technology_items.json'),
            getJSON('science_items.json'),
            getJSON('laptops_details.json')
        ]);

        console.log('Fetched technology items:', techItems);
        console.log('Fetched science items:', scienceItems);
        console.log('Fetched laptop details:', laptopDetails);
    } catch (error) {
        console.error('An error occurred:', error.message);
    }
};

حالات الاستخدام العملي

تعد الوعود ميزة أساسية في JavaScript للتعامل مع التعليمات البرمجية غير المتزامنة. فيما يلي الطرق الرئيسية لاستخدامه:

جلب البيانات من واجهات برمجة التطبيقات

كما هو موضح بالفعل في الأمثلة أعلاه، تعد هذه إحدى حالات الاستخدام الأكثر استخدامًا للوعود وأنت تعمل معها يوميًا.

التعامل مع عمليات الملف

يمكن قراءة وكتابة الملفات بشكل غير متزامن باستخدام الوعود، خاصة من خلال وحدة Node.js fs.promises

import * as fs from 'fs/promises';

const writeFileAsync = async (filePath, content, options = {}) => {
    try {
        await fs.writeFile(filePath, content, options);
        console.log(`File successfully written to ${filePath}`);
    } catch (error) {
        console.error(`Error writing file to ${filePath}:`, error.message);
    }
};

const filePath = 'output.txt';
const fileContent = 'Hello, this is some content to write to the file!';
const fileOptions = { encoding: 'utf8', flag: 'w' }; // Optional file write options

writeFileAsync(filePath, fileContent, fileOptions);

المكتبات القائمة على الوعد

Axios هي مكتبة يجب أن تكون على دراية بها. يتعامل Axios مع طلبات HTTP في العميل ويتم استخدامه على نطاق واسع.

Express هو إطار ويب لـ Node.js. فهو يجعل من السهل إنشاء تطبيقات الويب وواجهات برمجة التطبيقات، وعندما تستخدم الوعود مع Express، تظل التعليمات البرمجية الخاصة بك نظيفة وسهلة الإدارة.

مستودع مع الأمثلة

يمكن العثور على جميع الأمثلة على: https://github.com/PrincAm/promise-example

ملخص

تعد الوعود جزءًا أساسيًا من JavaScript، وهي ضرورية للتعامل مع المهام غير المتزامنة في تطوير الويب. سواء كنت تقوم بجلب البيانات، أو العمل مع الملفات، أو استخدام المكتبات الشائعة مثل Axios وExpress، فسوف تستخدم الوعود بشكل متكرر في التعليمات البرمجية الخاصة بك.

في هذه المقالة، اكتشفنا ماهية الوعود، وكيفية تحديد نتائجها واستردادها، وكيفية التعامل مع الأخطاء بشكل فعال. لقد قمنا أيضًا بتغطية الميزات الرئيسية مثل التسلسل، وPromise.all، وPromise.race. أخيرًا، قدمنا ​​صيغة انتظار غير متزامن، والتي توفر طريقة أكثر وضوحًا للتعامل مع الوعود.

يعد فهم هذه المفاهيم أمرًا بالغ الأهمية لأي مطور جافا سكريبت، لأنها أدوات ستعتمد عليها يوميًا.

إذا لم تجرب ذلك بعد، فإنني أوصي بكتابة مقتطف رمز بسيط لجلب البيانات من واجهة برمجة التطبيقات. يمكنك البدء بواجهة برمجة تطبيقات ممتعة لتجربتها. بالإضافة إلى ذلك، تتوفر جميع الأمثلة ومقتطفات التعليمات البرمجية في هذا المستودع لتستكشفها.

بيان الافراج تم إعادة نشر هذه المقالة على: https://dev.to/princam/promises-in-javascript-understanding-handling-and-mastering-async-code-10kn?1 إذا كان هناك أي انتهاك، يرجى الاتصال بـ [email protected] لحذفه
أحدث البرنامج التعليمي أكثر>

تنصل: جميع الموارد المقدمة هي جزئيًا من الإنترنت. إذا كان هناك أي انتهاك لحقوق الطبع والنشر الخاصة بك أو الحقوق والمصالح الأخرى، فيرجى توضيح الأسباب التفصيلية وتقديم دليل على حقوق الطبع والنشر أو الحقوق والمصالح ثم إرسالها إلى البريد الإلكتروني: [email protected]. سوف نتعامل مع الأمر لك في أقرب وقت ممكن.

Copyright© 2022 湘ICP备2022001581号-3