طراحی سایت و برنامه نویسی

آموزش طراحی سایت و برنامه نویسی

طراحی سایت و برنامه نویسی

آموزش طراحی سایت و برنامه نویسی

ارسال فرم HTML از طریق جاوا اسکریپت — راهنمای جامع

در این مقاله می‌خواهیم به بررسی روش‌های ارسال فرم HTML از طریق جاوا اسکریپت بپردازیم. در بخش قبلی دیدیم که فرم‌های HTML را می‌توان به صورت یک درخواست HTML به روش اعلانی ارسال کرد. در این بخش نیز با روش آماده‌سازی یک درخواست HTML برای ارسال از طریق جاوا اسکریپت آشنا می‌شویم. برای مطالعه بخش قبلی این نوشته به مطلب زیر مراجعه کنید:

فرم همیشه فرم نیست

از زمان معرفی open Web apps اینک استفاده از فرم های HTML در مقاصدی به جز فرم های معمولی که به صورت کاغذی پر می‌کنیم بسیار متداول شده است. بدین ترتیب رفته‌رفته توسعه‌دهندگان شروع به دست گرفتن کنترل بیشتری روی فرایند انتقال داده‌ها کرده‌اند.

به دست گرفتن کنترل اینترفیس سراسری

فرم HTML استاندارد، URL-ی را بارگذاری می‌کند که داده‌ها در آن ارسال می‌شوند، یعنی پنجره مرورگر برای بارگذاری یک صفحه کامل اقدام می‌کند. با این حال اجتناب از بارگذاری یک صفحه کامل موجب می‌شود که با پنهان‌سازی مشکلات و تأخیر شبکه، تجربه کاربری روان‌تری رقم بخورد.

اغلب UI-های مدرن از فرم های HTML برای گردآوری ورودی‌های کاربر استفاده می‌کنند. زمانی که کاربر تلاش می‌کند داده‌ها را ارسال بکند، اپلیکیشن کنترل را به دست می‌گیرد و این داده‌ها را به صورت ناهمگام در پس‌زمینه ارسال می‌کند. در ادامه تنها بخش‌هایی از رابط کاربری که نیازمند تغییر هستند، به‌روزرسانی می‌شوند.

فناوری ارسال داده‌های دلخواه به صورت ناهمگام به نام AJAX شناخته می‌شود که اختصاری برای عبارت «جاوا اسکریپت و XML ناهمگام» (Asynchronous JavaScript And XML) است.

تفاوت استفاده از جاوا اسکریپت در چیست؟

AJAX از شیء DOM به نام XMLHttpRequest یا به اختصار XHR استفاده می‌کند. این شیء می‌تواند درخواست‌های HTTP بسازد، آن‌ها را ارسال کند و نتایج را بازگشت دهد.

نکته: تکنیک‌های قدیمی‌تر AJAX صرفاً روی XMLHttpRequest تکیه نداشتند. برای نمونه JSOAP با تابع ()eval ترکیب شده بود. این تکنیک نیز کار می‌کند، اما استفاده از آن توصیه نمی‌شود، زیرا مشکلات امنیتی جدی دارد. تنها دلیل برای استفاده از این تکنیک ممکن است این باشد که مرورگرهای قدیمی از XMLHttpRequest یا JSON پشتیبانی نمی‌کنند، اما چنین مرورگرهایی باید واقعاً قدیمی باشند. بنابراین سعی کنید از چنین تکنیک‌هایی استفاده کنید.

XMLHttpRequest از لحاظ تاریخی برای واکشی و ارسال XML به عنوان یک فرمت تبادل داده طراحی شده است. اما نه XML و نه JSON در انکودینگ درخواست داده‌های فرم جای نمی‌گیرند. داده‌های فرم (application/x-www-form-urlencoded) لیست‌های انکودشده URL از جفت‌های کلید/مقدار تشکیل می‌دهند. برای ارسال کردن داده‌های باینری، درخواست HTTP به صورت multipart/form-data تغییر شکل می‌یابد.

اگر فرانت‌اند (کدی که در مرورگر اجرا می‌شود) و کد بک‌اند (کدی که روی سرور اجرا می‌شود) را کنترل کنید، می‌توانید JSON/XML را ارسال کرده و به هر شکلی که دوست دارید آن‌ها را پردازش کنید.

اما اگر می‌خواهید از سرویس شخص ثالث استفاده کنید؛ کار به این سادگی نیست. برخی سرویس‌ها تنها داده‌های فرم را می‌پذیرند. همچنین مواردی وجود دارند که استفاده از داده‌های فرم ساده‌تر است. اگر داده‌ها به صورت جفت‌های کلید/مقدار، یا داده‌های باینری خام باشند، ابزارهای بک‌اند موجود می‌توانند آن را بدون نیاز به هیچ کد اضافی مدیریت کنند.

اینک سؤالی که مطرح می‌شود، این است که روش ارسال این داده‌ها چگونه است؟ در بخش بعدی به این سؤال پاسخ می‌دهیم.

ارسال داده‌های فرم

3 روش برای ارسال داده‌های فرم وجود دارد که از تکنیک‌های قدیمی تا شیء جدیدتر FormData را شامل می‌شود. در ادامه همه این موارد را به تفصیل مورد بررسی قرار می‌دهیم.

ساخت یک به صورت دستی

XMLHttpRequest ساده‌ترین و مطمئن‌ترین راه برای ایجاد درخواست‌های HTTP محسوب می‌شود. برای ارسال داده‌های فرم با استفاده از XMLHttpRequest باید ابتدا داده‌ها را از طریق انکودینگ URL آماده کنیم و از مشخصه‌های تعیین شده برای درخواست‌های داده‌های فرم پیروی نماییم. در ادامه مثال قبلی را بازنویسی می‌کنیم:

چنان که مشاهده می‌کنید، HTML در عمل تغییر نیافته است. با این حال، کد جاوا اسکریپت کاملاً متفاوت است:

نتیجه نهایی به صورت زیر است:

نکته: استفاده از XMLHttpRequest تحت همان «سیاست اصالت» (origin policy) است که در زمان ارسال داده‌ها به وب‌سایت‌های شخص ثالث مورد استفاده قرار می‌گیرد. در مورد درخواست‌های cross-origin به کنترل دسترسی CORS و HTTP نیاز داریم.

استفاده از XMLHttpRequest و شیء FormData

ساخت یک درخواست HTTP به صورت دستی ممکن است کار پیچیده‌ای باشد. خوشبختانه یک استاندارد مشخصه XMLHttpRequest روشی راحت و ساده برای مدیریت درخواست‌های داده‌های فرم با شیء FormData ارائه می‌کند.

شیء FormFata می‌تواند برای انتقال داده‌های فرم یا برای به دست آوردن داده‌های درون یک عنصر فرم جهت مدیریت برای ارسال کردن آن، مورد استفاده قرار گیرد. توجه کنید که اشیای FormFata «فقط-نوشتنی» هستند، یعنی می‌توان آن‌ها را تغییر داد، اما نمی‌توان محتوای آن‌ها را بازیابی کرد.

در ادامه دو مثال از روش استفاده از این اشیا ارائه شده است:

استفاده از شیء مستقل FormData

شما احتمالاً با این کد ساده HTML آشنا هستید:

نتیجه آن چنین است:

استفاده از FormData متصل به یک عنصر فرم

روش دیگری که برای استفاده از شیء FormData وجود دارد، بهره‌گیری از عنصر <form> است. بدین ترتیب یک FormData ایجاد می‌شود که داده‌های موجود در فرم را نمایش می‌دهد.

کد نمونه HYML آن چنین است:

اما جاوا اسکریپت کنترل را از فرم می‌گیرد:

نتیجه کار چنین است:

شما با استفاده از مشخصه elements فرم می‌توانید لیستی از همه عناصر داده‌ای را در فرم به دست آورید و به صورت دستی آن‌ها را یک به یک مدیریت کنید. بدین ترتیب کنترل بیشتری روی این فرایند پیدا می‌کنید.

ساخت یک DOM در iframe پنهان

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

