ظهر دعم
WebAssembly (Wasm) في المتصفحات مؤخرًا نسبيًا. ولكن هذه التكنولوجيا يمكنها أن تزيد من إمكانيات الويب ، مما يجعلها منصة قادرة على دعم مثل هذه التطبيقات التي عادة ما تعتبر سطح مكتب.
يمكن أن يكون إتقان WebAssembly مهمة شاقة لمطوري الويب. ومع ذلك ، يمكن المحول البرمجي
AssemblyScript تحسين الموقف.
يقدم مؤلف المقال ، الذي ننشره ترجمة اليوم ، الحديث أولاً عن سبب كون WebAssembly تقنية واعدة للغاية ، ثم نلقي نظرة على كيف يمكن لـ AssemblyScript المساعدة في فتح إمكانات Wasm.
WebAssembly
يمكن أن يسمى WebAssembly لغة منخفضة المستوى للمتصفحات. إنه يمنح المطورين القدرة على إنشاء تعليمات برمجية لتجميعها إلى شيء آخر غير JavaScript. يتيح ذلك للبرامج المضمّنة في صفحات الويب أن تعمل بالسرعة نفسها التي تعمل بها التطبيقات الأصلية لمختلف المنصات. تعمل مثل هذه البرامج في بيئة محدودة وآمنة.
شارك ممثلو الفرق المسؤولة عن تطوير جميع المتصفحات الرائدة (Chrome و Firefox و Safari و Edge) في إنشاء معيار WebAssembly. واتفقوا على
بنية النظام في أوائل عام 2017. الآن جميع المتصفحات المذكورة أعلاه تدعم WebAssembly. في الواقع ، يمكن استخدام هذه التكنولوجيا في
حوالي 87 ٪ من المتصفحات.
رمز WebAssembly موجود بالتنسيق الثنائي. هذا يعني أن مثل هذا الرمز أصغر من كود JavaScript مماثل ويتم تحميله بشكل أسرع. يمكن تقديم Wasm-code ، بالإضافة إلى ذلك ، في
تنسيق نصي ، حتى يتمكن الناس من قراءته وتحريره.
عندما ظهر معيار WebAssembly لأول مرة ، ظن بعض المطورين أنه يمكن أن يحل محل JavaScript ويصبح اللغة الرئيسية للويب. ولكن يُنظر إلى WebAssembly كأداة جديدة تتكامل بشكل جيد مع النظام الأساسي الحالي للويب. هذا هو أحد
أهدافه ذات الأولوية .
بدلاً من استبدال JavaScript حيث تم استخدام هذه اللغة لفترة طويلة وبنجاح ، يوفر WebAssembly فرصًا جديدة مثيرة لمطوري الويب. صحيح أن رمز Wasm لا يتمتع بوصول مباشر إلى DOM ، لذلك ستستمر معظم مشاريع الويب الحالية في استخدام JavaScript. هذه اللغة ، على مدار سنوات من التطوير والتحسين ، سريعة بالفعل. و WebAssembly له تطبيقاته الخاصة:
- ألعاب.
- الحسابات العلمية ، المرئيات ، المحاكاة.
- تطبيقات CAD.
- تحرير الصور ومقاطع الفيديو.
كل هذه الاستخدامات الخاصة بـ Wasm يتم توحيدها حسب ما تعتبر التطبيقات الخاصة بهم عادة سطح مكتب. ولكن نظرًا لحقيقة أن WebAssembly يسمح لك بالوصول إلى مستوى من الأداء قريبًا من المستوى الأصلي ، يمكن الآن تنفيذ العديد من التطبيقات المماثلة باستخدام النظام الأساسي للويب.
يمكن WebAssembly الاستفادة من مشاريع الويب الحالية. مثال على
ذلك مشروع
Figma . بفضل استخدام Wasm ، تم تحسين وقت التحميل لهذا المشروع بشكل كبير. إذا كان موقع الويب يستخدم تعليمة برمجية تؤدي عمليات حسابية ثقيلة ، فمن أجل تحسين أداء هذا الموقع ، فمن المنطقي استبدال هذا الرمز فقط بتناظرية WebAssembly.
قد ترغب في محاولة استخدام WebAssembly في مشاريعك الخاصة. يمكن تعلم هذه اللغة وكتابتها
على الفور . ولكن ، مع ذلك ، تم تطوير WebAssembly أصلاً كهدف
تجميع للغات أخرى. تم
تصميمه بدعم جيد لـ C و C ++. ظهر
دعم تجريبي لـ Was في Go 1.11. يتم بذل الكثير من الجهد في كتابة تطبيقات Wasm في
Rust .
لكن من الممكن تمامًا ألا يرغب مطورو الويب في تعلم C أو C ++ أو Go أو Rust فقط لاستخدام WebAssembly. ماذا يفعلون؟ يمكن أن تعطي الإجابة على هذا السؤال AssemblyScript.
AssemblyScript
AssemblyScript هو مترجم يحول كود TypeScript إلى كود WebAssembly. TypeScript هي لغة تم تطويرها بواسطة Microsoft. هذه مجموعة شاملة من جافا سكريبت ، تتميز بدعم محسّن من النوع وبعض الميزات الأخرى. أصبح TypeScript لغة
شعبية إلى حد ما. تجدر الإشارة إلى أن AssemblyScript قادر على التحويل إلى Wasm فقط مجموعة محدودة من بنيات TypeScript. هذا يعني أنه حتى أي شخص غير مطلع على TypeScript يمكنه أن يتعلم بسرعة هذه اللغة بمستوى يكفي لكتابة التعليمات البرمجية التي يفهمها AssemblyScript.
علاوة على ذلك ، بالنظر إلى أن TypeScript يشبه JavaScript إلى حد كبير ، يمكننا القول أن تقنية AssemblyScript تسمح لمطوري الويب بدمج وحدات Wasm بسهولة في مشاريعهم دون الحاجة إلى تعلم لغة جديدة تمامًا.
مثال
دعنا نكتب أول وحدة AssemblyScript الخاصة بنا. يمكن العثور على جميع الكود الذي سنناقشه الآن على
جيثب .
لدعم WebAssembly ، نحتاج إلى
Node.js 8 على الأقل.
إنشاء دليل جديد ، تهيئة مشروع npm وتثبيت AssemblyScript:
mkdir assemblyscript-demo cd assemblyscript-demo npm init npm install --save-dev github:AssemblyScript/assemblyscript
لاحظ أنه يجب تثبيت AssemblyScript مباشرة من
مستودع GitHub للمشروع. لم يتم نشر AssemblyScript بعد في npm ، لأن المطورين
لا يعتبرونه جاهزًا للاستخدام على نطاق واسع.
asinit
ملفات مساعدة باستخدام الأمر
asinit
المتضمن في AssemblyScript:
npx asinit .
الآن قسم
scripts
لدينا
package.json
يجب أن تأخذ الشكل التالي:
{ "scripts": { "asbuild:untouched": "asc assembly/index.ts -b build/untouched.wasm -t build/untouched.wat --sourceMap --validate --debug", "asbuild:optimized": "asc assembly/index.ts -b build/optimized.wasm -t build/optimized.wat --sourceMap --validate --optimize", "asbuild": "npm run asbuild:untouched && npm run asbuild:optimized" } }
index.js
ملف
index.js
الموجود في المجلد الجذر للمشروع كما يلي:
const fs = require("fs"); const compiled = new WebAssembly.Module(fs.readFileSync(__dirname + "/build/optimized.wasm")); const imports = { env: { abort(_msg, _file, line, column) { console.error("abort called at index.ts:" + line + ":" + column); } } }; Object.defineProperty(module, "exports", { get: () => new WebAssembly.Instance(compiled, imports).exports });
يتيح لك هذا تضمين وحدات WebAssembly في التعليمات البرمجية الخاصة بك باستخدام الأمر requ. هذا - بنفس طريقة توصيل وحدات JavaScript المعتادة.
يحتوي مجلد
assembly
على ملف
index.ts
. لديها شفرة المصدر مكتوبة وفقا لقواعد AssemblyScript. شفرة الغليان التي يتم إنشاؤها تلقائيًا هي وظيفة بسيطة لإضافة رقمين:
export function add(a: i32, b: i32): i32 { return a + b; }
ربما كنت تتوقع توقيع دالة مماثلة لتبدو وكأنها
add(a: number, b: number): number
. لذلك سيبدو إذا كان مكتوبًا في برنامج TypeScript العادي. ولكن هنا ، بدلاً من نوع
number
، يتم
i32
نوع
i32
. يحدث هذا لأن كود AssemblyScript يستخدم
أنواع WebAssembly محددة
للأعداد الصحيحة وأرقام
الفاصلة العائمة ، بدلاً من نوع
الرقم العام من TypeScript.
لنقم بتجميع المشروع:
npm run asbuild
يجب أن تظهر الملفات التالية في مجلد الإنشاء:
optimized.wasm optimized.wasm.map optimized.wat untouched.wasm untouched.wasm.map untouched.wat
هناك إصدارات محسنة ومنتظمة للتجميع. يعطينا كل إصدار من التجميع ملفًا .wasm ثنائيًا ،
وخريطة خريطة .wasm.map ، وتمثيلًا نصيًا للرمز الثنائي في ملف .wat. العرض التقديمي لاختبار رمز Wasm مخصص للمبرمج ، لكننا لن ننظر حتى إلى هذا الملف. في الواقع ، أحد أسباب استخدام AssemblyScript هو أنه يلغي الحاجة للعمل مع رمز Wasm.
الآن لنقم بتشغيل Node.js في وضع REPL وتأكد من أن وحدة Wasm المترجمة يمكن استخدامها بنفس طريقة استخدام أي وحدة JS عادية:
$ node Welcome to Node.js v12.10.0. Type ".help" for more information. > const add = require('./index').add; undefined > add(3, 5) 8
بشكل عام ، هذا هو كل ما يلزم لاستخدام تقنية WebAssembly في Node.js.
تجهيز مشروع مع برنامج نصي مراقب
لإعادة إنشاء الوحدة النمطية تلقائيًا أثناء التطوير عند إجراء تغييرات عليها ، أوصي باستخدام الحزمة
onchange . الحقيقة هي أن AssemblyScript
ليس لديه بعد نظام خاص به لمراقبة تغييرات الملفات. تثبيت الحزمة onchange:
npm install --save-dev onchange
إضافة
asbuild:watch
البرنامج النصي إلى
package.json
.
يتم تضمين
علامة -i
في الأمر بحيث تبدأ عملية الإنشاء مرة واحدة عندما يتم استدعاء البرنامج النصي ، قبل حدوث أي أحداث.
{ "scripts": { "asbuild:untouched": "asc assembly/index.ts -b build/untouched.wasm -t build/untouched.wat --sourceMap --validate --debug", "asbuild:optimized": "asc assembly/index.ts -b build/optimized.wasm -t build/optimized.wat --sourceMap --validate --optimize", "asbuild": "npm run asbuild:untouched && npm run asbuild:optimized", "asbuild:watch": "onchange -i 'assembly/**/*' -- npm run asbuild" } }
الآن ، بدلاً من تشغيل الأمر
asbuild
باستمرار ، ما
asbuild:watch
سوى تشغيل
asbuild:watch
مرة واحدة.
إنتاجية
سنكتب اختبارًا بسيطًا لتقييم مستوى أداء رمز Wasm. يتمثل النطاق الرئيسي لـ WebAssembly في حل المهام التي تستخدم المعالج بشكل مكثف. على سبيل المثال ، هذه هي نوع من الحسابات "الثقيلة". لنقم بإنشاء وظيفة تكتشف ما إذا كان عدد معين أولي.
يظهر تنفيذ JS الأساسي لوظيفة مماثلة أدناه. يتم ترتيبها بكل بساطة ، حيث تقوم بالتحقق من الرقم بالقوة الغاشمة ، ولكن لأغراضنا ، يكون هذا مناسبًا ، نظرًا لأنه يؤدي مبالغ كبيرة من الحسابات.
function isPrime(x) { if (x < 2) { return false; } for (let i = 2; i < x; i++) { if (x % i === 0) { return false; } } return true; }
وظيفة مماثلة ، مكتوبة من أجل مترجم AssemblyScript ، تبدو هي نفسها تقريبا. الفرق الرئيسي هو وجود تعليقات توضيحية في الكود:
function isPrime(x: u32): bool { if (x < 2) { return false; } for (let i: u32 = 2; i < x; i++) { if (x % i === 0) { return false; } } return true; }
لتحليل أداء الكود ، سنستخدم حزمة
Benchmark.js . تثبيته:
npm install --save-dev benchmark
قم
benchmark.js
ملف
benchmark.js
:
const Benchmark = require('benchmark'); const assemblyScriptIsPrime = require('./index').isPrime; function isPrime(x) { for (let i = 2; i < x; i++) { if (x % i === 0) { return false; } } return true; } const suite = new Benchmark.Suite; const startNumber = 2; const stopNumber = 10000; suite.add('AssemblyScript isPrime', function () { for (let i = startNumber; i < stopNumber; i++) { assemblyScriptIsPrime(i); } }).add('JavaScript isPrime', function () { for (let i = startNumber; i < stopNumber; i++) { isPrime(i); } }).on('cycle', function (event) { console.log(String(event.target)); }).on('complete', function () { const fastest = this.filter('fastest'); const slowest = this.filter('slowest'); const difference = (fastest.map('hz') - slowest.map('hz')) / slowest.map('hz') * 100; console.log(`${fastest.map('name')} is ~${difference.toFixed(1)}% faster.`); }).run();
إليك ما تمكنت من الحصول عليه بعد تشغيل الأمر
node benchmark
العقدي على جهاز الكمبيوتر الخاص بي:
AssemblyScript isPrime x 74.00 ops/sec ±0.43% (76 runs sampled) JavaScript isPrime x 61.56 ops/sec ±0.30% (64 runs sampled) AssemblyScript isPrime is ~20.2% faster.
كما ترون ، كان تطبيق AssemblyScript للخوارزمية أسرع بنسبة 20٪ من تطبيق JS. ومع ذلك ، لاحظ أن هذا الاختبار هو علامة
تجارية صغيرة . لا تعتمد كثيرا على نتائجها.
من أجل العثور على نتائج أكثر موثوقية لبحث أداء مشاريع AssemblyScript - أوصي بإلقاء نظرة على
هذه المعايير
وهذه .
باستخدام وحدة Wasm على صفحة ويب
دعنا نستخدم وحدة Wasm الخاصة بنا على صفحة الويب. نبدأ بإنشاء ملف
index.html
بالمحتويات التالية:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>AssemblyScript isPrime demo</title> </head> <body> <form id="prime-checker"> <label for="number">Enter a number to check if it is prime:</label> <input name="number" type="number" /> <button type="submit">Submit</button> </form> <p id="result"></p> <script src="demo.js"></script> </body> </html>
الآن قم بإنشاء ملف
demo.js
الذي يظهر
demo.js
أدناه. هناك
العديد من الطرق لتحميل وحدات WebAssembly. الأكثر كفاءة هو تجميع وتهيئة لهم في وضع التدفق باستخدام وظيفة
WebAssembly.instantiateStreaming . يرجى ملاحظة أننا سنحتاج إلى إعادة تعريف وظيفة
الإجهاض ، والتي تسمى إذا لم
يتم تنفيذ
عبارة ما .
(async () => { const importObject = { env: { abort(_msg, _file, line, column) { console.error("abort called at index.ts:" + line + ":" + column); } } }; const module = await WebAssembly.instantiateStreaming( fetch("build/optimized.wasm"), importObject ); const isPrime = module.instance.exports.isPrime; const result = document.querySelector("#result"); document.querySelector("#prime-checker").addEventListener("submit", event => { event.preventDefault(); result.innerText = ""; const number = event.target.elements.number.value; result.innerText = `${number} is ${isPrime(number) ? '' : 'not '}prime.`; }); })();
بعد ذلك ، قم بتثبيت حزمة
خادم ثابت . نحتاج إلى خادم نظرًا لأنه من أجل استخدام وظيفة
WebAssembly.instantiateStreaming
، يجب صيانة الوحدة النمطية باستخدام نوع MIME
application/wasm
.
npm install --save-dev static-server
أضف البرنامج النصي المناسب إلى
package.json
:
{ "scripts": { "serve-demo": "static-server" } }
الآن
npm run serve-demo
الأمر
npm run serve-demo
وافتح عنوان URL الخاص بالمضيف المحلي في المتصفح. إذا قمت بإدخال رقم معين في النموذج ، يمكنك معرفة ما إذا كان بسيطًا أم لا. الآن ، في تطوير AssemblyScript ، قطعنا شوطًا طويلاً من كتابة التعليمات البرمجية إلى استخدامه في Node.js وعلى صفحة ويب.
النتائج
WebAssembly ، وبالتالي AssemblyScript ، غير قادر على تسريع أي موقع بطريقة سحرية بطريقة أو بأخرى. لكن Wasm لم يكن مكلفاً بتسريع كل شيء على الإطلاق. هذه التقنية رائعة لأنها تفتح الطريق أمام الويب لأنواع جديدة من التطبيقات.
شيء مماثل يمكن أن يقال عن AssemblyScript. تعمل هذه التقنية على تسهيل الوصول إلى WebAssembly لعدد كبير من المطورين. يسمح ، عند إنشاء تعليمات برمجية بلغة قريبة من JavaScript ، باستخدام إمكانيات WebAssembly لحل المشكلات الحسابية المعقدة.
أعزائي القراء! كيف يمكنك تقييم احتمالات استخدام AssemblyScript في مشاريعك؟
