پورت¶
برای برقراری ارتباط بین Elm و جاوااسکریپت، از Port استفاده میشود.
پورت برای کاربردهای localStorage
و WebSockets
استفاده میشود. بیایید روی نمونه WebSockets
تمرکز کنیم.
پورت در JavaScript¶
در این نمونه، تقریبا همان ساختار HTML را داریم که در برنامههای قبلی استفاده کردهایم، اما با کمی کد اضافی جاوااسکریپت. با ایجاد یک اتصال به wss://echo.websocket.org
هر چیزی را که به آن ارسال کنید، تکرار میکند. در نمونه کد Ellie میتوانید ببینید این کار به ما اجازه میدهد تا اسکلت یک اتاق چت را بسازیم:
با فراخوانی تابع ()Elm.Main.init
شروع کرده اما این بار از آبجکت app
استفاده میکنیم. برای ارسال داده، از پورت sendMessage
و برای دریافت داده از پورت messageReceiver
استفاده میکنیم.
این دو تابع، به کدی که در سمت Elm نوشته شده است، مربوط میشوند.
پورت در Elm¶
به خطوطی که از کلمه کلیدی port
در فایل Elm استفاده میکنند، نگاهی بیندازید. پورتهایی را که در سمت جاوااسکریپت دیدیم، بدین صورت در Elm تعریف میکنیم:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 |
|
توجه داشته باشید که در خط اول بجای module
از port module
استفاده شده است. این امکان وجود دارد که پورتها را در یک ماژول خاص تعریف کنید. در صورت نیاز، کامپایلر در این مورد شما را راهنمایی میکند، بنابراین امیدواریم کسی در این مورد خیلی گیر نکند!
بسیار خوب، اما چه اتفاقی در تعریف port
برای sendMessage
و messageReceiver
میافتد؟
پیامهای خروجی (Cmd
)¶
تعریف تابع sendMessage
اجازه میدهد تا پیامها را از Elm ارسال کنیم.
در اینجا اعلام میکنیم که میخواهیم مقدار String
را ارسال کنیم، اما میتوانیم هر نوع دادهای که با پرچم کار میکند را ارسال کنیم. در صفحه قبل درباره این نوع دادهها صحبت کردیم. میتوانید به این نمونه localStorage
نگاهی بیندازید تا ببینید یک Json.Encode.Value
چگونه به جاوااسکریپت ارسال میشود.
در ادامه، میتوانیم تابع sendMessage
را مانند هر تابع دیگری فراخوانی کنیم. اگر تابع update
یک دستور sendMessage "hello"
صادر کند، در سمت جاوااسکریپت درباره آن مطلع خواهید شد:
این کد جاوااسکریپت به تمام پیامهای خروجی مشترک شده است. میتوانید چندین تابع را مشترک کنید و توابع را با استفاده از تکنیک فراخوانی با ارجاع، لغو اشتراک کنید. بطور کلی توصیه میکنم که عملکرد آن را استاتیک یا ایستا نگه دارید.
همچنین توصیه میکنم بجای اینکه تعداد زیادی پورت ایجاد کنید، پیامهای غنیتری ارسال کنید. شاید این به معنای داشتن یک نوع داده سفارشی در Elm باشد که همه چیزهایی را که ممکن است بخواهید به جاوااسکریپت بگویید، نمایندگی کند و سپس از ماژول Json.Encode
برای ارسال آن به یک اشتراک جاوااسکریپت استفاده کنید. بسیاری از توسعهدهندگان متوجه میشوند که این کار منجر به عملکرد تمیزتری از SoC میشود. با استفاده از این تکنیک، Elm برخی از وضعیتها را در اختیار دارد و جاوااسکریپت وضعیتهای دیگر را.
پیامهای ورودی (Sub
)¶
تعریف تابع messageReceiver
اجازه میدهد تا به پیامهای ورودی Elm دسترسی یابیم.
در اینجا میگوییم که قرار است مقدار String
را دریافت کنیم، اما دوباره، میتوانیم برای هر نوع دادهای که میتواند از طریق پرچم یا پورت خروجی وارد شود، آماده باشیم. فقط کافی است نوع داده String
را با یکی از نوع دادههایی که میتوانند از مرز عبور کنند، جایگزین کنید.
میتوانیم تابع messageReceiver
را مانند هر تابع دیگری فراخوانی کنیم. در این مورد، هنگام تعریف subscriptions
، تابع messageReceiver Recv
را فراخوانی میکنیم زیرا میخواهیم از هر پیام ورودی جاوااسکریپت مطلع شویم. این کار به ما اجازه میدهد پیامهایی مانند ?Recv "How are you"
را در تابع update
دریافت کنیم.
در سمت جاوااسکریپت، میتوانیم هر زمان که بخواهیم به این پورت چیزی ارسال کنیم:
socket.addEventListener("message", function(event) {
app.ports.messageReceiver.send(event.data);
});
بطور تصادفی هر بار که WebSocket یک پیام دریافت میکند، داده ارسال میکنیم. اما میتوانید در زمانهای دیگر نیز این کار را انجام دهید. شاید پیامهایی از منبع داده دیگری نیز دریافت میکنیم. Elm نیازی به دانستن هیچ چیز درباره آن ندارد، که این خوب است! فقط رشتههای متنی را از طریق پورت مربوطه ارسال کنید.
یادداشت
کاربرد پورت در ایجاد مرزبندی قوی بین Elm و JavaScript است! به هیچ وجه سعی نکنید برای هر تابع مورد نیاز در جاوااسکریپت، یک پورت بسازید. ممکن است واقعا Elm را دوست داشته باشید و بخواهید همه چیز را در Elm انجام دهید، اما پورتها برای این کار طراحی نشدهاند. در عوض، بر روی سوالاتی مانند "چه کسی مالک وضعیت فعلی است؟" تمرکز و از یک یا دو پورت برای ارسال پیامها بطور متقابل استفاده کنید. اگر در یک سناریوی پیچیده هستید، میتوانید حتی مقادیر Msg
را با ارسال جاوااسکریپت مانند { tag: "active-users-changed", list: ... }
شبیهسازی کنید که در آن یک برچسب برای تمام اطلاعاتی که ممکن است ارسال کنید، وجود دارد.
در ادامه، چند راهنمایی ساده و مشکلات رایج آمده است:
-
ارسال
Json.Encode.Value
از طریق پورت توصیه میشود. مانند پرچم، برخی از انواع داده اصلی نیز میتوانند از طریق پورت عبور کنند. این عملکرد مربوط به زمانی است که هنوز دیکودِرهای JSON وجود نداشتند که میتوانید درباره آن بیشتر مطالعه کنید. -
تمام تعریفهای
port
باید در یکport module
ظاهر شوند. بهتر است تمام پورتهای خود را در یکport module
سازماندهی کنید تا مدیریت آن در یک فایل آسانتر شود. -
پورتها برای برنامهها هستند. یک
port module
فقط در برنامهها در دسترس است، اما نه در بستههای Elm. این کار اطمینان میدهد که توسعهدهندگان انعطافپذیری لازم را در برنامه خود داشته باشند، اما اکوسیستم بستهها بطور کامل با Elm پیادهسازی شود. اعتقاد دارم، این کار در دراز مدت یک اکوسیستم و جامعه کاربری قویتر ایجاد خواهد کرد. در بخش بعدی به محدودیتهای تعامل با جاوااسکریپت میپردازیم. -
پورتها میتوانند در فرآیند پاکسازی کد اضافی، حذف شوند. فرآیند پاکسازی کد اضافی در Elm به نسبت تهاجمی است و پورتهایی که در کد Elm استفاده نمیشوند را حذف میکند. کامپایلر نمیداند در سمت جاوااسکریپت چه میگذرد، بنابراین سعی کنید قبل از آن، چیزهای مرتبط را در Elm به یکدیگر متصل کنید.
امیدوارم این اطلاعات به شما کمک کند تا راهی برای گنجاندن Elm در پروژه خود پیدا کنید! این کار به اندازه انجام یک بازنویسی کامل در Elm جذاب نیست، اما تجربه نشان داده است که این استراتژی بسیار موثر است.