برنامه نویسی کاملا واکنش پذیر با Svelte 3.0

آفلاین
user-avatar
عرفان حشمتی
02 تیر 1400, خواندن در 13 دقیقه

این عنوان ممکن است کمی اغراق آمیز باشد، اما ایده‌ای که پشت آن است واقعا همین است. اگر هنوز نمی‌دانید Svelte چیست، پس با ما در این مقاله همراه باشید تا مفصل آن را برایتان شرح دهیم.

توجه داشته باشید که این یک آموزش در مورد نحوه شروع کار با Svelte نیست. اما در تلاش هستیم به زودی یک آموزش تعاملی گام به گام عالی را برایتان آماده کنیم.

قبل از اینکه وارد بحث اصلی شویم، اجازه دهید ابتدا نظر یکی از کاربران را با هم بررسی کنیم:

"Svelte به هیچ وجه نمی‌تواند به اندازه React واکنش پذیر باشد، حتی خود ری‌اکت هم کاملا واکنش پذیر نیست."

منظور این کاربر چیست و این چه تاثیری در نحوه نوشتن کد دارد؟ برای پاسخ به این سوال، بگذارید یک نمای ساده از نحوه کار React در پشت صحنه به شما ارائه دهیم.

هنگامی که یک برنامه React را رندر می‌کنید، ری‌اکت یک کپی از DOM را در چیزی به نام DOM مجازی نگه می‌دارد. DOM مجازی مانند واسطه‌ای بین کد ری‌اکت و آنچه مرورگر برای DOM ترسیم می‌کند، عمل خواهد کرد.

سپس هنگامی که داده‌ها تغییر می‌کند (ممکن است شما از this.setState یا useState استفاده کرده باشید)، ری‌اکت کمی روی آن کار می‌کند تا تعیین کند که چگونه می‌توان رابط کاربری را دوباره روی صفحه نمایش داد.

همچنین DOM مجازی را با DOM واقعی مقایسه می‌کند تا تعیین کند که چه چیزی به خاطر این به روزرسانی داده تغییر کرده است. سپس فقط قسمت‌هایی از DOM را که با نسخه جدید در DOM مجازی مطابقت ندارد، دوباره تغییر داده و هر بار که این فرایند صورت می‌گیرد نیازی به بروزرسانی مجدد کل DOM نیست.

این کار بسیار سریع انجام می‌شود زیرا به روزرسانی DOM مجازی بسیار آسان‌تر از به روزرسانی DOM واقعی است و ری‌اکت فقط بیت‌ها و تکه‌های DOM واقعی را که باید تغییر کنند به روز می‌کند. در ادامه این روند را دقیق‌تر بررسی خواهیم کرد.