هشدار: شما باید از این روش اجتناب کنید. در زمان استفاده از سرویس‌های شخص ثالث این تکنیک موجب بروز ریسک‌های امنیتی می‌شود، زیرا شما را در معرض حمله‌های تزریق اسکریپت قرار می‌دهد. اگر از HTTPS استفاده می‌کنید، این تکنیک می‌تواند روی same origin policy تأثیر بگذارد که محتوای یک <iframe> را غیر قابل دسترسی می‌کند. با این حال این متد در صورت نیاز به پشتیبانی از مرورگرهای خیلی قدیمی ممکن است تنها گزینه موجود باشد.

به مثال زیر توجه کنید:

نتیجه کد فوق چنین است:

کار با داده‌های باینری

اگر از یک شیء FormData در فرمی با ویجت‌های <input type=”file”> استفاده می‌کنید، داده‌ها به صورت خودکار پردازش خواهند شد. اما برای ارسال داده‌های باینری به صورت دستی باید کار بیشتری انجام یابد.

منابع زیادی برای داده‌های باینری روی وب مدرن وجود دارند که برای نمونه شامل FileReader ،Canvas و WebRTC هستند. متأسفانه برخی مرورگرهای قدیمی نمی‌توانند به داده‌های باینری دسترسی پیدا کنند و نیازمند استفاده از راه‌حل‌های پیچیده‌ای هستند. بررسی این مرورگرهای قدیمی خارج از حوصله این مقاله است.

ارسال داده‌های باینری با پشتیبانی از FormData کار سرراستی است. کافی است از متد ()append استفاده کنید. اگر این کار را به صورت دستی انجام دهید پیچیده‌تر خواهد بود.

ما در مثال زیر از API به نام FileReader برای دسترسی به داده‌های باینری استفاده کردیم و سپس درخواست داده‌های چندبخشی فرم را به صورت دستی می‌سازیم:

چنان که مشاهده می‌کنید، کد HTML شامل یک <form> استاندارد است. در این کد هیچ اتفاق عجیبی نمی‌افتد. بخش اصلی کار در کد جاوا اسکریپت رخ می‌دهد:

نتیجه کد فوق چنین است:

سخن پایانی

بسته به مرورگری که استفاده می‌کنید، ارسال کردن داده‌ها از طریق جاوا اسکریپت می‌تواند کاری آسان یا دشوار باشد. شیء FormData عموماً پاسخگو است و روی مرورگرهای قدیمی نیز می‌توان از یک polyfill برای آن استفاده کرد

منبع: فرادرس


مقدار بازگشتی با ارجاع در ++C — راهنمای جامع

ر زبان برنامه‌نویسی ++C نه‌تنها می‌توان مقادیر را با ارجاع به یک تابع ارسال کرد، بلکه می‌توان مقدار بازگشتی با ارجاع را نیز به دست آورد. برای درک این قابلیت باید در مورد متغیرهای سراسری که در این نوشته از سری مطالب قبلی معرفی کردیم، اطلاعاتی داشته باشید:

برای مطالعه بخش قبلی این سری مقالات به لینک زیر رجوع کنید:

مثال

بازگشتی با ارجاع

خروجی

5

در برنامه فوق، نوع بازگشتی تابع ()test به صورت int& است. از این رو این تابع یک ارجاع از متغیر num بازگشت می‌دهد.

گزاره بازگشتی تابع به صورت زیر است:

return num;

برخلاف بازگشتیِ با مقدار، این گزاره مقدار متغیر num را بازگشت نمی‌دهد، بلکه خود متغیر یعنی آدرس آن را بازگشت می‌دهد. از این رو زمانی که متغیر بازگشت یابد، می‌توان آن را به یک مقدار مثلاً به صورت زیر انتساب داد:

test() = 5;

بدین ترتیب مقدار 5 در متغیر num ذخیره می‌شود که روی صفحه نمایش پیدا می‌کند.

نکات مهمی که هنگام استفاده از بازگشت با ارجاع باید به خاطر داشت

تابع معمولی مقدار بازگشت می‌دهد، اما این تابع چنین نیست. از این رو نمی‌توان یک ثابت را از تابع بازگشت داد:

نمی‌توان یک متغیر محلی را از این تابع بازگشت داد:

بدین ترتیب به پایان این بخش از سری مقالات راهنمای جامع ++C می‌رسیم.

اگر این مطلب برای شما مفید بوده است، آموزش‌های زیر نیز به شما پیشنهاد می‌شوند:

منبع: فرادرس


آموزش جامع Webpack (بخش دوم: آشنایی مقدماتی) — از صفر تا صد

در این بخش از طریق مقالات آموزش جامع Webpack با برخی مبانی این ابزار مهم جاوا اسکریپت آشنا می‌شویم. در بخش قبلی در مورد تاریخچه وب‌پک توضیح دادیم:

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

آغاز یک پروژه

ترمینال را باز کنید، دایرکتوری پروژه خود را ایجاد کنید یا یک ریپازیتوری خالی را کلون کنید و پکیج‌های جدیدی ایجاد نمایید:

yarn init –y

توجه کنید که ما در این سری مقالات از yarn استفاده می‌کنیم، اما شما در صورت ترجیح می‌توانید از npm نیز استفاده کنید.

بدین ترتیب محیط npm ایجاد می‌شود. سپس یک فایل ساده با برخی کدهای جاوا اسکریپت به نام src/index.js می‌سازیم:

نصب وابستگی‌ها

برای نصب محیط زمان اجرای Webpack و کلاینت باید دستور زیر را اجرا کنیم:

اجرای build

اینک آماده حرکت هستیم. دستور زیر را اجرا کنید:

اگر از npm نسخه 5 به بالا استفاده می‌کنید می‌توانید از دستور زیر نیز بهره بگیرید:

npm webpack

نتیجه کار چیزی مانند زیر خواهد بود:

توجه کنید که webpack در مورد ارائه mode هشدار می‌دهد و دلیل این مسئله آن است که حالت production تصور شده است. در ادامه در مورد معنای این هشدار بیشتر توضیح خواهیم داد.

اکنون می‌توانیم خروجی را در dist/main.js مشاهده کنیم و این یک بسته (bundle) است.

قراردادهای سنتی در مورد پیکربندی

با پیروی از ابزارهای بسته‌بندی قدیمی مانند Parcel، وب‌پک نسخه 4 نیز اکنون به همان ترتیب طراحی شده است.

همچنان که دیدید می‌توانیم بدون وجود هیچ گونه فایل پیکربندی آن را اجرا کنیم و احتمالاً متوجه شده‌اید که دو چیز تصور شده است:

  • فایل مدخل به صورت src/index.js است.
  • خروجی به صورت dist/main.js است.

علاوه بر این وقتی هشدار زیر را مشاهده می‌کنید:

The ‘mode’ option has not been set

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

اجرا با حالت‌های مختلف

در این بخش به بررسی وقایعی که در زمان اجرا با حالت‌های مختلف رخ می‌دهند خواهیم پرداخت. فایل dist/main.js را در زمانی که وب‌پک در حالت پروداکشن است باز کرده و دستور زیر را اجرا کنید:

yarn webpack --mode development

یک بار دیگر dist/main.js را بررسی کنید. این بار می‌بینید که نسخه non-uglified unoptimized بسته ایجاد شده است.

در آغاز کد زمان اجرای وب‌پک را خواهید دید که مسئول تفکیک ماژول (ایمپورت/اکسپورت) است و سپس کد پوششی را می‌بینید:

تفکیک ماژول در عمل

اکنون تابع ()hello را به فایل دیگری به نام hello.js می‌بریم:

و آن را در اندیس ایمپورت می‌کنیم:

اینک build جدید را بار دیگر اجرا کرده و نتیجه را روی بسته dist/main.js مورد بررسی قرار می‌دهیم.

راه‌اندازی اسکریپت‌های NPM

برای این که کارها ساده‌تر شوند، این دستورهای بیلد را روی فایل package.json می‌بریم و قطعه کد زیر را به آن اضافه می‌کنیم:

اکنون می‌توانیم build را صرفاً با دستور زیر اجرا کنیم:

yarn build

