تعرَّف على كيفية قياس استخدام ذاكرة صفحة الويب في مرحلة الإنتاج لرصد حالات التراجع.
تدير المتصفحات ذاكرة صفحات الويب تلقائيًا. عندما تنشئ صفحة ويب عنصرًا، يخصّص المتصفّح جزءًا من الذاكرة "في الخلفية" لتخزين العنصر. بما أنّ الذاكرة هي مورد محدود، ينفِّذ المتصفّح عملية جمع القمامة لرصد الحالات التي لم تعُد فيها العناصر مطلوبة وتحرير قطعة الذاكرة الأساسية.
ومع ذلك، فإنّ عملية رصد المحتوى ليست مثالية، وقدتبيّن أنّه من المستحيل رصد المحتوى بشكل مثالي. وبالتالي تقترب المتصفحات من مفهوم "هناك حاجة إلى كائن" من مفهوم "يمكن الوصول إلى كائن". إذا تعذّر على صفحة الويب الوصول إلى عنصر من خلال متغيّراته وحقول العناصر الأخرى التي يمكن الوصول إليها، يمكن للمتصفح استرداد العنصر بأمان. يؤدي الاختلاف بين هذين المفهومين إلى تسرُّب الذاكرة كما هو موضّح في المثال التالي.
const object = {a: new Array(1000), b: new Array(2000)};
setInterval(() => console.log(object.a), 1000);
لم تعُد هناك حاجة إلى المصفوفة الأكبر b
هنا، ولكن لن يستردها المتصفِّح لأنه لا يزال من الممكن الوصول إليها عبر object.b
في معاودة الاتصال. وبالتالي،
يتم تسرُّب ذاكرة الصفيف الأكبر.
إنّ تسرّبات الذاكرة شائعة على الويب. ومن السهل حدوث ذلك عن طريق نسيان إلغاء تسجيل مستمع للأحداث، أو عن طريق التقاط عناصر من إطار iframe عن طريق الخطأ، أو عدم إغلاق عامل، أو تجميع عناصر في صفائف، وما إلى ذلك. إذا كانت صفحة ويب تتضمّن عمليات تسرُّب للذاكرة، يزداد استخدامها للذاكرة بمرور الوقت وتبدو صفحة الويب بطيئة ومزدحمة للمستخدمين.
الخطوة الأولى في حل هذه المشكلة هي قياسها. تتيح واجهة برمجة التطبيقات الجديدة
performance.measureUserAgentSpecificMemory()
API للمطوّرين معرفة مقدار استخدام صفحات الويب للذاكرة في مرحلة الإنتاج، وبالتالي رصد تسرُّب الذاكرة الذي لا يتم رصده في الاختبارات المحلية.
ما هي أوجه اختلاف performance.measureUserAgentSpecificMemory()
عن واجهة برمجة تطبيقات performance.memory
القديمة؟
إذا كنت على دراية بواجهة برمجة التطبيقات الحالية غير العادية performance.memory
،
قد تتساءل عن الفرق بين واجهة برمجة التطبيقات الجديدة وواجهة برمجة التطبيقات الحالية. يكمن الاختلاف الرئيسي بينهما في أنّ واجهة برمجة التطبيقات القديمة تعرض حجم ذاكرة JavaScript العشوائية، في حين تقدّر واجهة برمجة التطبيقات الجديدة الذاكرة المستخدَمة في صفحة الويب. يصبح هذا الاختلاف مهمًا
عندما يشارك Chrome كومة الذاكرة المستخدم نفسه مع صفحات ويب متعددة (أو مثيلات متعددة لصفحة الويب نفسها). في هذه الحالات، قد تكون نتيجة واجهة برمجة التطبيقات
القديمة غير صحيحة بشكل عشوائي. وبما أنّ واجهة برمجة التطبيقات القديمة محدّدة في مصطلحات متعلقة بالتنفيذ مثل "الحزمة"، لا يمكن توحيدها.
هناك اختلاف آخر وهو أنّ واجهة برمجة التطبيقات الجديدة تُجري قياسًا للذاكرة أثناء جمع المهملات. ويقلل هذا من مستوى التشويش في النتائج، ولكن قد يستغرق ظهور النتائج بعض الوقت. تجدر الإشارة إلى أنّ المتصفّحات الأخرى قد تقرر تنفيذ واجهة برمجة التطبيقات الجديدة بدون الاعتماد على جمع البيانات غير المرغوب فيها.
حالات الاستخدام المقترَحة
يعتمد استخدام الذاكرة لصفحة ويب على توقيت الأحداث وإجراءات المستخدمين وعمليات جمع القمامة. ولهذا السبب تم تصميم واجهة برمجة التطبيقات لقياس الذاكرة لتجميع بيانات استخدام الذاكرة من الإنتاج. تكون نتائج المكالمات الفردية أقلّ فائدة. أمثلة على حالات الاستخدام:
- رصد التراجع أثناء طرح إصدار جديد من صفحة الويب لرصد عمليات تسرُّب الذاكرة الجديدة
- اختبار A/B لميزة جديدة لتقييم تأثيرها في الذاكرة ورصد تسرُّب الذاكرة
- ربط استخدام الذاكرة بمدة الجلسة للتحقّق من تسرُّب الذاكرة أو عدم تسرُّبه
- ربط استخدام الذاكرة بمقاييس المستخدمين لفهم التأثير العام لاستخدام الذاكرة
توافُق المتصفح
لا تتوفّر واجهة برمجة التطبيقات حاليًا إلا في المتصفّحات المستندة إلى Chromium، بدءًا من الإصدار 89 من Chrome. تعتمد نتيجة واجهة برمجة التطبيقات بشكل كبير على التنفيذ لأنّ المتصفّحات لديها طرق مختلفة لتمثيل العناصر في الذاكرة وطرق مختلفة لتقدير استخدام الذاكرة. قد تستبعد المتصفّحات بعض مناطق الذاكرة من حساب المساحة إذا كان احتساب المساحة بشكل صحيح باهظ التكلفة أو غير عملي. وبالتالي، لا يمكن مقارنة النتائج على مستوى المتصفحات. لا فائدة من مقارنة النتائج للمتصفح نفسه.
جارٍ استخدام performance.measureUserAgentSpecificMemory()
رصد الميزات
لن تكون دالة performance.measureUserAgentSpecificMemory
متاحة أو قد تتعذّر
تنفيذها مع ظهور خطأ SecurityError إذا لم تستوفِ بيئة التنفيذ
متطلبات الأمان لمنع تسرُّب المعلومات من مصادر متعددة.
تعتمد هذه الميزة على العزل المشترك المصدر، والذي يمكن لصفحة الويب تفعيله
من خلال ضبط رؤوس COOP+COEP.
يمكن رصد مدى توفّر الميزة أثناء التشغيل:
if (!window.crossOriginIsolated) {
console.log('performance.measureUserAgentSpecificMemory() is only available in cross-origin-isolated pages');
} else if (!performance.measureUserAgentSpecificMemory) {
console.log('performance.measureUserAgentSpecificMemory() is not available in this browser');
} else {
let result;
try {
result = await performance.measureUserAgentSpecificMemory();
} catch (error) {
if (error instanceof DOMException && error.name === 'SecurityError') {
console.log('The context is not secure.');
} else {
throw error;
}
}
console.log(result);
}
الاختبار المحلي
يُجري Chrome عملية قياس الذاكرة أثناء جمع المهملات، ما يعني أنّ واجهة برمجة التطبيقات لا تحلّ وعد النتائج على الفور، بل تنتظر بدلاً من ذلك عملية جمع المهملات التالية.
يفرض طلب واجهة برمجة التطبيقات تجميع البيانات المهملة بعد انتهاء المهلة، والتي يتم ضبطها حاليًا على 20 ثانية، ولكن قد يحدث ذلك في وقت أقرب. يؤدي بدء Chrome باستخدام علامة سطر الأوامر
--enable-blink-features='ForceEagerMeasureMemory'
إلى تقليل مهلة الانتظار إلى الصفر، وهي مفيدة لتصحيح الأخطاء والاختبار على الجهاز.
مثال
إنّ الاستخدام المُقترَح لواجهة برمجة التطبيقات هو تحديد أداة مراقبة ذاكرة شاملة تُجري تحليلات لمستخدِمي الذاكرة في صفحة الويب بالكامل وتُرسِل النتائج إلى خادم لجمعها وتحليلها. إنّ أبسط طريقة هي أخذ عيّنات بشكل دوري، مثلاً كل M
دقيقة. ومع ذلك، يؤدي ذلك إلى إدخال تحيز في البيانات لأنّه قد تحدث ذروات في استخدام الذاكرة بين العيّنات.
يوضّح المثال التالي كيفية إجراء قياسات غير متحيّزة للذاكرة باستخدام عملية بوسينون، ما يضمن احتمالية حدوث العيّنات بشكلٍ متساوٍ في أيّ وقت (العرض التجريبي، المصدر).
عليك أولاً تحديد دالة يمكنها جدولة القياس التالي للذاكرة باستخدام setTimeout()
مع فاصل عشوائي.
function scheduleMeasurement() {
// Check measurement API is available.
if (!window.crossOriginIsolated) {
console.log('performance.measureUserAgentSpecificMemory() is only available in cross-origin-isolated pages');
console.log('See https://web.dev/coop-coep/ to learn more')
return;
}
if (!performance.measureUserAgentSpecificMemory) {
console.log('performance.measureUserAgentSpecificMemory() is not available in this browser');
return;
}
const interval = measurementInterval();
console.log(`Running next memory measurement in ${Math.round(interval / 1000)} seconds`);
setTimeout(performMeasurement, interval);
}
تحسب الدالة measurementInterval()
فاصلًا زمنيًا عشوائيًا بالمللي ثانية
بحيث يتم إجراء قياس واحد في المتوسط كل خمس دقائق. اطّلِع على التوزّع الدوامي
إذا كنت مهتمًا بمعرفة العمليات الحسابية التي تستند إليها الدالة.
function measurementInterval() {
const MEAN_INTERVAL_IN_MS = 5 * 60 * 1000;
return -Math.log(Math.random()) * MEAN_INTERVAL_IN_MS;
}
أخيرًا، تستدعي الدالة غير المتزامنة performMeasurement()
واجهة برمجة التطبيقات وتُسجِّل
النتيجة وتُحدِّد موعد القياس التالي.
async function performMeasurement() {
// 1. Invoke performance.measureUserAgentSpecificMemory().
let result;
try {
result = await performance.measureUserAgentSpecificMemory();
} catch (error) {
if (error instanceof DOMException && error.name === 'SecurityError') {
console.log('The context is not secure.');
return;
}
// Rethrow other errors.
throw error;
}
// 2. Record the result.
console.log('Memory usage:', result);
// 3. Schedule the next measurement.
scheduleMeasurement();
}
أخيرًا، ابدأ القياس.
// Start measurements.
scheduleMeasurement();
قد تبدو النتيجة على النحو التالي:
// Console output:
{
bytes: 60_100_000,
breakdown: [
{
bytes: 40_000_000,
attribution: [{
url: 'https://example.com/',
scope: 'Window',
}],
types: ['JavaScript']
},
{
bytes: 20_000_000,
attribution: [{
url: 'https://example.com/iframe',
container: {
id: 'iframe-id-attribute',
src: '/iframe',
},
scope: 'Window',
}],
types: ['JavaScript']
},
{
bytes: 100_000,
attribution: [],
types: ['DOM']
},
],
}
يتم عرض تقدير إجمالي استخدام الذاكرة في حقل bytes
. تعتمد هذه القيمة
بشكل كبير على التنفيذ ولا يمكن مقارنتها بين المتصفّحات. وقد
يختلف ذلك حتى بين الإصدارات المختلفة من المتصفح نفسه. تتضمّن القيمة
ذاكرة JavaScript وDOM لجميع إطارات iframe والنوافذ ذات الصلة وموظفي الويب في
العملية الحالية.
تقدّم قائمة breakdown
معلومات إضافية عن الذاكرة المستخدَمة. يصف كل إدخال
جزءًا من الذاكرة وينسبه إلى مجموعة من
المنافذ وإطارات iframe والعمال الذين تم تحديدهم من خلال عنوان URL. يسرد حقل types
أنواع الذاكرة المرتبطة بالذاكرة الخاصة بالتنفيذ.
من المهم أن يتم التعامل مع جميع القوائم بطريقة عامة وعدم استخدام افتراضات تستند إلى متصفح معين. على سبيل المثال، قد تعرِض بعض المتصفحاتbreakdown
فارغًا أوattribution
فارغًا. قد تعرض المتصفّحات الأخرى
إدخالات متعددة في attribution
تشير إلى أنّه تعذّر عليها التمييز بين
أيّ من هذه الإدخالات يملك الذاكرة.
ملاحظات
يسرّ مجموعة منتدى أداء الويب وفريق Chrome معرفة
رأيك وتجاربك مع
performance.measureUserAgentSpecificMemory()
.
أخبِرنا عن تصميم واجهة برمجة التطبيقات.
هل هناك مشكلة في واجهة برمجة التطبيقات لا تعمل على النحو المتوقّع؟ هل هناك سمات غير متوفّرة تحتاج إليها لتنفيذ فكرتك؟ يمكنك الإبلاغ عن مشكلة في المواصفات على مستودع GitHub الخاص بـ performance.measureUserAgentSpecificMemory() أو إضافة ملاحظاتك إلى مشكلة حالية.
الإبلاغ عن مشكلة في التنفيذ
هل رصدت خطأ في عملية تنفيذ Chrome؟ أم هل التنفيذ مختلف عن المواصفات؟ أبلِغ عن الخطأ على new.crbug.com. احرص على
تضمين أكبر قدر ممكن من التفاصيل، وتقديم تعليمات بسيطة لإعادة تكرار
الخطأ، وضبط المكوّنات على Blink>PerformanceAPIs
.
يُعدّ تطبيق Glitch مثاليًا لمشاركة عمليات إعادة الإنتاج بسرعة وسهولة.
إظهار الدعم
هل تخطّط لاستخدام performance.measureUserAgentSpecificMemory()
؟ يساعد الدعم العلني
فريق Chrome في تحديد الأولويات للميزات ويوضّح لموفّري المتصفّحات الآخرين مدى
أهمية توفير الدعم لها. يمكنك إرسال تغريدة إلى @ChromiumDev
وإعلامنا بمكان استخدامها وكيفية استخدامها.
روابط مفيدة
- الشرح
- العرض التوضيحي | مصدر العرض التوضيحي
- خطأ في التتبُّع
- إدخال ChromeStatus.com
- التغييرات منذ إطلاق Origin Trial API
- التجربة والتقييم التي انتهت
الشكر والتقدير
نشكر بشدة "دومينيك دينيكولا" و"يوآف وايسس" و"ماتياس بينينز" على مراجعات تصميم واجهات برمجة التطبيقات، و"دومينيك إنفوير" و"هانيس باير" و"كينتارو هارا" و"مايكل ليباتز" على مراجعات الرموز البرمجية في Chrome. أشكر أيضًا "بير باركر" و"فيليب وايس" و"أولغا بيلوميستنيك" و"ماثيو بولاهان" و"نيل ماكاي" على تقديم ملاحظات قيّمة من المستخدمين أدّت إلى تحسين واجهة برمجة التطبيقات بشكل كبير.
صورة رئيسية من إعداد هاريسون برودبنت على قناة Un التصميم