اما چیزی که ممکن است در این فرایند برایتان جای سوال باشد این است که اگر به ری‌اکت نگویید که داده‌های شما تغییر کرده است (یعنی با فراخوانی this.setState یا معادل HookDOM مجازی تغییر نمی‌کند و ری‌اکت واکنشی نشان نمی‌دهد.

منظور کاربر از این که گفت ری‌اکت کاملا واکنش پذیر نیست این بود که ری‌اکت متکی به تصمیم شما است تا داده‌های برنامه را ردیابی کرده و در هنگام تغییر آنها را به روزرسانی کند.

خب حالا وقت آن است که به سراغ svelte برویم.

Svelte یک رویکرد کاملا جدید برای ایجاد رابط کاربری است و به طرز چشمگیری سریع، کارآمد و واقعا واکنش پذیر به طوری که بدون استفاده از DOM مجازی در خطوط کد کمتر از آنچه با هر فریمورک یا کتابخانه دیگری می‌نویسید، عمل می‌کند.

به نظر می‌رسد که همه چیز عالی است، اما این چه تفاوتی با تعداد بیشماری از دیگر کتابخانه‌ها و فریمورک‌های جاوااسکریپت دارد؟ در ادامه به شما خواهیم گفت.

برای مطالعه بیشتر می‌توانید مقاله ۱۰ دلیل برای اینکه Svelte را به هر توسعه دهنده وب جدیدی پیشنهاد کنیم را نیز بررسی کنید.

1. واکنش پذیری واقعی

Svelte یک کتابخانه نیست، حتی یک فریمورک هم نیست. بلکه این کامپایلری است که کد شما را می‌گیرد و جاوااسکریپت بومی را که مستقیما با DOM شما تعامل دارد بدون نیاز به واسطه از بین می‌برد.

بله این یک ایده عالی است که نمی‌دانم چرا تاکنون آنقدر مورد استقبال قرار نگرفته، اما به شما می‌گویم که چرا فکر می‌کنم این خیلی جالب است.

در زیر نقل قولی از صحبت‌های ریچ هریس در کنفرانس YGLF 2019 آورده شده است:

"Svelte 3.0 واکنش پذیری را از API کامپوننت خارج کرده و آن را به زبان منتقل می‌کند."

معنی این جمله چیست؟ قبل‌تر دیدیم که ری‌اکت (و بیشتر فریمورک‌های دیگر) چگونه نیاز به استفاده از API دارد تا به او بگویید داده تغییر کرده است (دوباره با فراخوانی this.setState یا استفاده از useState) قبل از اینکه بخواهد DOM مجازی خود را به روز کند.

نیاز به فراخوانی this.setState در ری‌اکت (و بیشتر فریمورک‌ها و کتابخانه‌های دیگر رابط کاربری) به این معنی است که واکنش پذیری برنامه شما اکنون به یک API خاص گره خورده است، و بدون آن کاملا از تغییرات داده بی اطلاع است.

Svelte رویکرد دیگری در این زمینه دارد که از شیوه اجرای کد در Observable الهام گرفته است. به این صورت که به جای اجرای کد از بالا به پایین، آن را به ترتیب توپولوژیک اجرا می‌کند. به قطعه کد زیر نگاه کنید:

1. (() => {
2.   const square = number => number * number;
3.
4.   const secondNumber = square(firstNumber);
5.   const firstNumber = 42;
6.
7.   console.log(secondNumber);
8. })();

اکنون اگر این کد از بالا به پایین اجرا شود، در خط 4 خطایی مشاهده خواهید کرد؛ زیرا secondNumber به firstNumber وابسته می‌باشد که در آن مرحله مقداردهی اولیه نشده است.

اگر همین کد را به ترتیب توپولوژیک اجرا کنید، هیچ خطایی پیش نمی‌آید. چطور ممکن است؟ کامپایلر این کد را از بالا به پایین اجرا نمی‌کند. در عوض نگاهی به همه متغیرها می‌اندازد و یک نمودار وابستگی ایجاد می‌کند (یعنی چه چیزی ابتدا به چه چیز دیگری نیاز دارد).

از نظر ما این دیدگاه مسخره است که چطور یک کامپایلر از نظر توپولوژیک کد را کامپایل می‌کند.

1. Does this new variable 'square' depend on any other variable?
     - it doesn't, so I'll initialize it
2. Does this new variable 'secondNumber' depend on any other variable?
     - it depends on 'square' and 'firstNumber'. I already initialized 'square', but I haven't initialized 'firstNumber', which I will do  now.
3. OK, I've initialized 'firstNumber'. Now I can initialize 'secondNumber' using 'square' and 'firstNumber'
     - Do I have all the variables required to run this console.log  statement?
     - Yes, so I'll run it.

در نگاه اول به نظر می‌رسد که کد از بالا به پایین در حال اجرا است، اما با یک نگاه دقیق‌تر متوجه می‌شوید که در واقع برخی از آنها جابه‌جا می‌شوند.

وقتی به خط 4 برسد کامپایلر متوجه می‌شود که firstNumber مقداری ندارد، بنابراین اجرا را در آنجا متوقف کرده و کد را جستجو می‌کند تا ببیند آیا آن را در جای دیگر تعریف کرده‌اید یا نه. و ما دقیقا این کار را در خط 5 انجام دادیم، پس خط 5 را بررسی می‌کند قبل از اینکه به خط 4 برگردد تا آن را اجرا کند.

نکته: اگر عبارت A به عبارت B وابسته باشد، دستور B بدون در نظر گرفتن ترتیب تعریف مقادیر زودتر اجرا می‌شود.

اما این رویکرد چگونه در پیاده سازی واکنش پذیری Svelte اعمال می‌شود؟ شما می‌توانید یک دستور را با یک شناسه در جاوااسکریپت مشخص کنید که به این صورت است: $: foo = bar.

و تمام کاری که انجام می‌دهد این است که یک شناسه به نام $ به عبارت foo = bar اضافه می‌کند (عملیاتی که اگر foo قبلا تعریف نشده باشد، به سختی شکست می‌خورد).

بنابراین در این حالت وقتی Svelte هر عبارتی را با پیشوند $ مشاهده کند، می‌داند که متغیر سمت چپ مقدار خود را از متغیر سمت راست می‌گیرد. اکنون ما راهی برای اتصال مقدار یک متغیر به مقدار دیگر داریم.

واکنش پذیری! این بدان معنی است که ما اکنون از یک هسته اصلیAPI  برای دستیابی به واکنش پذیری واقعی و بدون نیاز به APIهای شخص ثالث مانند this.setState استفاده می‌کنیم.

در عمل اینگونه به نظر می‌رسد:

1. // vanilla js
2. let foo = 10;
3. let bar = foo + 10; // bar is now 20
4. foo = bar // bar is still 20 (no reactivity)
5. bar = foo + 10 // now bar becomes 30
6. // svelte js
7. let foo = 10;
8. $: bar = foo + 10; // bar is now 20
9. foo = 15 // bar is now 25 because it is bound to the value of foo

توجه کنید که چگونه در کد بالا نیازی به تعیین مجدد bar به مقدار جدید foo نداریم یا این کار را مستقیما از طریق bar = foo + 10; انجام می‌دهیم یا با فراخوانی یک متد API مانند this.setState({ bar = foo + 10 }); که به طور خودکار برای ما مدیریت می‌شود.

این بدان معناست که وقتی bar را برابر با 15 قرار می‌دهید، foo به صورت خودکار به مقدار 25 به روز می‌شود و لازم نیست API را فراخوانی کنید تا آن را برای شما به روز کند، Svelte از قبل آن را می‌داند.

نسخه کامپایل شده کد Svelte بالا اینگونه به نظر می‌رسد:

1. ... omitted for brevity ...
2. function instance($$self, $$props, $$invalidate) {
3.   let foo = 10; // bar is now 20
4.   $$invalidate('foo', foo = 15) // bar is now 25 because it is bound to the value of foo
5.   let bar;
6.   $$self.$$.update = ($$dirty = { foo: 1 }) => {
7.     if ($$dirty.foo) { $$invalidate('bar', bar = foo + 19); }
8.   };
9.   return { bar };
10. }
11. ... omitted for brevity ...

سعی کنید کد بالا را به صورت کامل مطالعه کرده و حتما آن را بررسی کنید.

می‌بینید که چگونه به روزرسانی foo قبل از تعریف bar اتفاق افتاده؟ به این دلیل است که کامپایلر به جای بررسی از بالا به پایین، کد Svelte را به ترتیب توپولوژی تجزیه می‌کند.

Svelte به خودی خود نسبت به تغییرات داده واکنش نشان می‌دهد و دیگر نیازی نیست نگران پیگیری تغییرات و چگونگی انجام آنها باشید. خودش به طور خودکار همه چیز را می‌داند.

توجه: در خط 4 مقدار bar تا بعد از حلقه رویداد بعدی به روز نمی‌شود، این طور همه چیز خوب و مرتب است.

با این کار هر زمان اطلاعات شما تغییر کرد، دیگر نگران به روزرسانی دستی وضعیت خود نباشید. با اینکه Svelte به شما کمک می‌کند رابط کاربری خود را با آخرین وضعیت خود سازگار کنید، می‌توانید در طول پروژه بر منطق کار خود تمرکز کنید.

2. اختصار

به یاد دارید که گفتیم Svelte به شما اجازه می‌دهد کارهای کمتری را با نوشتن کد کمتر انجام دهید؟ در زیر یک کامپوننت ساده در React و معادل آن را در Svelte به شما نشان خواهیم داد و خودتان قضاوت کنید:

17 خط در مقابل 29 خط کد

این دو برنامه از نظر عملکرد کاملا یکسان هستند، اما می‌بینید که چه تعداد کد بیشتری برای نوشتن در React.js نیاز دارید – با این حال دیگر انگولار را مثال نمی‌زنیم!

خروجی:

جدا از اینکه کد Svelte چشم نوازتر است، استدلال در مورد آن نیز بسیار ساده‌تر می‌باشد؛ زیرا قطعات کمتری نسبت به کد React دارد. همچنین برای به روزرسانی مقدار عنصر ورودی، به یک کنترل کننده رویداد نیاز نداریم و فقط اتصال مقدار کافی است.

تصور کنید که تازه شروع به یادگیری توسعه وب کرده‌اید. کد کدامیک باعث سردرگمی بیشتر شما می‌شود؟

اگرچه به نظر می‌رسد این یک موضوع پیش پا افتاده باشد، اما به سرعت مشخص می‌شود که هنگام ساخت برنامه‌های بزرگتر و پیچیده‌تر، نوشتن خطوط کد کمتر مفید خواهد بود. من شخصا دیده‌ام که همکارانم ساعت‌ها زمان صرف تلاش برای درک چگونگی عملکرد یک کامپوننت بزرگ در ری‌اکت کرده‌اند.

صادقانه اعتقاد دارم که API ساده شده Svelte به ما امکان می‌دهد کدها را بسیار سریعتر بخوانیم و بهره وری کلی خود را بهبود ببخشیم.

3. عملکرد و کارایی

دیدیم که Svelte واقعا واکنش پذیر است و به شما امکان می‌دهد کارهای کمتری انجام دهید. اما در مورد عملکرد چطور؟ تجربه کاربر با برنامه‌هایی که کاملا در Svelte نوشته شده‌اند چگونه است؟

یکی از دلایل قدرتمند بودن ری‌اکت این است که چطور از DOM مجازی برای به روزرسانی بیت‌ها و بخش‌های رابط کاربری برنامه استفاده می‌کند و هر زمان تغییری صورت گیرد نیازی به بروزرسانی مجدد کل DOM نیست.

اگرچه یک نقطه ضعف در این روش وجود دارد که اگر داده‌های یک کامپوننت تغییر یابند، ری‌اکت آن کامپوننت و همه فرزندانش را مجددا رندر می‌کند، چه همه فرزندان نیاز به رندر مجدد داشته باشند چه نداشته باشند. به همین دلیل است که ری‌اکت دارای APIهایی مانند shouldComponentUpdate ، useMemo ، React.PureComponent و مواردی از این دست می‌باشد.

این مشکلی است که همیشه وجود داشته حتی اگر از DOM مجازی برای به روزرسانی رابط کاربری در صورت تغییر state استفاده شود.

با اینکه Svelte از DOM مجازی استفاده نمی‌کند، اما چگونه مسئله به روزرسانی DOM را برای مطابقت با وضعیت برنامه شما حل می‌کند؟ خوب بگذارید دوباره سخنان ریچ هریس را از سخنرانی فوق العاده YGLF نقل کنیم:

"فریمورک‌ها ابزاری برای سازماندهی کد نیستند، بلکه آنها ابزاری برای سازماندهی ذهن شما هستند."

نقل قول بالا همان چیزی است که ریچ را به این ایده سوق داده که یک فریمورک می‌تواند چیزی باشد که در مرحله ساخت اجرا شود و در زمان اجرا نیازی به داشتن واسطه برای کد شما نباشد. به خاطر این ایده است که Svelte صرفا یک کامپایلر است و فریمورک نیست.

این ایده ساده سرانجام منجر به این می‌شود که Svelte واقعا سریع است. Svelte کد شما را به یک کد کارآمد و سطح پایین که مستقیما با DOM تعامل دارد، کامپایل می‌کند. بسیار خوب است، اما چگونه مسئله بروزرسانی مجدد کل DOM را هنگام تغییر داده حل می‌کند؟

تفاوت تنها در نحوه کار یک فریمورک مانند React است که می‌داند چه چیزی تغییر کرده در مقابل Svelte می‌داند که چگونه آن را انجام دهد. ما دیدیم که ری‌اکت چطور به شما اجازه می‌دهد تا یک متد API را فراخوانی کرده تا هنگام تغییر داده‌ها به آن اطلاع دهید، اما در Svelte صرفا استفاده از عملگر انتساب = برای آن کافی است.

اگر یک متغیر state یا بهتر است بگوییم foo با استفاده از عملگر = به روز شود، Svelte فقط سایر متغیرهای وابسته به آن را به روز می کند، همانطور که قبلا دیدیم. این کار اجازه می‌دهد تا Svelte فقط قسمت‌هایی از DOM را که ارزش خود را از foo به دست می‌آورند، دوباره به روز کند.

من قصد دارم اجرای واقعی نحوه کار را کنار بگذارم، زیرا مقاله به اندازه کافی طولانی شده است. اما اگر مشتاق یادگیری بیشتر هستید، می‌توانید ویدئوی سخنان ریچ هریس را در این مورد ببینید.

سخن پایانی

Svelte 3.0 یکی از بهترین اتفاقاتی است که در توسعه نرم‌افزار رخ داده است. ممکن است برخی بگویند که این اغراق است، اما من مخالفم. مفهوم Svelte و نحوه اجرای آن به ما امکان می‌دهد کارهای بیشتری انجام دهیم با اینکه کد کمتری را به مرورگر می‌فرستیم.

این به نوبه خود به شما کمک می‌کند برنامه‌هایی با کارایی بیشتر، سبک‌تر و کدی که خوانایی آن آسان‌تر است، تولید کنید. اکنون فکر نمی‌کنید که Svelte به زودی جایگزین React ، Angular یا هر فریمورک فرانت-اند دیگری خواهد شد؟

فعلا برای جواب قطعی دادن به این سوال زود است. چرا که Svelte در مقایسه با آنها نسبتا جدید است. بنابراین برای رشد و تکامل و حل کردن برخی مشکلاتی که ممکن است هنوز ندانیم وجود دارند، به زمان بیشتری نیاز دارد.

درست مانند React که هنگام انتشار دنیای توسعه نرم‌افزار را تغییر داد، Svelte نیز توانایی تغییر نحوه تفکر ما درباره فریمورک‌ها و آنچه که در هنگام ایجاد برنامه‌های جدید برای ما امکان پذیر است را دارد.

منبع

چه امتیازی به این مقاله می دید؟
خیلی بد
بد
متوسط
خوب
عالی

دیدگاه‌ها و پرسش‌ها

برای ارسال دیدگاه لازم است، ابتدا وارد سایت شوید.

در حال دریافت نظرات از سرور، لطفا منتظر بمانید

در حال دریافت نظرات از سرور، لطفا منتظر بمانید

آفلاین
user-avatar
عرفان حشمتی @heshmati74
مهندس معماری سیستم های کامپیوتری، طراح و توسعه دهنده وب سایت
دنبال کردن

گفتگو‌ برنامه نویسان

بخشی برای حل مشکلات برنامه‌نویسی و مباحث پیرامون آن وارد شو