يمكنك تصميم تطبيقات متوافقة مع المتصفّحات الحديثة وإجراء تحسينات تدريجية عليها كما في عام 2003.
في آذار (مارس) 2003، قام فينك أذهل ستيف شامبون عالم تصميم الويب بمفهوم التحسين التدريجي استراتيجية لتصميم الويب تؤكد على تحميل محتوى صفحة الويب الأساسية أولاً، ثم يضيف تدريجيًا المزيد من التفاصيل وطبقات عرض تقديمي وميزات أكثر صرامة من الناحية التقنية بالإضافة إلى المحتوى. بينما كان التحسين التدريجي في عام 2003 يدور حول استخدام التصاميم الحديثة ميزات CSS وJavaScript غير المزعج، وحتى رسومات موجّهة يمكن تغيير حجمها. يتعلق التحسين التدريجي في عام 2020 وما بعده باستخدام أحدث إصدار من المتصفّح.
JavaScript حديث
بالحديث عن JavaScript، وضع توافق المتصفّح مع أحدث إصدار من JavaScript الأساسي ES 2015
الرائعة أمرًا رائعًا.
يتضمّن المعيار الجديد الوعود والوحدات والفئات والقيم الحرفية للنماذج والدوال السهمية وlet
وconst
المعلَمات التلقائية والمولّدات وعملية التدمير والاستراحة والانتشار وMap
/Set
WeakMap
/WeakSet
، وغير ذلك الكثير.
جميعها متاحة.
وهي ميزة غير متزامنة، وهي إحدى ميزات الإصدار ES 2017، وإحدى الوظائف المفضّلة لديّ شخصيًا،
يمكن استخدامها
في جميع المتصفحات الرئيسية.
تتيح الكلمتان الرئيسيتان async
وawait
سلوكًا غير متزامن وقائم على الوعود
أن تتم كتابتها بأسلوب أوضح، مع تجنب الحاجة إلى تهيئة سلاسل الوعود بشكل صريح.
وحتى إضافات اللغات الحديثة للغاية في إسبانيا 2020 مثل السلاسل الاختيارية انحدار الفراغ الوصول إلى الدعم بسرعة كبيرة. يمكنك الاطّلاع على نموذج التعليمات البرمجية أدناه. عندما يتعلق الأمر بميزات JavaScript الأساسية، لا يمكن أن يكون العشب أكثر خضرة منه هو اليوم.
const adventurer = {
name: 'Alice',
cat: {
name: 'Dinah',
},
};
console.log(adventurer.dog?.name);
// Expected output: undefined
console.log(0 ?? 42);
// Expected output: 0
نموذج التطبيق: Fugu Greetings
في هذه المقالة، أعمل باستخدام تطبيق ويب تقدّمي (PWA) بسيط يسمى تحية "فوغو" (GitHub). يمثّل اسم هذا التطبيق تلميحًا لمشروع Project Fugu 🐡، فهو محاولة لتقديم كل ما هو جديد على الويب. إمكانيات تطبيقات Android/iOS/الكمبيوتر المكتبي. يمكنك قراءة المزيد عن المشروع في الصفحة المقصودة.
Fugu Greetings هو تطبيق رسم يتيح لك إنشاء بطاقات تهنئة افتراضية وإرسال إلى أحبائك. إنه يوضح مفاهيم PWA. من المهم موثوقة وتفعيل وضع "عدم الاتصال بالإنترنت" بالكامل، لذلك حتى إذا لم لديك شبكة، يمكنك الاستمرار في استخدامها. إنّه أيضًا قابل للتثبيت على الشاشة الرئيسية للجهاز ويتكامل بسلاسة مع نظام التشغيل كتطبيق مستقل.
التحسين التدريجي
وبعد الانتهاء من هذا العمل، حان الوقت للحديث عن التحسين التدريجي. تعريف مسرد مصطلحات مستندات الويب MDN المفهوم على النحو التالي:
التحسين التدريجي هو فلسفة تصميم توفر أساسًا من المحتوى والوظائف لأكبر عدد ممكن من المستخدمين، مع تقديم أفضل تجربة ممكنة للمستخدمين فقط من خلال أحدث إصدار في المتصفحات التي يمكنها تشغيل جميع الرموز المطلوبة.
اكتشاف الميزات يُستخدم عمومًا لتحديد ما إذا كان بإمكان المتصفحات التعامل مع وظائف أكثر حداثة، بينما يتم استخدام الرموز polyfill لإضافة الميزات الناقصة باستخدام JavaScript.
[…]
التحسين التدريجي هو أسلوب مفيد يتيح لمطوّري الويب التركيز على تطوير أفضل مواقع الويب الممكنة أثناء جعل هذه المواقع تعمل على عدة برامج وكيل مستخدم غير معروفة. التقليص السلس مرتبط ولكن ليس هو الشيء نفسه وغالبًا ما يُنظر إليه على أنه يسير في الاتجاه المعاكس إلى التحسين التدريجي. في الواقع، كلا النهجين صالحان ويمكن أن يتكاملا في كثير من الأحيان مع بعضهما البعض.
المساهمون في MDN
قد يكون بدء كل بطاقة تهنئة من الصفر أمرًا مرهقًا حقًا.
إذًا لماذا لا تتوفّر ميزة تسمح للمستخدمين باستيراد صورة والبدء من هناك؟
باستخدام نهج تقليدي، كنت قد استخدمت
<input type=file>
العنصر لتحقيق ذلك.
أولاً، عليك إنشاء العنصر وضبط type
على 'file'
وإضافة أنواع MIME إلى السمة accept
.
ثم "النقر" آليًا والاستماع إلى التغييرات.
عند تحديد صورة، يتم استيرادها مباشرةً إلى اللوحة.
const importImage = async () => {
return new Promise((resolve) => {
const input = document.createElement('input');
input.type = 'file';
input.accept = 'image/*';
input.addEventListener('change', () => {
resolve(input.files[0]);
});
input.click();
});
};
عند توفير ميزة الاستيراد، يجب أن تتوفّر الميزة تصدير على الأرجح.
حتى يتمكن المستخدمون من حفظ بطاقات التهنئة محليًا.
الطريقة التقليدية لحفظ الملفات هي إنشاء رابط ارتساء
مع download
مع عنوان URL لملف blob باعتباره href
.
يمكنك أيضًا النقر آليًا لبدء التنزيل،
ولمنع تسرُّب الذاكرة، نأمل ألا ننسى إبطال عنوان URL لكائن الكائن الثنائي الكبير (blob).
const exportImage = async (blob) => {
const a = document.createElement('a');
a.download = 'fugu-greeting.png';
a.href = URL.createObjectURL(blob);
a.addEventListener('click', (e) => {
setTimeout(() => URL.revokeObjectURL(a.href), 30 * 1000);
});
a.click();
};
لكن انتظر دقيقة. عقليًا، لم "تنزّل" بطاقة تهنئة، لديك "تم الحفظ" بها. بدلاً من عرض "حفظ" مربع حوار يتيح لك اختيار مكان وضع الملف نزَّل المتصفِّح بطاقة التهنئة مباشرةً بدون تفاعل المستخدم ووضعها مباشرة في مجلد التنزيلات. هذا ليس رائعًا.
ماذا لو كانت هناك طريقة أفضل؟ ماذا لو كان بإمكانك فتح ملف محلي وتعديله ثم حفظ التعديلات، إما إلى ملف جديد أو إلى الملف الأصلي الذي فتحته في البداية؟ اتضح أن هناك. File System Access API: فتح الملفات وإنشائها بالإضافة إلى تعديلها وحفظها .
إذًا، كيف يمكنني اكتشاف واجهة برمجة تطبيقات؟
تعرض واجهة برمجة التطبيقات File System Access API طريقة جديدة للسمة window.chooseFileSystemEntries()
.
وبالتالي، أحتاج إلى تحميل وحدات استيراد وتصدير مختلفة بشكل مشروط حسب ما إذا كانت هذه الطريقة متاحة أم لا. لقد أوضحنا كيفية القيام بذلك أدناه.
const loadImportAndExport = () => {
if ('chooseFileSystemEntries' in window) {
Promise.all([
import('./import_image.mjs'),
import('./export_image.mjs'),
]);
} else {
Promise.all([
import('./import_image_legacy.mjs'),
import('./export_image_legacy.mjs'),
]);
}
};
ولكن قبل التعمق في تفاصيل واجهة برمجة تطبيقات File System Access API، اسمحوا لي أن أبرز بسرعة نمط التحسين التدريجي هنا. في المتصفحات التي لا تتيح حاليًا واجهة برمجة التطبيقات File System Access API، أحمّل النصوص البرمجية القديمة. يمكنك الاطلاع على علامتَي تبويب الشبكة في Firefox وSafari أدناه.
ولكن في Chrome، وهو متصفح متوافق مع واجهة برمجة التطبيقات، لن يتم تحميل سوى النصوص البرمجية الجديدة.
وقد تم تحقيق ذلك بشكل أنيق بفضل
الإصدار import()
الديناميكي الذي تستخدمه جميع المتصفحات الحديثة
الدعم.
كما ذكرت سابقًا، العشب أخضر اللون في هذه الأيام.
واجهة برمجة التطبيقات File System Access API
وبعد أن عالجنا هذا الأمر، حان الوقت للاطّلاع على طريقة التنفيذ الفعلية استنادًا إلى واجهة برمجة التطبيقات File System Access API.
لاستيراد صورة، أتصل بـ window.chooseFileSystemEntries()
.
وأمرره إلى السمة accepts
حيث أقول "أريد ملفات صور".
يمكن استخدام امتدادات الملفات وأنواع MIME.
ينتج عن ذلك مؤشر ملف يمكنني من خلاله الحصول على الملف الفعلي من خلال استدعاء getFile()
.
const importImage = async () => {
try {
const handle = await window.chooseFileSystemEntries({
accepts: [
{
description: 'Image files',
mimeTypes: ['image/*'],
extensions: ['jpg', 'jpeg', 'png', 'webp', 'svg'],
},
],
});
return handle.getFile();
} catch (err) {
console.error(err.name, err.message);
}
};
عملية تصدير الصورة هي نفسها تقريبًا، ولكن هذه المرة
أحتاج إلى تمرير معلمة النوع 'save-file'
إلى الطريقة chooseFileSystemEntries()
.
من هنا يظهر لي مربع حوار لحفظ الملفات.
عندما يكون الملف مفتوحًا، لم يكن هذا الإجراء ضروريًا لأنّ 'open-file'
هو الإعداد التلقائي.
تم ضبط المعلَمة accepts
بشكل مشابه سابقًا، ولكن هذه المرة تقتصر على صور PNG فقط.
مرة أخرى، أعود إلى مؤشر الملف، ولكن بدلاً من الحصول على الملف،
هذه المرة أنشئ بثًا قابلاً للكتابة عن طريق الاتصال بـ createWritable()
.
بعد ذلك، أكتب الكائن الثنائي الكبير، وهو صورة بطاقة التهنئة، إلى الملف.
أخيرًا، أغلق ساحة المشاركات القابلة للكتابة.
دائمًا ما يفشل كل شيء: قد تكون مساحة القرص غير متاحة،
قد يكون هناك خطأ في الكتابة أو القراءة، أو ربما يلغي المستخدم مربع حوار الملف.
هذا هو السبب في أنني دائمًا ألتزم المكالمات بجملة try...catch
.
const exportImage = async (blob) => {
try {
const handle = await window.chooseFileSystemEntries({
type: 'save-file',
accepts: [
{
description: 'Image file',
extensions: ['png'],
mimeTypes: ['image/png'],
},
],
});
const writable = await handle.createWritable();
await writable.write(blob);
await writable.close();
} catch (err) {
console.error(err.name, err.message);
}
};
باستخدام التحسين التدريجي مع واجهة برمجة التطبيقات File System Access API، يمكنني فتح ملف كما كان من قبل. يتم رسم الملف المستورَد مباشرةً على اللوحة. يمكنني إجراء تعديلاتي وحفظها في نهاية المطاف باستخدام مربع حوار حفظ حقيقي حيث يمكنني اختيار اسم الملف وموقع تخزينه. ويكون الملف جاهزًا الآن لحفظه للأبد.
واجهتا برمجة التطبيقات Web Share وWeb Share Target
بصرف النظر عن الاحتفاظ بها للأبد، ربما أرغب في مشاركة بطاقة التهنئة. وهذا ما تفعله Web Share API Web Share Target API يتيح لي ذلك. حصلت الأجهزة المحمولة وأنظمة تشغيل سطح المكتب مؤخرًا على ميزة المشاركة المدمجة والآليات الأخرى. على سبيل المثال، في ما يلي ورقة المشاركة في متصفّح Safari على أجهزة الكمبيوتر المكتبي على نظام التشغيل macOS والتي تم تشغيلها من مقالة في. مدونتي. عند النقر على زر مشاركة المقالة، يمكنك مشاركة رابط يؤدي إلى المقالة مع صديق، وذلك على سبيل المثال، عبر تطبيق "الرسائل" على نظام التشغيل macOS.
التعليمات البرمجية اللازمة لتنفيذ ذلك واضحة جدًا. اتصل بـ navigator.share()
يمكنك تمريره اختياريًا إلى title
وtext
وurl
في كائن.
ولكن ماذا لو أردت إرفاق صورة؟ لا يتوافق المستوى 1 من Web Share API مع هذا الإجراء حتى الآن.
الخبر السار هو أنّ المستوى 2 من ميزة "مشاركة الويب" قد أضاف إمكانيات مشاركة الملفات.
try {
await navigator.share({
title: 'Check out this article:',
text: `"${document.title}" by @tomayac:`,
url: document.querySelector('link[rel=canonical]').href,
});
} catch (err) {
console.warn(err.name, err.message);
}
دعني أوضح لك كيفية تنفيذ ذلك باستخدام تطبيق بطاقة Fugu Greeting.
أولاً، أحتاج إلى تحضير كائن data
باستخدام مصفوفة files
تتألف من كائن ثنائي كبير واحد، ثم
title
وtext
. وبعد ذلك، ومن أفضل الممارسات، أستخدِم طريقة navigator.canShare()
الجديدة التي
ما يقترحه اسمه:
فهي تخبرني ما إذا كان بإمكان المتصفّح مشاركة كائن data
الذي أحاول مشاركته من الناحية الفنية.
إذا طلبت مني navigator.canShare()
مشاركة البيانات، أنا مستعدّ
الاتصال بـ navigator.share()
كما في السابق.
بما أنّه قد يتعذّر تنفيذ بعض الخطوات، سأستخدم مجموعة try...catch
من جديد.
const share = async (title, text, blob) => {
const data = {
files: [
new File([blob], 'fugu-greeting.png', {
type: blob.type,
}),
],
title: title,
text: text,
};
try {
if (!(navigator.canShare(data))) {
throw new Error("Can't share data.", data);
}
await navigator.share(data);
} catch (err) {
console.error(err.name, err.message);
}
};
كما في السابق، أستخدم التحسين التدريجي.
إذا كان كل من 'share'
و'canShare'
موجودين على الكائن navigator
، عندها فقط سأنتقل إلى الأمام
تحميل share.mjs
عبر import()
الديناميكي.
لا أحمّل الملف على المتصفّحات مثل Safari على الأجهزة الجوّالة التي تستوفي شرطًا واحدًا فقط من الشرطَين.
الوظيفة.
const loadShare = () => {
if ('share' in navigator && 'canShare' in navigator) {
import('./share.mjs');
}
};
في Fugu Greetings، إذا نقرت على الزر مشاركة على متصفّح داعم مثل Chrome على Android، يتم فتح ورقة المشاركة المضمنة. يمكنني، على سبيل المثال، اختيار Gmail، فتنبثق أداة إنشاء البريد الإلكتروني تم إرفاق صورة.
واجهة برمجة تطبيقات منتقي جهات الاتصال
بعد ذلك، أريد التحدّث عن جهات الاتصال، بمعنى دفتر عناوين الجهاز. أو تطبيق "مدير جهات الاتصال" عند كتابة بطاقة تهنئة، قد لا يكون من السهل دائمًا كتابتها بشكل صحيح اسم شخص ما. فعلى سبيل المثال، لدي صديق كريم يفضل كتابة اسمه بالأحرف السيريلية. أنا باستخدام لوحة مفاتيح QWERTZ ألمانية وليس لديهم أي فكرة عن كيفية كتابة أسمائهم. هذه مشكلة يمكن لواجهة برمجة تطبيقات اختيار جهات الاتصال حلها. بما أنّ صديقي مخزن في تطبيق جهات الاتصال على هاتفي، عبر واجهة برمجة تطبيقات منتقي جهات الاتصال، يمكنني النقر على جهات الاتصال من الويب.
أولاً، أحتاج إلى تحديد قائمة الخصائص التي أريد الوصول إليها.
في هذه الحالة، أريد فقط الأسماء،
ولكن في حالات الاستخدام الأخرى، قد أهتم بأرقام الهواتف وعناوين البريد الإلكتروني وصور الأفاتار
أو الأيقونات أو العناوين المادية.
بعد ذلك، يمكنني إعداد كائن options
وضبط multiple
على true
، لأتمكّن من اختيار المزيد
أكثر من إدخال واحد.
أخيرًا، يمكنني استدعاء الدالة navigator.contacts.select()
، والتي تعرض الخصائص المطلوبة
لجهات الاتصال التي يحددها المستخدم.
const getContacts = async () => {
const properties = ['name'];
const options = { multiple: true };
try {
return await navigator.contacts.select(properties, options);
} catch (err) {
console.error(err.name, err.message);
}
};
وربما تكون قد تعلمت الآن النمط التالي: لا أحمّل الملف إلا عندما تكون واجهة برمجة التطبيقات متوافقة.
if ('contacts' in navigator) {
import('./contacts.mjs');
}
في Fugu Greeting، عندما أنقر على زر جهات الاتصال وأختار أفضل صديقَين لي Церге البودكاست кинакоровиш ضرباتрин و劳伦斯·爱德华·"拉里"·佩奇، يمكنك معرفة كيف فإن منتقي جهات الاتصال يقتصر على إظهار أسمائهم فقط، وليس عناوين بريدهم الإلكتروني، أو معلومات أخرى مثل أرقام هواتفهم. ثم يتم رسم أسمائهم على بطاقة التهنئة.
واجهة برمجة التطبيقات Asynchronous Clipboard API
الخطوة التالية هي النسخ واللصق. يعد النسخ واللصق من العمليات المفضلة لدينا كمطوري البرامج. بصفتي مؤلف بطاقات تهنئة، قد أحتاج في بعض الأحيان إلى الشيء نفسه. أريد إما لصق صورة في بطاقة تهنئة أعمل عليها، أو نسخ بطاقة التهنئة حتى أتمكن من متابعة تعديلها من في مكان آخر. Async Clipboard API تدعم النصوص والصور معًا. لأشرح لكم كيف أضفتُ دعم النسخ واللصق إلى Fugu تطبيق رسائل الترحيب
لنسخ شيء ما على حافظة النظام، أحتاج إلى الكتابة إليه.
تستخدم الطريقة navigator.clipboard.write()
صفيفًا من عناصر الحافظة
.
يُعد كل عنصر في الحافظة في الأساس كائنًا ذا قيمة ثنائية، ونوع الكائن الثنائي الكبير (blob)
كمفتاح.
const copy = async (blob) => {
try {
await navigator.clipboard.write([
new ClipboardItem({
[blob.type]: blob,
}),
]);
} catch (err) {
console.error(err.name, err.message);
}
};
لللصق، أحتاج إلى التكرار فوق عناصر الحافظة التي أحصل عليها من خلال استدعاء
navigator.clipboard.read()
السبب في ذلك هو أن عناصر متعددة في الحافظة قد تكون موجودة في الحافظة في
تمثيلات مختلفة.
يتضمّن كل عنصر في الحافظة حقل "types
" يوضّح لي أنواع MIME المتاحة
الموارد.
أستدعي طريقة getType()
لعنصر الحافظة، وأمرر
نوع MIME الذي حصلت عليه من قبل.
const paste = async () => {
try {
const clipboardItems = await navigator.clipboard.read();
for (const clipboardItem of clipboardItems) {
try {
for (const type of clipboardItem.types) {
const blob = await clipboardItem.getType(type);
return blob;
}
} catch (err) {
console.error(err.name, err.message);
}
}
} catch (err) {
console.error(err.name, err.message);
}
};
ولا داعي لقول ذلك الآن. لا أنفّذ هذا الإجراء إلا على المتصفّحات المتوافقة.
if ('clipboard' in navigator && 'write' in navigator.clipboard) {
import('./clipboard.mjs');
}
إذًا، كيف يعمل هذا عمليًا؟ لدي صورة مفتوحة في تطبيق معاينة macOS ونسخه إلى الحافظة. عندما أنقر على لصق، يطلب مني تطبيق Fugu Greetings ما إذا كنت أريد السماح للتطبيق بعرض النصوص والصور على الحافظة أم لا.
أخيرًا، بعد قبول الإذن، يتم لصق الصورة في التطبيق. الطريقة الأخرى تعمل أيضًا. دعني أنسخ بطاقة تهنئة إلى الحافظة. عندما أفتح "معاينة" وانقر على ملف ثم جديد من الحافظة، يتم لصق بطاقة التهنئة في صورة جديدة بلا عنوان.
واجهة برمجة التطبيقات Badging API
هناك واجهة برمجة تطبيقات أخرى مفيدة وهي Badging API.
ولأنّه تطبيق ويب تقدّمي قابل للتثبيت، فإنّ تطبيق Fugu Greetings لديه رمز تطبيق
التي يمكن للمستخدمين وضعها على شريط التطبيقات أو الشاشة الرئيسية.
هناك طريقة ممتعة وسهلة لعرض واجهة برمجة التطبيقات وهي (ab)استخدامها في Fugu Greetings
كعدّاد ضربات القلم.
أضفت أداة معالجة حدث تعمل على زيادة عدّاد ضغطات القلم كلما حدث حدث pointerdown
ثم يضبط شارة الرمز المحدث.
عند محو اللوحة، تتم إعادة ضبط العدّاد وتتم إزالة الشارة.
let strokes = 0;
canvas.addEventListener('pointerdown', () => {
navigator.setAppBadge(++strokes);
});
clearButton.addEventListener('click', () => {
strokes = 0;
navigator.setAppBadge(strokes);
});
تعمل هذه الميزة على تحسين تدريجي، وبالتالي فإنّ طريقة التحميل كالعادة.
if ('setAppBadge' in navigator) {
import('./badge.mjs');
}
في هذا المثال، رسمت الأرقام من واحد إلى سبعة، باستخدام خط واحد لكل رقم. أصبح عدّاد الشارات على الرمز الآن سبعة.
واجهة برمجة التطبيقات Periodic Background Sync API
هل تريد أن تبدأ كل يوم بشيء جديد؟ من الميزات الرائعة في تطبيق Fugu Greetings أنّه يمكن أن يكون مصدر إلهام لك كل صباح بصورة خلفية جديدة لبدء بطاقة التهنئة. يستخدم التطبيق واجهة برمجة التطبيقات Periodic Background Sync API. لتحقيق ذلك.
تتمثّل الخطوة الأولى في تسجيل حدث مزامنة دوري في تسجيل مشغّل الخدمات.
يرصد علامة مزامنة تُسمى 'image-of-the-day'
.
ويكون الحد الأدنى للفاصل الزمني هو يوم واحد،
ليتمكّن المستخدم من الحصول على صورة خلفية جديدة كل 24 ساعة.
const registerPeriodicBackgroundSync = async () => {
const registration = await navigator.serviceWorker.ready;
try {
registration.periodicSync.register('image-of-the-day-sync', {
// An interval of one day.
minInterval: 24 * 60 * 60 * 1000,
});
} catch (err) {
console.error(err.name, err.message);
}
};
الخطوة الثانية هي الاستماع إلى حدث periodicsync
في مشغّل الخدمات.
إذا كانت علامة الحدث هي 'image-of-the-day'
، أي العلامة التي تم تسجيلها من قبل،
يتم استرداد صورة اليوم عن طريق الدالة getImageOfTheDay()
،
وتم نشر النتيجة لجميع العملاء، حتى يتمكنوا من تحديث اللوحات
ذاكرات التخزين المؤقت.
self.addEventListener('periodicsync', (syncEvent) => {
if (syncEvent.tag === 'image-of-the-day-sync') {
syncEvent.waitUntil(
(async () => {
const blob = await getImageOfTheDay();
const clients = await self.clients.matchAll();
clients.forEach((client) => {
client.postMessage({
image: blob,
});
});
})()
);
}
});
مرة أخرى، هذا هو التحسين التدريجي، لذلك لا يتم تحميل الرمز إلا عندما
يتيح المتصفح استخدام واجهة برمجة التطبيقات.
وينطبق ذلك على كلّ من رمز العميل ورمز مشغّل الخدمات.
في حال استخدام المتصفِّحات غير المتوافقة، لا يتم تحميل أي منهما.
ملاحظة كيفية إجراء ذلك في مشغّل الخدمات، بدلاً من عنصر import()
ديناميكي
(هذا الخيار غير متاح في سياق مشغّل الخدمات)
حتى الآن)،
أستخدم النموذج الكلاسيكي
importScripts()
// In the client:
const registration = await navigator.serviceWorker.ready;
if (registration && 'periodicSync' in registration) {
import('./periodic_background_sync.mjs');
}
// In the service worker:
if ('periodicSync' in self.registration) {
importScripts('./image_of_the_day.mjs');
}
في تحية Fugu Greeting، يؤدي الضغط على الزر خلفية إلى إظهار صورة بطاقة التهنئة لليوم التي يتم تحديثها كل يوم عبر واجهة برمجة التطبيقات Periodic Background Sync API.
واجهة برمجة تطبيقات تشغيل الإشعارات
في بعض الأحيان، حتى مع وجود الكثير من الإلهام، تحتاج إلى تذكير تلقائي لإنهاء الترحيب الذي بدأته. بنجاح. هذه ميزة يتم تفعيلها من خلال واجهة برمجة التطبيقات Notification Triggers API. بصفتي مستخدمًا، يمكنني إدخال وقت أريد فيه تنبيهي لإكمال بطاقة التهنئة. عند حلول ذلك الوقت، أتلقى إشعارًا بأنّ بطاقة التهنئة في انتظارك.
بعد المطالبة بالوقت المستهدف،
يجدول التطبيق الإشعار من خلال showTrigger
.
يمكن أن يكون هذا الحدث TimestampTrigger
بتاريخ الاستهداف المحدّد سابقًا.
سيتم تشغيل إشعار التذكير على الجهاز، ولن تحتاج إلى الشبكة أو الخادم.
const targetDate = promptTargetDate();
if (targetDate) {
const registration = await navigator.serviceWorker.ready;
registration.showNotification('Reminder', {
tag: 'reminder',
body: "It's time to finish your greeting card!",
showTrigger: new TimestampTrigger(targetDate),
});
}
وكما هو الحال مع كل شيء آخر عرضتُه حتى الآن، هذا تحسين تدريجي، لذلك يتم تحميل التعليمة البرمجية بشكل مشروط فقط.
if ('Notification' in window && 'showTrigger' in Notification.prototype) {
import('./notification_triggers.mjs');
}
عندما أضع علامة في مربّع الاختيار تذكير في Fugu Greetings، تظهر رسالة عندما أريد أن يتم تذكيري بإنهاء بطاقة التهنئة.
عندما يظهر إشعار مجدوَل في Fugu Greetings، يظهر تمامًا مثل أي إشعار آخر، ولكن كما كتبت من قبل، لم يتطلب الاتصال بالشبكة.
واجهة برمجة تطبيقات Wake Lock
أريد أيضًا تضمين Wake Lock API. في بعض الأحيان تحتاج فقط إلى التحديق لفترة طويلة على الشاشة حتى الحصول على الإلهام قبلك. أسوأ ما يمكن أن يحدث بعد ذلك هو إيقاف الشاشة. وقد تمنع واجهة برمجة التطبيقات Wake Lock API حدوث ذلك.
الخطوة الأولى هي الحصول على قفل تنشيط باستخدام navigator.wakelock.request method()
.
أدخلها على السلسلة 'screen'
للحصول على قفل تنشيط الشاشة.
بعد ذلك، أضيف أداة معالجة حدث ليتم تنبيهها عند فتح قفل التنشيط.
يمكن أن يحدث هذا، على سبيل المثال، عندما يتغير مستوى رؤية علامة التبويب.
إذا حدث هذا، يمكنني الحصول على قفل التنشيط مرة أخرى عندما تصبح علامة التبويب مرئية مرة أخرى.
let wakeLock = null;
const requestWakeLock = async () => {
wakeLock = await navigator.wakeLock.request('screen');
wakeLock.addEventListener('release', () => {
console.log('Wake Lock was released');
});
console.log('Wake Lock is active');
};
const handleVisibilityChange = () => {
if (wakeLock !== null && document.visibilityState === 'visible') {
requestWakeLock();
}
};
document.addEventListener('visibilitychange', handleVisibilityChange);
document.addEventListener('fullscreenchange', handleVisibilityChange);
نعم، هذا تحسين تدريجي، لذلك لا أحتاج إلى تحميله إلا عندما يتصفح يدعم واجهة برمجة التطبيقات.
if ('wakeLock' in navigator && 'request' in navigator.wakeLock) {
import('./wake_lock.mjs');
}
في Fugu Greetings، يتوفّر مربّع الاختيار الأرق الذي يحافظ على تنشيط الشاشة.
واجهة برمجة تطبيقات Idle Detection
في بعض الأحيان، حتى إذا كنت تحدّق في الشاشة لساعات، عديم الفائدة ولا يمكنك استنباط أقل فكرة حول ما تفعله ببطاقة التهنئة. تسمح Idle Detection API للتطبيق برصد وقت عدم نشاط المستخدم. إذا كان المستخدم غير نشِط لفترة طويلة جدًا، تتم إعادة ضبط التطبيق على الحالة الأولية. ويمحو اللوحة. تخضع واجهة برمجة التطبيقات هذه حاليًا خلف إذن الإشعارات نظرًا لأن الكثير من حالات الاستخدام التجريبي للاكتشاف في وضع عدم النشاط تكون متعلقة بالإشعارات، على سبيل المثال، لإرسال إشعار إلى الجهاز الذي يستخدمه المستخدم حاليًا بشكل نشط.
بعد التأكد من منح إذن الإشعارات، أنشئ حينئذٍ مثيلاً كاشف الخمول. أسجّل أداة معالجة حدث تنتبه إلى التغييرات غير النشطة، والتي تتضمن بيانات المستخدم حالة الشاشة. يمكن أن يكون المستخدم نشطًا أو خاملاً، ويمكن فتح قفل الشاشة أو قفلها. إذا كان المستخدم في وضع عدم النشاط، يتم محو اللوحة. أُعطي أداة رصد عدم النشاط لفترة قصيرة 60 ثانية.
const idleDetector = new IdleDetector();
idleDetector.addEventListener('change', () => {
const userState = idleDetector.userState;
const screenState = idleDetector.screenState;
console.log(`Idle change: ${userState}, ${screenState}.`);
if (userState === 'idle') {
clearCanvas();
}
});
await idleDetector.start({
threshold: 60000,
signal,
});
وكالعادة، لا أحمّل هذا الرمز إلا عندما يتيح المتصفّح ذلك.
if ('IdleDetector' in window) {
import('./idle_detection.mjs');
}
في تطبيق Fugu Greetings، يتم محو اللوحة عند ضبط مربّع الاختيار الملف الشخصي المؤقت. ويتم تحديده ويظل المستخدم في وضع الخمول لفترة طويلة جدًا.
الخاتمة
أوه، يا لها من رحلة. العديد من واجهات برمجة التطبيقات في نموذج واحد فقط وتذكر أنني لا أجعل المستخدم يدفع تكلفة التنزيل مطلقًا عن ميزة لا يدعمها المتصفح. باستخدام التحسين التدريجي، أتأكّد من تحميل الرمز ذي الصلة فقط. ونظرًا لأن HTTP/2، تكون الطلبات رخيصة، فمن المفترض أن يعمل هذا النمط بشكل جيد مع العديد من التطبيقات بالرغم من أنك قد ترغب في التفكير في أداة لحزم التطبيقات كبيرة الحجم.
قد يبدو التطبيق مختلفًا قليلاً على كل متصفح نظرًا لعدم دعم جميع الأنظمة الأساسية لجميع الميزات، ولكن الوظيفة الأساسية متاحة دائمًا هناك، ويتم تحسينها بشكل تدريجي وفقًا لإمكانيات المتصفّح المحدَّد. تجدر الإشارة إلى أنّ هذه الإمكانيات قد تتغيّر حتى في متصفّح واحد اعتمادًا على ما إذا كان التطبيق قيد التشغيل كتطبيق مثبَّت أو في علامة تبويب متصفّح.
إذا كان يهمّك تطبيق Fugu Greetings، ابحث عنها وتشعبها على GitHub.
يسعى فريق Chromium جاهدًا إلى جعل العشب أكثر مراعاة للبيئة في ما يتعلق بواجهات برمجة تطبيقات Fugu API المتقدمة. ومن خلال تطبيق التحسين التدريجي على تطوير تطبيقي، أتأكد من أن الجميع يحصل على تجربة أساسية جيدة وقوية، ولكن الأشخاص الذين يستخدمون متصفحات تتوافق مع المزيد من واجهات برمجة تطبيقات النظام الأساسي للويب يحصلون على تجربة أفضل. أنا أتطلع إلى معرفة ما يمكنك فعله بالتحسين التدريجي في تطبيقاتك.
شكر وتقدير
أنا ممتنّ كريستيان ليبل
هيمانث HM الذين ساهما في إطلاق ميزة Fugu Greetings
تمت مراجعة هذه المقالة بواسطة جو ميدلي و
كايس باسك.
ساعدني جيك أرتشيبالد في معرفة الموقف
باستخدام import()
الديناميكي في سياق مشغّل الخدمات.