یا

yarn build:dev

اگر از NPM استفاده می‌کنید، باید از دستور npm run و سپس نام اسکریپت استفاده کنید.

احتمالاً وقتی بسته خود را بررسی کردید، متوجه شدید که همه کدهای ES6 همچنان در آن حضور دارند و این کار transpiling نبوده است.

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

چیزی که مسئول transpile کردن از ES6/ES7 به ES5 است، babelJs نام دارد.

سخن پایانی

در این بخش از یک دایرکتوری خالی آغاز و پروژه‌ای با وابستگی‌های NPM ایجاد کردیم و در چند گام معدود با استفاده از اسکریپت‌ها اقدام به ساخت بسته‌های وب‌پک نمودیم. با این حال این وضعیت همچنان یک راه‌اندازی خام محسوب می‌شود و ما باید مرورگرهایی بیشتر از آنچه از +ES2015 پشتیبانی می‌کنند را در نظر بگیریم. در بخش بعدی با روش انجام صحیح این کار آشنا خواهیم شد.

اگر این مطلب برای شما مفید بوده است، آموزش‌های زیر نیز به شما پیشنهاد می‌شوند:

منبع: فرادرس


آموزش برنامه نویسی سوئیفت (Swift): مفهوم ژنریک ها (Generics) –‌ بخش سیزدهم

در بخش قبلی این سری مقالات آموزش سوئیفت در مورد اسامی مستعار نام، مشاهده‌گرهای مشخصه و تفاوت self با Self صحبت کردیم. اما زمانی که به توضیح Self رسیدیم، مشاهده کردیم که ابتدا باید مفهوم ژنریک را در زبان سوئیفت روشن‌تر بکنیم. برای مطالعه بخش قبلی به لینک زیر مراجعه کنید:

از سوی دیگر صحبت کردن در مورد ژنریک‌ها بدون اشاره به Self کار دشواری است. پروتکل‌ها نیز می‌توانند از Self جهت گسترش کارکردهای خود بهره بگیرند. با این حال در اغلب مقالات می‌بینیم که یک‌راست به موضوع ژنریک‌ها یا پروتکل‌ها پرداخته شده و به‌یک‌باره هر سه موضوع موردبررسی قرار گرفته است.

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

ژنریک

احتمالاً تاکنون زمانی که مشغول کدنویسی سوئیفت بوده‌اید به این نکته فکر کرده‌اید که چه خوب می‌شد اگر مجبور نبودید برای اجرای کارهای تکراری، متدهای تکراری بنویسید. این همان جایی است که ژنریک‌ها به کار می‌آیند.

ژنریک‌ها امکان ایجاد تابع‌هایی را با قابلیت استفاده مجدد می‌دهند که می‌توانند در انواع متفاوتی استفاده شوند. تنها نکته این است که این نوع باید با کاری که قرار است اجرا شود متناسب باشد.

این بدان معنی است که می‌توان یک تابع منفرد نوشت که مقدار مجموع را محاسبه می‌کند و مهم نیست که مقادیر ارسالی به آن از نوع int ،double، یا float باشند. این تابع برای هر نوع Binarty Integr نیز کار می‌کند، اما در مورد انواع String کارکردی نخواهد داشت. در ادامه این تابع ژنریک را مورد بررسی بیشتری قرار می‌دهیم:

در این بخش نوعی ساختار جدید را شاهد هستیم. ابتدا <T> را می‌بینید. البته هر چیزی می‌تواند درون براکت‌ها باشد و عموماً از T برای نمایش نوع T استفاده می‌شود. همچنین در برخی موارد به صورت <Elements> می‌بینیم.

نکته دیگری که مشاهده می‌شود تغییر اعلان تابع است که عنوان آن به صورت زیر است:

در واقع این یک mutating func جدید است که add را فراخوانی می‌کند و از یک نوع ژنریک با نام <T> استفاده می‌کند و یک آرگومان منفرد newItem از نوع T می‌گیرد. Mutating به این معنی است که این تابع می‌تواند ساختار آرایه items را تغییر دهد.

این نوع از روی نوع لیستی که در ابتدا مقداردهی شده استنباط می‌شود. به محض این که کامپایلر این خط را ببیند:

همه رخدادهای <T> درون دامنه ساختار List ژنریک را به <Int> تغییر می‌دهد. از این رو آرایه Items و همه تابع‌ها انتظار نوع Int را خواهند داشت.

اگر یک List جدید با استفاده از <String> ساخته شود و در stringList ذخیره شود، این آرایه و تابع می‌تواند انتظار استفاده از یک نوع String را داشته باشد.

شما احتمالاً قبلاً این ساختار را دیده‌اید مثلاً وقتی که دیکشنری‌ها و آرایه‌ها را می‌ساختید از آن استفاده کرده‌اید. ما موارد زیادی از این اختصارها را ساخته‌ایم که به طور عمده روی استنباط نوع تکیه دارند؛ اما سوئیفت در پشت صحنه از ما پشتیبانی می‌کند و به صورت خودکار این نوع‌ها را برای ما گسترش می‌دهد.

آرایه‌های اعداد صحیح با استفاده از ساختار ()[Int] اعلان می‌شوند؛ اما سوئیفت آن را به صورت ()<Array<Int بسط می‌دهد.

دیکشنری‌های رشته‌ها با استفاده از ()[String: String] اعلان می‌شوند؛ اما همانند آرایه‌ها، سوئیفت آن را به صورت دیکشنری‌های ()<Dictionary<String: String درک می‌کند.

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

در ادامه متد دوم کد فوق را نیز بررسی می‌کنیم:

طرز کار این متد مانند متد add است و به جای T هر نوعی که برای ایجاد List استفاده شده باشد جایگزین می‌شود؛ اما این متد از Int به عنوان مقدار پارامتر استفاده می‌کند. دلیل این کار آن است که باید اندیس مبتنی بر Integer آرایه را داشته باشیم. علی غم این که محتوای آرایه ژنریک است؛ اما اندیس‌ها همچنان عدد صحیح هستند.

البته عنصری که در آن اندیس قرار دارد از نوع ژنریک تعریف‌شده ما خواهد بود؛ اما اگر کاربر هیچ چیزی به آرایه اضافه نکرده باشد چطور؟ ما باید این موقعیت که هیچ عنصری در آرایه نباشد را نیز مدیریت کنیم. بنابراین ابتدا مطمئن می‌شویم که یک آیتم را در لیست خود داریم. در ادامه می‌توانیم تلاش کنیم عنصر را دریافت کنیم. اما اگر نتوانیم آن عنصر را پیدا کنیم مقدار nil بازگشت می‌دهیم.

دقت کنید که در پاراگراف قبلی گفتیم «تلاش» می‌کنیم. این یک نکته منطقی است که اگر تمرین‌های قبلی را انجام داده باشید، متوجه سرنخ آن می‌شوید. تصور کنید ما سه آیتم به آرایه اضافه کرده‌ایم؛ اما گزاره زیر را اجرا می‌کنیم:

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

در این بخش یک سؤال دیگر را مطرح می‌کنیم. اگر یک لیست جدید با استفاده از دستور زیر ایجاد کنیم و مقادیر 3، 4 و 5 را به آن اضافه کنیم:

در این صورت اگر از دستور زیر استفاده کنیم، در زمان استفاده از print(value) دقیقاً چه متنی در کنسول نمایش می‌یابد؟

مفهوم ژنریک

سازگاری

شما می‌تواند کاری کنید که ژنریک‌ها با پروتکل‌های خاصی سازگاری داشته باشد. بدین ترتب آن‌ها تنها می‌توانند با نوع‌های خاصی وهله‌سازی شوند. برای نمونه زمانی که از پروتکل BinaryInteger استفاده می‌کنید، در واقع تعیین کرده‌اید که صرفاً اعداد صحیح با علامت (+/-) و بی علامت (+) می‌توانند در این متد ژنریک استفاده شوند.

امکان تعریف سازگاری با هر نوع وجود دارد؛ اما بهترین استفاده از آن با بهره‌گیری از رفتارهای پایه و پروتکل‌های پایه‌ای مانند Numeric ،Stridable ،Sequence و/یا Collection است.

