تنفيذ الطلبات بتسلسل وترتيب في Nodejs باستخدام Async/Await

فراس اللومنذ 7 سنوات

المستوى: مُبتدئ.

 

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

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

هل من حل؟ بكل تأكيد هناك حل منطقي وبسيط جدًا يتمثّل في Async/Await المدعومة بشكل افتراضي في Nodejs، أي تنفيذ المهام بشكل متزامن. وقبل كتابة المثال دعونا نتّفق على شيء واحد يتمثّل في ضرورة استخدام Promises مع Async/Await فبدونها لن يعمل الكود بالشكل المطلوب.


let app = require("express")()

let myFunc = ()=>{
    return new Promise((Resolve, Reject)=>{
        setTimeout(()=>{
            console.log("This is in between")
            Resolve()
        },3000)
    })
}
app.get("/", (req, res)=>{
        console.log("This is First")
        myFunc()
        console.log("This is Second")
        res.send("Ok")
   
    
})

app.listen(3000, ()=>{
    console.log("Running....`")
})

 باختصار يقوم الكود السابق باستقبال طلب المستخدم وطباعة ثلاث جمل، الأولى This is First والثانية This is in Between والثالثة This is Second. لكن لو قمت بتنفيذ الكود السابق ستتفاجئ بأن النتيجة ليست هكذا، حيث سيتم طبع الجملتين الأولى والثالثة، والثانية سيتم تنفيذها بعد 3 ثوان، وهذا لأنني أنا قمت بتأخيرها يدويًا لمحاولة شرح المُشكلة التي أتحدّث عنها، أي تنفيذ حدث دون انتهاء سابقه، الأمر الذي قد لا نرغب به أحيانًا.

يُمكنك تخيّل الجملة الثانية هي رفع الصور والثالثة هي تخزين أسماء الملفات في قاعدة البيانات. وهنا يأتي دور الـ Async/Await ليُصبح الكود على الشكل


let app = require("express")()

let myFunc = ()=>{
    return new Promise((Resolve, Reject)=>{
        setTimeout(()=>{
            console.log("This is in between")
            Resolve()
        },3000)
    })
}
app.get("/", async(req, res)=>{
    try{
        console.log("This is First")
        await myFunc()
        console.log("This is Second")
        res.send("Ok")
    }catch(e){
        throw e
    }
    
})

app.listen(3000, ()=>{
    console.log("Running....`")
})

لو قمت الآن بتشغيل الكود ستجد أن التنفيذ يجري بترتيب منطقي، يتم طباعة الجملة الأولى ثم الانتظار حتى طباعة الثانية، بعدها يقوم النظام بطباعة الثالثة.
لا تنس استخدام Promise مع الـ Async/Await، ولا تُفرط في استخدامها كثيرًا، فقط عند الحاجة. وكتنويه بسيط هناك بعض المكتبات مثل mongoose تقوم بإرجاع Promise لك عند إضافة سجل جديد لقاعدة البيانات، الأمر الذي يعني أنك تستطيع ببساطة وضعه ضمن Async/Await لتنفيذ أشياء فقط بعد الانتهاء من الإضافة. الفيديو يُظهر عمليًا ما الذي يحدث مع وبدون الـ Async/Await.

https://www.youtube.com/embed/4q2HGr-6N4M?feature=oembed

أما ما يحدث في الخفاء فهو مشروح في الصور التالية لفهم معمارية NodeJS بشكل كامل. كما يُمكن قراءة الموضوع التالي: "ماهو الـSingle Thread Event Loop في الـNodeJS"

5a19a76bbc49d_ScreenShot2017-11-25at2_08_18PM.thumb.png.eba15b129363e6915afe8c1709b1e7f7.png

5a19a778512bf_ScreenShot2017-11-25at2_13_48PM.thumb.png.820d4c48ba5cf2dd59afae6a78e7a457.png

 

إذا كانت هناك أية استفسارات أتمنى تركها في التعليقات أو التواصل معي في حسابي على تويتر @FerasAllaou

كلمات دليلية:
5
إعجاب
5443
مشاهدات
1
مشاركة
4
متابع
متميز
محتوى رهيب

التعليقات (2)

maher:

شكرا على الشرح 
ولكن لدي سؤال بخصوص مثال جلب محتويات الصفحة ..أخر مثال في الموضوع 
لماذا بدء بتنفيذ طباعة السطر الاخير وليس الاول 
اليس التسلسل كالتالي
1- طباعة السطر الاول
2-استدعاء الmyfetch وتنفيذه مع الانتظار حتى الانتهاء من الجلب
3- بعد الانتهاء يستدعي طباعة السطر الاخير 

أقصد أن الانتظار موجود ضمن التابع وبالتالي عملية الانتظار تتم عند استدعائه وعليه فطباعة السطر الاول سابقة لعملية الانتظار ولورودها اولا 

Mohamed Fakhr El Din:

الف شكر 👍

لايوجد لديك حساب في عالم البرمجة؟

تحب تنضم لعالم البرمجة؟ وتنشئ عالمك الخاص، تنشر المقالات، الدورات، تشارك المبرمجين وتساعد الآخرين، اشترك الآن بخطوات يسيرة !