این‌ها رفتارهای پایه‌ای هستند که می‌توان سازگاری با آن‌ها را تعریف کرد. در این صفحه (+) می‌توانید فهرست کامل را مشاهده کنید؛ اما در ادامه برخی از مواردی که استفاده متداولی دارند را نیز بررسی کرده‌ایم:

  • Equatable  – امکان بررسی این مسئله را می‌دهد که مقدار یک متغیر مقدار دیگر برابر است یا نه.
  • Comparable  – امکان مقایسه مقدار یک متغیر با متغیر دیگر را با استفاده از عملگرهای رابطه (بولی) مانند «بزرگ‌تر از»، «کمتر از»، «برابر» می‌دهد.
  • Hashable  – یک هش Integer ایجاد می‌کند که امکان استفاده از نوع، در یک مجموعه یا یک کلید دیکشنری را می‌دهد.

برخی اوقات یکی از این موارد برای نیازهای شما کافی است؛ اما در موقعیت‌های دیگری نیز ممکن است به بیش از یک مورد نیاز داشته باشید.

برای این که بهترین استفاده را از ژنریک‌ها داشته باشید باید پروتکل‌های مختلف توصیف‌شده در مستندات اپل را بررسی کنید. هر پروتکلی که استفاده می‌شود، صرفاً باید مطمئن شوید که با آن چه برایش استفاده می‌کنید سازگار است. این بدان معنی است که نباید فهرستی از سن افراد بسازید که از پروتکل FloatingPoint استفاده کند؛ مگر این که بخواهید از این تابع با اعداد اعشاری (float, double) استفاده کنید.

در ادامه به بررسی روش محدودسازی یک تابع ژنریک برای محدودسازی انواعی که می‌توانند استفاده شوند می‌پردازیم.

ما با استفاده از پروتکل Numeric به کامپایلر اعلام می‌کنیم، هر نوعی که عدد است را می‌تواند به جای T قبول کند. این امر به ما اجازه می‌دهد که از همان تابع برای انواع مختلفی استفاده کنیم.

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

ژنریک‌ها در پروتکل‌ها

این همان نقطه‌ای است که قبلاً به آن رسیدیم و به جای صحبت کردن در ژنریک‌ها در پروتکل‌ها؛ از آن عبور کرده و در مورد سازگاری و مثال‌هایی از شیوه تفکر لازم برای استفاده از ژنریک‌ها در پروتکل‌ها صحبت کردیم.

ژنریک‌ها در پروتکل‌ها چنان که انتظار می‌رود عمل می‌کنند؛ اما سازگاری فاصله زیادی با این وضعیت دارد. بدین ترتیب امکان صحبت بیشتر در مورد Self و همچنین خویشاوند نزدیک آن typealiase که associatedtype نامیده می‌شود فراهم می‌آید. ابتدا به توضیح دقیق‌تر Self می‌پردازیم.

Self یک الگوریتم جستجوی باینری است که شباهت زیادی به روش جستجو در یک دفترچه شماره تلفن یا دیکشنری دارد. فرض کنید به دنبال کلمه Swift در دیکشنری می‌گردید.

  1. ابتدا کتاب را باز می‌کنید و مثلاً به جایی روی حروف M می‌رسید.
  2. S بزرگ‌تر از M است و بنابراین نیمی از صفحه‌ها را به عقب بازمی‌گردیم تا به جایی مانند T می‌رسیم.
  3. S کوچک‌تر از T است و از این رو دوباره نیمی از صفحه‌های قبلی را به جلو ورق می‌زنیم تا به جایی بین حرف M و T برسیم.
  4. این کار را تا جایی ادامه می‌دهیم که به صفحه‌ای حاوی کلمه Swift برسیم.

در این مثال، یک پروتکل ارائه می‌کنیم که می‌تواند با هر نوعی کار کند به شرط این که آن نوع معادل Self باشد. Self در این چارچوب به این معنی است که می‌خواهیم مطمئن شویم مقداری که ارسال شده است نیز امکان سازگاری با پروتکل Ordered را دارد. ما یک سازه عددی داریم که از آن برای مقایسه با مقداری از همان نوع بهره می‌گیریم.

سپس اندیس بالا و پایین آرایه را به دست می‌آوریم (چون مرتب است) و در ادامه مقداری که به دنبالش هستیم را پیدا می‌کنیم. به این منظور ابتدا میانه آرایه را می‌یابیم. الگوریتم زیر این کار را انجام می‌دهد:

چون که:

0 + (10 - 0) / 2 = 5

در ادامه اگر به نقطه بالا برویم، به دلیل رند کردن به نتیجه زیر می‌رسیم:

 5 + (10–5) / 2 = 8

سپس [if sortedKeys[mid را بررسی کنیم، که مقدار 5 را به دست می‌دهد، (precedes(k قبل از مقداری است که به دنبالش می‌گردیم و از این رو مقدار زیر یا مقداری بالاتر از میانه را تنظیم می‌کنیم:

اگر مقدار مورد نظر در این بازه نباشد، مقدار hi = mid را تنظیم می‌کنیم، چون می‌خواهیم هر چیزی پایین تراز mid را بگردد. بدین ترتیب ادامه می‌دهیم تا زمانی که یک مقدار باقی بماند که lo است.

انواع Associated به منظور placeholder-هایی مشابه <T>؛ اما در اعلان پروتکل استفاده می‌شوند. مثال لیست فوق را با استفاده از پروتکل با یک نوع Associated بازنویسی می‌کنیم:

ابتدا associatedtype را داریم که آن را Item می‌نامیم، زیرا قرار است آیتم‌هایی را در یک آرایه ذخیره کنیم.

سپس آرایه items را با استفاده از یک getter که با { get } نمایش می‌یابد ایجاد می‌کنیم. این دستور به کامپایلر اعلام می‌کند که این آرایه باید فقط-خواندنی باشد. اگر بخواهیم این آرایه قابل خواندن و قابل نوشتن باشد می‌توانیم از { get set } استفاده کنیم. در این حالت تنها می‌خواهیم که کاربر متغیر را با استفاده از تابع add تعیین کند. در مقالات آینده در مورد getrer-ها و setter-ها بیشتر صحبت خواهیم کرد.

در این مورد نیز یک mutating func داریم، زیرا تابع خودش، یعنی آن struct که مالک متد را تغییر می‌دهد همچنین متدی برای دریافت آیتم‌ها ایجاد می‌کنیم که نکته جدیدی ندارد.

Struct با نام <List<T خارج از چارچوب پروتکل و تا حدود زیادی شبیه به وضعیت پیشین است. البته ما هیچ اکستنشنی برای پروتکل ایجاد نکرده‌ایم که بتواند در صورت نیاز کارکردهای پیش‌فرض را شامل شود. در برخی موارد زمانی که بین انواع مختلف سوئیچ می‌کنیم، ممکن است به کارکردهای متفاوتی نیاز داشته باشیم. برای نمونه زمانی که از یک <List<String استفاده می‌کنیم، ممکن است بخواهیم یک آرایه از کاراکترها و یا آرایه‌ای از رشته‌ها را الحاق کنیم. همین موضوع در مورد <List<Character نیز صدق می‌کند.

اینک با کسب این دانش جدید می‌دانیم که پروتکل‌های دیگری نیز وجود دارند که انواع رایجی مانند String ،Int ،Double و غیره از چیزی مانند Numeric ارث می‌برند و می‌توانیم یک اکستنشن از Numeric بسازیم که پروتکل را به خدمت بگیرد و کارکرد پیش‌فرضی که همه انواع Numeric را در برمی‌گیرد برای آن تعریف کنیم. در این حالت می‌توانیم یک چنین موردی را برای نوع‌های StringProtocol برای رشته‌ها بسازیم.

نکته آخری که باید در مورد ژنریک‌ها بگوییم در خصوص بند where است. بند where یک متمم برای پروتکل یا associatedtypes است.

بدین ترتیب myProtocol یک الزام روی هر چیزی که از این پروتکل استفاده کند، قرار می‌دهد و همچنین از Hashable استفاده می‌کند. به طور معمول سازگاری با پروتکل‌های کتابخانه استاندارد سوئیفت نیازمند پیاده‌سازی چند نوع، متغیر و/یا متد associated است که کمی اضافه‌کاری به نظر می‌رسد. در مورد Hashable باید کد زیر را به struct یا class خود اضافه کنید.

hashvalue کاملاً سرراست است؛ اما static func ==(lhs:rhs:) -> Bool برای ما کاملاً جدید است.

static به این معنی است که می‌توان آن را در هر کجا صرفاً با استفاده از ListA == ListB فراخوانی کرد و دو لیست را برای برابری فشرده می‌سازد. علامت == جایی است که برابرسازی اجرا می‌شود و یک روش استفاده از این عملگر محسوب می‌شود. lhs و rhs به معنی سمت چپ و سمت راست عملگر برابری هستند. ما یک مقدار بولی بازگشت می‌دهیم اما پیاده‌سازی این تابع خالی است. بنابراین باید پرسید چه اتفاقی در آن می‌افتد؟ منطقی که قصد داریم استفاده کنیم استفاده از بررسی برابری است. ما صرفاً یک پیاده‌سازی پیش‌فرض می‌سازیم که چارچوبی مانند زیر دارد:

اگر lhs برابر با rhs باشد، مقدار true و در غیر این صورت مقدار false بازگشت می‌یابد.

در بخش دوم که بند where با یک نوع associated استفاده شده است، در واقع قصد داریم کارکرد خود را در صورتی ارائه کنیم که شیئی که پروتکل را اختیار کرده است، الزام نوع مرتبط آن را نیز مورد استفاده قرار دهد. اگر شیء این کار را بکند، همه متدهایی که از نوع associated استفاده می‌کنند را به دست می‌آورد و در غیر این صورت چنین اتفاقی نخواهد افتاد. پیاده‌سازی آن به صورت زیر است:

به طور خلاصه تفاوت‌های بند where بین سطح پروتکل و سطح نوع associated چنین است که وقتی در سطح پروتکل استفاده می‌شود، به خدمت گرفتن شیء برای استفاده از پروتکل ارجاع یافته در بند where ضروری است. زمانی که بند where در سطح نوع associated استفاده می‌شود، شیء برای استفاده از پروتکل تعریف‌شده در بند where ضروری نیست؛ اما به همه متدهایی که در اختیار پروتکل هستند نیز دسترسی نخواهد داشت.

سخن پایانی

بدین ترتیب به پایان این مقاله با موضوع ژنریک‌ها می‌رسیم. ژنریک‌ها کارکردهای زیادی را با چند تغییر کوچک در کد در اختیار ما قرار می‌دهند. این موردی است که در زمان ایجاد پروتکل‌ها قطعاً باید در خاطر داشته باشیم و از خود بپرسیم آیا این پروتکل برای انواع مختلفی استفاده خواهد شد؟ یا این انواع چندان متفاوت هستند که باید به دنبال استفاده از بند where برای محدودسازی کارکردهای ارائه شده باشیم.

اغلب افراد تصور می‌کنند که در برنامه‌نویسی مهمترین نکته دست یافتن به منطق طرز کار اپلیکیشن‌ها است. با این که این منطق مهم است؛ اما نکته مهم‌تر از آن مسائلی مانند کامنت های کد، حفظ خوانایی کد، سازگاری در چینش فایل‌ها و ساختار کد و در نهایت روش مدیریت خطا در کد است.

همه افراد می‌توانند اپلیکیشنی بسازند که کار مفیدی انجام دهد؛ اما ممکن است همین اپلیکیشن زمانی که API سرور تغییر پیدا می‌کند و داده‌هایی خارج از آن چه مورد انتظار است دریافت می‌کند از کار بیفتد چون خطاها به درستی مدیریت نشده‌اند. به دلیل اهمیت موضوع مدیریت خطا در بخش بعدی قصد داریم به بررسی روش مدیریت خطا در iOS و macOS بپردازیم. تا آن زمان به تمرین کد کدنویسی ادامه بدهید و هر کجا که به مشکلی برخورد کردید به مستندات مراجعه کنید. اگر در اولین بار کدتان کار نکرد نباید نگران شوید زیرا یادگیری ژنریک ها به زمان نیاز دارد. در بخش بعدی این سری مقالات آموزشی، در مورد مدیریت خطا در سوئیفت صحبت خواهیم کرد.

برای مطالعه قسمت بعدی این مجموعه مطلب آموزشی روی لینک زیر کلیک کنید:

اگر این مطلب برای شما مفید بوده است، آموزش‌های زیر نیز به شما پیشنهاد می‌شوند:

منبع: فرادرس


فناوری های مختلف جاسازی (Embedding) در HTML — راهنمای کاربردی

شما با مطالعه بخش‌های پیشین این سری مقالات راهنمای کاربردی HTML اینک باید با طرز کار جاسازی یا Embedding موارد مختلف از قبیل صوت و ویدئو در صفحه‌های وب آشنا شده باشید. در این مرحله قصد داریم این موضوع را کمی بسط دهیم و به بررسی عناصری بپردازیم که امکان جاسازی طیف گسترده‌ای از انواع محتوا را در صفحه‌های وب فراهم می‌سازند. این موارد شامل فناوری‌های مختلف جاسازی از جمله عناصر <iframe> ،<embed> و <object> هستند. <iframe>-ها برای جاسازی صفحه‌های وب دیگر استفاده می‌شوند و دو مورد دیگر نیز برای جاسازی فایل‌های PDF ،SVG و حتی Flash مورد استفاده قرار می‌گیرند. Flash فناوری است که روزهای آخر عمر خود را سپری می‌کند، اما کماکان در جاهای مختلف به چشم می‌خورد. برای مطالعه بخش قبلی این سری مقالات به صفحه زیر مراجعه کنید:

پیش‌نیازها

  • سواد مقدماتی رایانه
  • نصب نرم‌افزارهای مقدماتی
  • دانش پایه از کار با فایل‌ها
  • آشنایی با مبانی HTML

موارد فوق از طریق مراجعه به مقالات قبلی این سری آموزشی قابل حصول هستند. هدف از این مقاله جاسازی آیتم‌های مختلف مانند فیلم‌های Flash و صفحه‌های وب دیگر، در صفحه‌های HTML با استفاده از عناصر <object> ،<embed> و <iframe> است.

تاریخچه مختصری از جاسازی

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

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

کمی بعدتر (در اواخر دهه 90 و ابتدای دهه 2000) فناوری‌های افزونه (plugin) مانند Java Applets و Flash بسیار محبوبیت یافتند. این فناوری‌ها به توسعه‌دهندگان وب امکان جاسازی محتوای کاملی از قبیل ویدئو یا انیمیشن در صفحه‌های وب ایجاد می‌کردند که از طریق HTML ممکن نبود. جاسازی این فناوری‌ها از طریق عناصری مانند <object> و همچنین عنصر کمتر استفاده شده <embed> صورت می‌گرفت و در زمان خود بسیار مفید بودند.

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

در نهایت عنصر <iframe> (به همراه روش‌های دیگر جاسازی مانند <canvas> ،<video> و غیره) پیدا شد. این عنصر روشی برای جاسازی کل یک سند وب را درون صفحه وب دیگر ارائه می‌کرد به طوری که آن سند وب یک عنصر <img> یا شبیه به آن است و به صورت معمولی مورد استفاده قرار می‌گیرد.

اینک که با تاریخچه موضوع آشنا شدیم، می‌توانیم در ادامه به بررسی روش استفاده از این فناوری‌ها بپردازیم.

یادگیری عملی: کاربردهای کلاسیک جاسازی

در این مقاله، قصد داریم مستقیماً به بخش یادگیری عملی وارد شویم تا بی‌درنگ ایده‌ای عملی از این که فناوری «جاسازی» (embedding) در چه مواردی مفید است به دست بیاوریم. در دنیای آنلاین اغلب افراد با وب‌سایت یوتیوب آشنا هستند؛ اما شاید بسیاری از آن‌ها با قابلیت‌های اشتراکی که این سرویس در اختیار کاربران قرار می‌دهد آشنا نباشند. در ادامه به بررسی روشی می‌پردازیم که یوتیوب امکان جاسازی ویدئوهای خود را در صفحه‌های وب دیگر با استفاده از <iframe> می‌دهد:

  1. ابتدا به وب‌سایت یوتیوب بروید و یک ویدئو را به‌دلخواه خود انتخاب کنید.
  2. زیر ویدئو یک دکمه share مشاهده می‌کنید. این دکمه را انتخاب کنید تا گزینه‌های اشتراک برای شما نمایش پیدا کنند.
  3. دکمه Embed را کلیک کنید تا یک کد <iframe> در اختیار شما قرار گیرد. این کد را کپی کنید.
  4. کد کپی شده را در کادر input زیر وارد کنید تا نتیجه را در بخش Output مشاهده کنید.

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

  1. ابتدا به وب‌سایت سرویس نقشه گوگل (+) بروید و نقشه‌ای که می‌خواهید را تنظیم کنید.
  2. روی منوی سه خط در سمت چپ-بالای صفحه کیک کنید.
  3. گزینه Share or embed map را انتخاب کنید.
  4. گزینه Emed map را کلیک کنید تا یک کد <iframe> در اختیار شما قرار گیرد. این کد را کپی کنید.
  5. کد کپی شده را در کادر فوق وارد کرده و نتیجه را در پنجره output ملاحظه کنید.

جزییات iframe-ها

همان طور که دیدید استفاده از iframe-ها آسان و بسیار مفید است. عناصر <iframe> طوری طراحی شده‌اند که امکان جاسازی سندهای وب دیگر را در سند جاری به دست می‌دهند. این وضعیت برای قرار دادن محتوای دیگر وب‌سایت‌ها در وب‌سایت خودتان بسیار مفید است. در این وضعیت شما کنترل مستقیمی روی این محتوا ندارید و شاید اصولاً این کنترل را نمی‌خواهید هم داشته باشید، چون چیزی از قبیل یک ویدئو آنلاین، سیستم درج توضیح مانند Disqus، نقشه‌های آنلاین، بنرهای تبلیغاتی و یا موارد مشابه است. مثال‌های قابل ویرایش آنلاین به نام بخش‌های «یادگیری عملی» که در طی این سری مقالات آموزشی مشاهده کردید، همگی با استفاده از iframe-ها پیاده‌سازی شده‌اند.

استفاده از عناصر <iframe> برخی دغدغه‌های امنیتی جدی را مطرح ساخته است که در ادامه بررسی خواهیم کرد؛ اما این بدان معنی نیست که نباید از آن‌ها در وب‌سایت‌ها استفاده شود؛ بلکه باید در زمان استفاده از آن آگاهی و دقت مضاعفی به کار بست. کد این عناصر را در ادامه کمی بیشتری مورد بررسی قرار می‌دهیم. فرض کن می‌خواهید لغت‌نامه MDN را به عنوان یکی از صفحه‌های وب در وب‌سایت خود بگنجانید. بدین منظور می‌توانید از کدی مانند زیر استفاده کنید:

این مثال شامل مبانی ضروری اولیه مورد نیاز برای استفاده از یک <iframe> است که در ادامه توضیح داده‌ایم:

Allowfullscreen: اگر این مقدار تعیین شده باشد، <iframe> می‌تواند با استفاده از Full Screen API در حالت تمام صفحه قرار گیرد (که البته توضیح آن فراتر از حیطه این مقاله است).

Frameborder: اگر برابر با 1 تعیین شده باشد، به مرورگر اعلام می‌شود که یک حاشیه بین این فریم و دیگر فریم‌ها ترسیم کند که رفتار پیش‌فرض محسوب می‌شود. اگر مقدار 0 تعیین شده باشد این حاشیه حذف می‌شود. استفاده از این پارامتر دیگر توصیه نمی‌شود؛ چون همین تأثیر را به روشی بهتر می‌توان با استفاده از border: none در CSS به دست آورد.

src: این خصوصیت همانند عناصر <video> و <img> شامل یک مسیر است که به URL سندی که قرار است جاسازی شود اشاره می‌کند.

width و height: این خصوصیت‌ها میزان عرض و ارتفاع فریم را تعیین می‌کنند.

Fallback content: به همان روش مشابه عناصری مانند <video> با استفاده از این خصوصیت می‌توان محتوای جایگزین را بین تگ‌های ابتدایی و پایانی <iframe></iframe> تعیین کرد. این محتوا در مواردی نمایش می‌یابد که مرورگر از عنصر <iframe> پشتیبانی نکند. در این حالت یک لینک به صفحه جایگزین تعیین می‌کنیم. البته این روزها مشاهده مرورگری که از iframe پشتیبانی نکند، بسیار بعید است.

Sandbox: این خصوصیت که روی مرورگرهای مدرن‌تر به روشی نسبتاً متفاوت از باقی ویژگی‌های <iframe> کار می‌کند نیازمند تنظیمات امنیتی با درجه بالایی است و در بخش بعدی در مورد آن بیشتر صحبت خواهیم کرد.

نکته: به منظور افزایش سرعت بهتر است خصوصیت src مربوط به iframe را پس از این که محتوای اصلی صفحه بارگذاری شد توسط جاوا اسکریپت تعیین کنیم. بدین ترتیب صفحه زودتر در دسترس کاربر قرار می‌گیرد و زمان بارگذاری رسمی صفحه کاهش می‌یابد که معیار مهمی در مبحث سئو محسوب می‌شود.

دغدغه‌های امنیتی

در بخش فوق به دغدغه‌های امنیتی اشاره کردیم. اینک نوبت آن رسیده که جزییات بیشتری را مورد بررسی قرار دهیم. ما انتظار نداریم که شما همه محتوای زیر را در نخستین بار مطالعه به طور کامل درک کنید؛ بلکه می‌خواهیم صرفاً شما را از وجود این دغدغه آگاه کرده و ارجاعی بدهیم که وقتی تجربه بیشتری در استفاده از iframe-ها یافتید مجدداً به این مطلب مراجعه کرده و آن را با دقت بیشتری مطالعه کنید. ضمناً نیازی نیست که در مورد استفاده از iframe-ها دچار تشویش شوید، تنها چیزی که باید بدانید این است که همواره باید مراقب باشید.

سازندگان مرورگرها و توسعه‌دهندگان وب با این واقعیت تلخ مواجه شده‌اند که iframe-ها هدف مشترکی برای افراد بد در وب محسوب می‌شوند. این افراد به طور معمول «هکر» (Hacker) نامیده می‌شوند؛ اما اصطلاح دقیق «کرکر» (Cracker) است. کرکرها تلاش می‌کنند تا صفحه وب شما را به طرز نامناسبی تغییر دهد یا افراد را فریب بدهند تا چیزی را که می‌خواهند مانند اطلاعات حساسی چون نام کاربری و رمز عبور را به دست آورند. به همین دلیل مهندسان و توسعه‌دهندگان مرورگرها، سازوکارهای امنیتی مختلفی برای امن‌تر ساختن iframe-ها ارائه کرده‌اند و برخی رویه‌های مناسب نیز وجود دارند که باید مورد توجه قرار گیرند. برخی از این موارد در ادامه معرفی شده‌اند.

نکته: «کلیک ربایی» (Clickjacking) نوعی از حمله‌های رایج iframe است که در آن هکرها یک iframe ناپیدا را در سند شما جاسازی می‌کنند و یا این که سند شما را درون وب‌سایت خرابکارانه خودشان جاسازی می‌کنند و بدین ترتیب تعامل‌های کاربران را به دست می‌آورند. این یک روش رایج برای گمراه کردن کاربران یا سرقت داده‌های حساس آن‌ها محسوب می‌شود.

به عنوان اولین مثال تلاش کنید نمونه ارائه شده قبلی که کد آن را در ادامه می‌بینید در مرورگر خود بارگذاری کنید:

در این زمان در عمل چیزی روی صفحه مشاهده نمی‌شود و اگر به کنسول مرورگر در بخش ابزارهای توسعه‌دهنده مرورگر (با کلیدهای میانبر Ctrl+Shift+I) نگاه کنید، پیامی می‌بینید که دلیل این وضعیت را به شما اعلام می‌کند. در مرورگر فایرفاکس اعلام می‌شود که بارگذاری به دلیل این که امکان استفاده از iframe وجود ندارد متوقف شده است:

X-Frame-Options: https://developer.mozilla.org/en-US/docs/Glossary does not permit framing

دلیل این امر آن است که توسعه‌دهندگانی که MDN را ساخته‌اند یک تنظیمات روی سرور قرار داده‌اند که باعث می‌شود صفحه‌های وب‌سایتشان امکان جاسازی درون iframe-ها را نداشته باشد. این کار مفیدی محسوب می‌شود، زیرا این که کل یک صفحه MDN در صفحه‌های دیگر جاسازی شود، هیچ معنی ندارد به جز این که فردی که این کار را می‌کند، می‌خواهد ادعا کند صاحب وب‌سایت MDN است و می‌خواهد داده‌های کاربران را از طریق کلیک ربایی به سرقت ببرد. هر دوی این‌ها وضعیت نامناسبی محسوب می‌شوند. به علاوه این که اگر همه افراد شروع به انجام این کار بکنند همه پهنای باند خود را بر دوش بنیاد Mozilla می‌اندازند که نوعی سوءاستفاده محسوب می‌شود.

تنها در موارد ضروری از embed استفاده کنید

برخی اوقات جاسازی محتوای ثالث مانند ویدئوهای یوتیوب و نقشه‌ها مفید است؛ اما در صورتی که استفاده از این نوع جاسازی‌ها را به موارد صرفاً ضروری محدود کنید از دردسرهای زیادی جلوگیری خواهید کرد. یک قاعده سرانگشتی مناسب برای امنیت وب این است که: «شما هرگز نمی‌توانید بیش از حد هوشیار باشد. اگر خودتان چیزی ساخته‌اید، آن را دوباره بررسی کنید. اگر کس دیگری آن را ساخته است، پیش‌فرضتان این باشد که خطرناک است؛ مگر این که خلافش ثابت شود.»

علاوه بر امنیت باید از مشکلات مالکیت معنوی نیز آگاه باشید. اغلب محتوای آنلاین و آفلاین دارای کپی‌رایت هستند. حتی محتوایی که ممکن است فکرش را نکنید (برای نمونه اغلب تصاویر روی Wikimedia Commons) دارای کپی‌رایت هستند. هرگز محتوایی را روی صفحه وب خود قرار ندهید؛ مگر این که مالک آن باشید یا مالکان آن به شما مجوز مکتوب و بی‌ابهام داده باشند. جریمه‌های نقض قانون کپی‌رایت بسیار سنگین هستند و در این مورد نیز نمی‌توانید صرفاً به هوشیاری خود اکتفا کنید.

اگر یک محتوا دارای لایسنس است؛ باید از شرایط لایسنس پیروی کنید. برای نمونه محتوای MDN دارای لایسنس CC-BY-SA است. این بدان معنی است که شما باید زمانی که از این وب‌سایت نقل قول می‌کنید حتی در صورتی که تغییرات زیادی در آن ایجاد کرده باشید، به این وب‌سایت «ارجاع» (Credit) بدهید.

استفاده از HTTPS

HTTPS نسخه رمزنگاری‌شده HTTP است. شما باید وب‌سایت خود را هر زمان که ممکن است از طریق HTTPS عرضه کنید، چون:

  1. HTTPS احتمال این که محتوای ریموت در زمان انتقال جعل شود را کاهش می‌دهد.
  2. HTTPS از دسترسی محتوای جاسازی‌شده به محتوای سند اصلی و برعکس جلوگیری می‌کند.

استفاده از HTTPS نیازمند یک گواهی امنیتی است که ممکن است گران‌قیمت باشد (البته وب‌سایت Let’s Encrypt کار را آسان‌تر ساخته است.) اگر امکان تهیه یک گواهی امنیتی را ندارید می‌توانید سند والد خود را روی HTTP عرضه کنید. با این وجود به دلیل مزیت دوم HTTPS که در بخش فوق اشاره کردیم، مهم نیست که چه هزینه‌ای می‌کنید، چون هرگز نباید محتوای شخص ثالث را با استفاده از HTTP عرضه کنید. در چنین وضعیتی در بهتری حالت مرورگر کاربران یک هشدار جدی به آن‌ها می‌دهد. همه شرکت‌های مشهور که محتوای خود را از طریق یک iframe در اختیار شما برای جاسازی می‌دهند آن را از طریق HTTPS عرضه می‌کنند. برای اطمینان در زمان جاسازی محتوایی از نقشه‌های گوگل یا یوتیوب به URL درون خصوصیت src مربوط به iframe نگاه کنید.

نکته: «صفحه‌های گیت‌هاب» (Github Pages) امکان عرضه محتوا را به صورت پیش‌فرض از طریق HTTPS فراهم ساخته‌اند و از این رو برای میزبانی محتوا مفید هستند. اگر از میزبان متفاوتی استفاده می‌کنید و در این خصوص مطمئن نیستید، در مورد آن از ارائه‌دهنده سرویس میزبانی سؤال کنید.

همواره از خصوصیت sandbox استفاده کنید

طبیعی است که شما می‌خواهید حمله‌کنندگان در زمانی که می‌خواهند حملاتی را روی وب‌سایت شما اجرا می‌کنند، کمترین قدرت ممکن را داشته باشند، از این رو باید تنها مجوزهای واقعاً ضروری را برای اجرای کارهای خود به محتوای جاسازی‌شده بدهید. البته این مسئله در خصوص خود محتوای اصلی نیز صدق می‌کند. sandbox یک کانتینر برای کد است که در آن می‌تواند به صورت مناسبی اجرا یا تست شود؛ اما امکان ایجاد آسیب (تصادفی یا خرابکارانه) به بقیه کد را نمی‌دهد.

محتوای خارج از sandbox می‌تواند کارهای بسیار مختلفی مانند اجرای کدهای جاوا اسکریپت، ارائه فرم، باز کردن پنجره‌های پاپ‌آپ و غیره را اجرا کند. شما به صورت پیش‌فرض باید همانند مثال قبلی‌مان، همه محدودیت‌های جاوا اسکریپت را با استفاده از خصوصیت sandbox بدون هیچ پارامتری اعمال کنید.

اگر موردی واقعاً ضروری باشد می‌توانید مجوزها را یک‌به‌یک (داخل مقدار خصوصیت “”=sandbox) اضافه کنید. برای مشاهده همه گزینه‌ها به مدخل sandbox (+) مراجعه کنید. یک نکته مهم این است که هرگز نباید هر دو خصوصیت allow-scripts و allow-same-origin را به sandbox اضافه کنید، چون در این حالت محتوای جاسازی‌شده آن سیاست‌های امنیتی اصلی را که سایت را قادر به متوقف کردن اسکریپت‌ها می‌کند را دور می‌زند و از جاوا اسکریپت برای خاموش کردن وضعیت sandbox استفاده می‌کند.

نکته: استفاده از sandbox در صورتی که حمله‌کنندگان بتوانند افراد را برای بازدید مستقیم از محتوای وب‌سایت خرابکار فریب بدهند (خارج از iframe) هیچ فایده‌ای نخواهد داشت. اگر هر گونه احتمال می‌دهید که محتوایی خرابکارانه باشد، بهتر است که آن را از دامنه‌ای به جز دامنه سایت خود ارائه کنید.

پیکربندی دایرکتیوهای CSP

CSP اختصاری برای «سیاست امنیت محتوا» (content security policy) است و یک مجموعه از هدرهای HTTP (متادیتا به همراه صفحه‌های وب که از وب‌سرور عرضه می‌شوند) عرضه می‌کند که برای بهبود امنیت سند HTML طراحی شده‌اند. زمانی که از بحث امن سازی iframe-ها صحبت می‌کنیم باید بدانید که امکان پیکربندی سرور برای ارسال یک هدر X-Frame-Options وجود دارد. این کار موجب می‌شود که وب‌سایت‌های دیگر نتوانند محتوای شما را در صفحه‌های وب خود جاسازی کنند. این دقیقاً همان کاری است که توسعه‌دهندگان MDN انجام داده‌اند و قبلاً توضیح دادیم.

عناصر <embed> و <object>

عناصر <embed> و <object>کارکردی متفاوت از <iframe> دارند. این عناصر ابزارهای جاسازی با مقاصد عمومی برای جاسازی چند نوع مختلف از محتوای خارجی هستند که شامل فناوری‌های افزونه مانند اپلت‌های جاوا و Flash، PDF و حتی محتوایی مانند ویدئو و تصاویر SVG می‌شود.

نکته: در این چارچوب یک «افزونه» (plugin) اشاره به نرم‌افزاری دارد که امکان دسترسی به محتوایی را می‌دهد که مرورگر نمی‌تواند به صورت native به آن دسترسی داشته باشد.

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

اگر در هر صورت تصور کردید که نیاز به جاسازی یک محتوای افزونه دارید، این نوعی از اطلاعات است که دست‌کم به آن‌ها نیاز خواهید داشت:

<embed><object>
URL محتوای جاسازی‌شدهsrcdata
نوع داده صحیح برای محتوای جاسازی‌شدهtypetype
عرض و ارتفاع کادری که از سوی افزونه کنترل می‌شود.height
width
height
width
نام‌ها و مقادیر برای ارائه به پارامترهای افزونهخصوصیت‌های موجود با آن نام و مقادیرعناصر <param> با تگ منفرد درون <object>
محتوای مستقل HTML به عنوان Fallback برای زمانی که منابع موجود نیستند.پشتیبانی نمی‌شود.پس از عناصر <param> درون <object> قرار می‌گیرد.

نکته: <object> به یک خصوصیت به نام data، یک خصوصیت type و یا هر دو نیاز دارد. اگر هر دوی این خصوصیت‌ها استفاده می‌کنید احتمالاً به یک خصوصیت typemustmatch هم نیاز خواهید داشت که در زمان نگارش این مقاله صرفاً در فایرفاکس پیاده‌سازی شده است. typemustmatch موجب می‌شود که فایل جاسازی‌شده اجرا نشود؛ مگر این که خصوصیت type نوع رسانه صحیح را ارائه کند. بدین ترتیب typemustmatch می‌تواند در مواردی که محتوای جاسازی‌شده را از منبع متفاوتی استفاده می‌کنید، مزیت‌های امنیتی زیادی داشته باشد. بدین ترتیب حمله‌کنندگان امکان اجرای اسکریپت‌های دلخواه را از طریق افزونه نمی‌یابند.

در ادامه مثالی از عنصر <embed> برای جاسازی یک فیلم Flash را می‌بینید:

همان طور که می‌بینید این وضعیت کاملاً خطرناکی است، زیرا محتوای HTML تولیدشده از سوی ابزار Adobe Flash از این هم بدتر است و از عنصر <object> با یک عنصر <embed> جاسازی‌شده داخل آن برای پوشش همه پایه‌ها استفاده می‌کند. Flash حتی به صورت موفقی برای محتوای fallback به جای ویدئوی HTML5 نیز استفاده شده است؛ اما این وضعیت امروز دیگر چندان ضروری تلقی نمی‌شود.

اینک مثالی از <object> را بررسی می‌کنیم که یک PDF را در یک صفحه جاسازی می‌کند:

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

معایب افزونه‌ها

زمانی بود که افزونه‌ها جزئی جداناپذیر از وب محسوب می‌شدند. آیا زمانی را به خاطر می‌آورید که برای تماشای یک ویدئوی آنلاین مجبور به نصب Adobe Flash Player بوده‌اید؟ در این زمان به طور مرتب هشدارهایی در مورد به‌روزرسانی Flash Player و Java Runtime Environment دریافت می‌کردید. فناوری‌های وب اینک بسیار رشد یافته‌اند و آن روزها سپری شده‌اند. در اغلب موارد ارائه محتوایی که وابسته به این افزونه‌ها است دیگر ضرورتی ندارد و باید شروع به استفاده از فناوری‌های وب جایگزین بکنیم و این کار چندین مزیت دارد که در ادامه ارائه شده است:

  • دسترسی افراد مختلف به وب‌سایت شما افزایش می‌یابد: هر کس یک مرورگر دارد؛ اما افزونه‌ها امروزه به‌خصوص در میان کاربران موبایل بسیار نادر هستند. از آنجا که وب بدون وجود افزونه‌ها نیز تا حدود زیادی قابل استفاده است، افراد ترجیح می‌دهند که به وب‌سایت‌های رقیب که نیازی به افزونه ندارند مراجعه کنند.
  • از شر افزونه‌ها رها می‌شوید: با کنار گذاشتن افزونه‌ها، مشکلات دسترس‌پذیری مختلفی که از Flash و دیگر افزونه ناشی می‌شد نیز رفع می‌شوند.
  • از مخاطرات امنیتی اضافی دور می‌مانید: Adobe Flash حتی پس از وصله‌های بسیاری که دریافت کرد، یک نرم‌افزار کاملاً ناامن بود. در سال 2015 «الکس استاموس» (Alex Stamos) مدیر ارشد امنیتی فیسبوک از Adobe درخواست کرد که پروژه Flash را متوقف کند.

اینک سؤال این است که چه باید کرد؟ اگر به تعامل‌پذیری نیاز دارید، HTML و جاوا اسکریپت می‌توانند هر آن چه را که ممکن بود از اپلت‌های جاوا یا فناوری منسوخ ActiveX/BHO انتظار داشته باشید را به سهولت در اختیار شما قرار دهند. به جای تکیه بر روی Adobe Flash می‌توانید از ویدئوهای HTML5 برای نیازهای رسانه‌ای، از SVG برای گرافیک‌های برداری و از Canvas برای تصاویر پیچیده و انیمیشن‌ها استفاده کنید. «پیتر الست» (Peter Elst) سال‌ها قبل اشاره کرده است که Adobe Flash برای هر کاری به جز بازی‌سازی تخصصی و اپلیکیشن‌های تجاری که در نظر بگیرید، به ندرت ابزار مناسبی محسوب می‌شود. در مورد ActiveX هم باید گفت حتی مرورگر Edge مایکروسافت هم دیگر از آن پشتیبانی نمی‌کند.

جمع‌بندی

موضوع «جاسازی» (Embedding) محتوای دیگر در سندهای وب ممکن است به سرعت به موضوع پیچیده‌ای تبدیل شود. از این رو در این مقاله تلاش کردیم آن را به یک روش ساده و آشنا معرفی کنیم تا هم به راحتی درک شود و هم برخی از ویژگی‌های پیشرفته فناوری‌های درگیر در آن نیز تفهیم شوند. در آغاز شما به ندرت از جاسازی استفاده می‌کنید؛ مگر این که بخواهید یک نقشه یا ویدئویی را روی صفحه وب خود قرار دهید. با این وجود، زمانی که تجربه بیشتری در زمینه توسعه وب کسب کنید، احتمالاً کاربردهای بیشتری برای آن خواهید یافت.

فناوری‌های زیاد دیگری به جز آن‌هایی که در این مقاله معرفی کردیم نیز وجود دارند که برای جاسازی محتوای خارجی در صفحه‌های وب استفاده می‌شوند. برخی از آن‌ها را مانند <video> ،<audio> ،<img> در مقالات قبلی این سری آموزشی معرفی کردیم، اما موارد دیگری مانند <canvas> برای گرافیک‌های 2 بعدی و 3 بعدی تولیدشده از سوی جاوا اسکریپت و <svg> برای جاسازی گرافیک‌های برداری وجود دارند که باید آن‌ها را نیز بیاموزید. در بخش بعدی این سری مقالات آموزشی به بررسی SVG خواهیم پرداخت.

برای مطالعه قسمت بعدی این مجموعه مطلب آموزشی می‌توانید روی لینک زیر کلیک کنید: