החלפת נתיב חם ב-JavaScript של האפליקציה שלך באמצעות WebAssembly

הוא מהיר באופן עקבי, יו

בגרסה הקודמת שלי מאמרים שדיברתי על האופן שבו WebAssembly מאפשרת להביא את הסביבה העסקית של הספרייה של C/C++ לאינטרנט. אפליקציה אחת עושה שימוש נרחב בספריות C/C++ הוא squoosh, שמאפשר לדחוס תמונות באמצעות מגוון של רכיבי קודק עברו מ-C++ ל-WebAssembly.

WebAssembly היא מכונה וירטואלית ברמה נמוכה שמריצה את הבייטקוד שמאוחסן ב-.wasm קבצים. קוד הבייט הזה מוקלד בצורה חזקה ומובנה בצורה כזאת שהוא יכול להדר ולבצע אופטימיזציה למערכת המארחת מהר הרבה יותר אפשר גם להפעיל JavaScript. WebAssembly מספקת סביבה להרצת קוד שימוש בארגז חול (sandboxing) ובהטמעה כבר מההתחלה.

מניסיוני, רוב הבעיות בביצועים באינטרנט נגרמות מאילוץ אבל מדי פעם, אפליקציה צריכה משימה יקרה מבחינה ממוחשבת שנמשכת הרבה זמן. WebAssembly יכול לעזור כאן.

הנתיב החם

ב-squoosh, כתבנו פונקציית JavaScript שמסובב את מאגר התמונות בכפולות של 90 מעלות. בזמן האפשרות OffscreenCanvas יכולה להיות אידיאלית עבור הוא לא נתמך בכל הדפדפנים שטירגטנו, באגים ב-Chrome.

הפונקציה הזו עוברת באיטרציות על כל פיקסל של תמונת קלט ומעתיקה אותה מיקום שונה בתמונת הפלט כדי להשיג סיבוב. ל-4094 פיקסלים על ברזולוציה של 4096 פיקסלים (16 מגה-פיקסלים), נדרשות יותר מ-16 מיליון איטרציות של בלוק קוד פנימי, שזה מה שאנחנו קוראים לו 'נתיב חם'. למרות שהיא די גדולה מספר איטרציות, שניים מתוך שלושה דפדפנים שבדקנו, מסיימים את המשימה ב-2 שניות או פחות. משך זמן מקובל לאינטראקציה מהסוג הזה.

for (let d2 = d2Start; d2 >= 0 && d2 < d2Limit; d2 += d2Advance) {
    for (let d1 = d1Start; d1 >= 0 && d1 < d1Limit; d1 += d1Advance) {
    const in_idx = ((d1 * d1Multiplier) + (d2 * d2Multiplier));
    outBuffer[i] = inBuffer[in_idx];
    i += 1;
    }
}

דפדפן אחד מנצל יותר מ-8 שניות. הדרך שבה דפדפנים מבצעים אופטימיזציה של JavaScript הוא מסובך מאוד, ומנועים שונים מבצעים אופטימיזציה לדברים שונים. בחלקם מתבצעת אופטימיזציה לביצוע גולמי, וחלקם מבצעים אופטימיזציה לאינטראקציה עם ה-DOM. לחשבון במקרה הזה, מצאנו נתיב שלא עבר אופטימיזציה בדפדפן אחד.

לעומת זאת, WebAssembly בנויה סביב מהירות הביצוע הגולמית. ככה. אם אנחנו רוצים ביצועים מהירים וצפויים בדפדפנים שונים לקוד כמו זה, אפשר להיעזר ב-WebAssembly.

WebAssembly לביצועים צפויים

באופן כללי, ביצועי השיאים של JavaScript ו-WebAssembly זהים. עם זאת, ב-JavaScript ניתן להגיע לביצועים האלה רק ב"נתיב מהיר", ולרוב קשה להישאר ב"נתיב המהיר" הזה. אחד היתרונות המרכזיים המוצרים של WebAssembly מספקים ביצועים צפויים, גם בדפדפנים שונים. המחמירה והארכיטקטורה ברמה נמוכה מאפשרת למהדר לחזק מבטיחה שיהיה צורך לבצע אופטימיזציה של קוד WebAssembly רק פעם אחת, להשתמש תמיד ב'נתיב המהיר'.

כתיבה ל-WebAssembly

בעבר לקחנו ספריות C/C++ והוספנו אותן ל-WebAssembly כדי להשתמש פונקציונליות באינטרנט. לא ממש נגענו בקוד של הספריות, בדיוק כתבו כמויות קטנות של קוד C/C++ כדי ליצור את הגשר בין הדפדפן ועל הספרייה. הפעם המוטיבציה שלנו שונה: אנחנו רוצים לכתוב משהו מאפס עם WebAssembly, כדי שנוכל להשתמש ואת היתרונות של WebAssembly.

ארכיטקטורת WebAssembly

אם כותבים עבור WebAssembly, כדאי להבין קצת יותר טוב על הנושא מה זה WebAssembly בפועל.

כדי לצטט את WebAssembly.org:

כשיוצרים קטע של C או קוד Rust ל-WebAssembly, מקבלים .wasm שמכיל הצהרת מודול. ההצהרה הזו כוללת רשימה של ייבוא שהמודול מצפה מהסביבה שלו, רשימה של פעולות ייצוא הופך לזמין למארח (פונקציות, קבועים, מקטעי זיכרון) כמובן את ההוראות הבינאריות בפועל לפונקציות הכלולות.

משהו שלא הבנתי עד שבדקתי את זה: WebAssembly "מכונה וירטואלית מבוססת סטאק" לא נשמר בקטע של הזיכרון שבו משתמשים המודולים של WebAssembly. הסטאק הוא פנימי לגמרי ל-VM לא נגיש למפתחי אתרים (למעט דרך כלי פיתוח). לכן, ייתכן כדי לכתוב מודולים של WebAssembly שלא זקוקים לזיכרון נוסף בכלל, להשתמש רק בסטאק הפנימי של ה-VM.

במקרה שלנו נצטרך להשתמש בזיכרון נוסף כדי לאפשר גישה שרירותית לפיקסלים של התמונה שלנו וליצור גרסה מסובבת של התמונה הזו. הדבר למה מיועד WebAssembly.Memory.

ניהול הזיכרון

בדרך כלל, אם תשתמשו בזיכרון נוסף, תגלו שצריך לנהל את הזיכרון הזה. אילו חלקים מהזיכרון נמצאים בשימוש? אילו בחינם? למשל, בגרסה C, הפונקציה malloc(n) מוצאת מקום בזיכרון. של n בייטים ברצף. פונקציות מהסוג הזה נקראות גם "מקצים". כמובן שהיישום של המקצה בשימוש חייב להיכלל ב WebAssembly ולהגדיל את הקובץ. הגודל והביצועים האלה יכולות להשתנות באופן משמעותי בהתאם לפונקציות האלה נעשה בו שימוש באלגוריתם, ולכן שפות רבות מציעות יישומים מרובים לבחירה ('dmalloc', 'emmalloc', 'wee_alloc' וכו').

במקרה שלנו אנחנו יודעים את המידות של תמונת הקלט (וכתוצאה מכך של תמונת הפלט) לפני שאנחנו מפעילים את מודול WebAssembly. כאן יש לנו זיהינו הזדמנות: בדרך כלל, נעביר את מאגר הנתונים הזמני של ה-RGBA לפונקציה WebAssembly ולהחזיר את התמונה המסובבת עם ערך מסוים. כדי ליצור את הערך המוחזר, נצטרך להשתמש במקצה. אבל מכיוון שאנחנו יודעים את כמות הזיכרון הכוללת שנדרשת (פי שניים מגודל הקלט תמונה, פעם אחת לקלט ופעם אחת לפלט), אנחנו יכולים להכניס את תמונת הקלט זיכרון WebAssembly באמצעות JavaScript, מריצים את המודול WebAssembly כדי ליצור תמונה שנייה מסובבת, ואז להשתמש ב-JavaScript כדי לקרוא את התוצאה. אנחנו יכולים לקבל בלי להשתמש בכלל בניהול זיכרון!

יופי של בחירה

אם בדקתם את פונקציית JavaScript המקורית שאנחנו רוצים לבצע ב-WebAssembly, אפשר לראות שמדובר בפעולה חישובית בלבד ללא ממשקי API ספציפיים ל-JavaScript. לכן, החווייה צריכה להיות ישרה למדי להעביר את הקוד הזה לכל שפה. בדקנו 3 שפות שונות שעברו הידור ל-WebAssembly: C/C++, Rust ו-AssemblyScript. השאלה היחידה התשובה לשאלה שלנו בכל אחת מהשפות היא: איך אנחנו ניגשים לזיכרון הגולמי מבלי להשתמש בפונקציות של ניהול זיכרון?

C ו-Emscripten

Emscripten הוא מהדר C עבור יעד WebAssembly. המטרה של Emscripten היא משמש כתחליף למהדרים ידועים (כמו GCC או clang) והוא תואם בעיקר לסימונים. זה חלק מרכזי במשימה של Emscripten מאחר שהוא רוצה להפוך את הקוד הקיים של C ו-C++ ל-WebAssembly הוא קל יותר ככל האפשר.

גישה לזיכרון גולמי היא מעצם טבעה של C, וסמנים קיימים בשביל סיבה:

uint8_t* ptr = (uint8_t*)0x124;
ptr[0] = 0xFF;

כאן אנחנו הופכים את המספר 0x124 למצב מצביע (לא חתום) ב-8 ביט מספרים שלמים (או בייטים). הפעולה הזו הופכת בפועל את המשתנה ptr למערך החל מכתובת הזיכרון 0x124, שבעזרתו נוכל להשתמש כמו כל מערך אחר, שמאפשרים לנו לגשת לבייטים נפרדים לקריאה ולכתיבה. במקרה שלנו, מסתכלים במאגר נתונים זמני של RGBA של תמונה שאנחנו רוצים להזמין מחדש כדי להשיג בסבב. כדי להזיז פיקסל, עלינו להעביר 4 בייטים עוקבים בו-זמנית (בייט אחד לכל ערוץ: R, G, B ו-A). כדי להקל על המודל, אנחנו יכולים ליצור מערך של מספרים שלמים לא חתומים בפורמט 32 ביט. באופן מקובל, תמונת הקלט שלנו תתחיל בכתובת 4, ותמונת הפלט תתחיל מיד אחרי קלט התמונה מסתיים:

int bpp = 4;
int imageSize = inputWidth * inputHeight * bpp;
uint32_t* inBuffer = (uint32_t*) 4;
uint32_t* outBuffer = (uint32_t*) (inBuffer + imageSize);

for (int d2 = d2Start; d2 >= 0 && d2 < d2Limit; d2 += d2Advance) {
    for (int d1 = d1Start; d1 >= 0 && d1 < d1Limit; d1 += d1Advance) {
    int in_idx = ((d1 * d1Multiplier) + (d2 * d2Multiplier));
    outBuffer[i] = inBuffer[in_idx];
    i += 1;
    }
}

אחרי שמעבירים את פונקציית JavaScript כולה ל-C, אנחנו יכולים להדר את קובץ ה-C עם emcc:

$ emcc -O3 -s ALLOW_MEMORY_GROWTH=1 -o c.js rotate.c

כמו תמיד, emscripten יוצר קובץ קוד הדבקה שנקרא c.js ומודול Wam שנקרא c.wasm. שימו לב שמודול Wam מריץ gzip ל-260 בייטים בלבד, קוד הדבק הוא כ-3.5KB אחרי gzip. אחרי קצת כישורים, הצלחנו לוותר את קוד החיבור וליצור מודולים של WebAssembly באמצעות ממשקי ה-API של וניל. בדרך כלל הדבר אפשרי ב-Emscripten, כל עוד לא משתמשים באפשרות מהספרייה הרגילה של C.

Rust

Rust היא שפת תכנות חדשה ומודרנית עם מערכת סוגים עשירים, ללא סביבת זמן ריצה ומודל בעלות שמבטיח הגנה על הזיכרון ובטיחות השרשורים. חלודה תומך גם ב-WebAssembly כתכונת ליבה, וצוות Rust תרמה הרבה כלים מצוינים לסביבה העסקית של WebAssembly.

אחד מהכלים האלה הוא wasm-pack, של קבוצת העבודה של חלודה. wasm-pack לוקח את הקוד והופך אותו למודול ידידותי לאינטרנט שפועל חדשני עם חבילות כמו Webpack. wasm-pack הוא במיוחד נוח, אבל כרגע פועל רק עבור חלודה. הקבוצה לשקול להוסיף תמיכה בשפות אחרות לטירגוט WebAssembly.

ב-Rust, פרוסות הן מערכים שנמצאים ב-C. ובדיוק כמו בשפת C, אנחנו צריכים ליצור פרוסות שבהן נעשה שימוש בכתובות ההתחלה שלנו. זה נוגד את מודל הבטיחות של הזיכרון שחלודה אוכפת, ולכן כדי שנוכל להשתמש במילת המפתח unsafe, שמאפשרים לנו לכתוב קוד שלא תואם למודל הזה.

let imageSize = (inputWidth * inputHeight) as usize;
let inBuffer: &mut [u32];
let outBuffer: &mut [u32];
unsafe {
    inBuffer = slice::from_raw_parts_mut::<u32>(4 as *mut u32, imageSize);
    outBuffer = slice::from_raw_parts_mut::<u32>((imageSize * 4 + 4) as *mut u32, imageSize);
}

for d2 in 0..d2Limit {
    for d1 in 0..d1Limit {
    let in_idx = (d1Start + d1 * d1Advance) * d1Multiplier + (d2Start + d2 * d2Advance) * d2Multiplier;
    outBuffer[i as usize] = inBuffer[in_idx as usize];
    i += 1;
    }
}

מתבצע הידור של קובצי חלודה באמצעות

$ wasm-pack build

מניב מודול Wam בנפח 7.6KB עם כ-100 בייטים של קוד הדבקה (שני המקרים אחרי gzip).

AssemblyScript

AssemblyScript הוא די פרויקט צעיר שמטרתו להיות מהדר מסוג TypeScript-to-WebAssembly. זו עם זאת, חשוב לציין שהוא לא צורך רק TypeScript. AssemblyScript משתמש באותו תחביר כמו TypeScript, אבל יוצא משימוש לספרייה שלהם. הספרייה הרגילה משמשת כמודלים ליכולות של WebAssembly. כלומר, לא ניתן פשוט להרכיב סוג סקריפט כלשהו שאתם נמצאים בו ל-WebAssembly, אבל המשמעות היא שלא צריך ללמוד שפת תכנות לכתיבת WebAssembly!

    for (let d2 = d2Start; d2 >= 0 && d2 < d2Limit; d2 += d2Advance) {
      for (let d1 = d1Start; d1 >= 0 && d1 < d1Limit; d1 += d1Advance) {
        let in_idx = ((d1 * d1Multiplier) + (d2 * d2Multiplier));
        store<u32>(offset + i * 4 + 4, load<u32>(in_idx * 4 + 4));
        i += 1;
      }
    }

בהתחשב בסוג פני השטח הקטן של הפונקציה rotate(), לנייד את הקוד הזה בקלות ל-AssemblyScript. הפונקציות load<T>(ptr: usize) ו-store<T>(ptr: usize, value: T) מסופקות על ידי AssemblyScript כדי לגשת לזיכרון הגולמי. כדי להדר את קובץ AssemblyScript, צריך רק להתקין את חבילת ה-NPM AssemblyScript/assemblyscript ולהפעיל

$ asc rotate.ts -b assemblyscript.wasm --validate -O3

מערכת AssemblyScript תספק לנו מודול Wasm בנפח של כ-300 בייטים וללא קוד דבק. המודול עובד רק עם ממשקי API של וניל WebAssembly.

זיהוי משפטי של WebAssembly

7.6KB של Rust מפתיעים את הגודל בהשוואה לשתי השפות האחרות. יש יש כמה כלים בסביבה העסקית של WebAssembly שיכולים לעזור לכם לנתח קובצי WebAssembly (ללא קשר לשפה שבה נוצרו) וגם לספר לכם מה קורה, וגם לעזור לכם לשפר את המצב.

טוויגי

Twiggy הוא כלי נוסף מ-Rust צוות WebAssembly שולף כמה נתונים מועילים מ-WebAssembly של מודל טרנספורמר. הכלי לא ספציפי לחלודה והוא מאפשר לבדוק דברים כמו בתרשים הקריאה של המודול, למצוא חלקים שאינם בשימוש או מיותרים אילו קטעים תורמים לגודל הקובץ הכולל של המודול. את השיטה השנייה אפשר לבצע באמצעות הפקודה top של Twiggy:

$ twiggy top rotate_bg.wasm
צילום מסך של התקנת Twiggy

במקרה זה אנחנו יכולים לראות שרוב גודל הקובץ נובע מקצה לקצה. זה היה מפתיע, כי הקוד שלנו לא משתמש בהקצאות דינמיות. גורם חשוב נוסף הוא "שמות הפונקציות". תת-סעיף.

וואאם-סטריפ

wasm-strip הוא כלי מ-WebAssembly Binary Toolkit, או בקיצור Wabt. הוא מכיל שני כלים שמאפשרים לבדוק מודולים של WebAssembly ולשנות אותם. wasm2wat הוא כלי פירוק שהופך מודול Wam בינארי בפורמט קריא לאנשים. קובץ ה-Wabt מכיל גם wat2wasm, שמאפשר להפנות לחזור לפורמט קריא לאנשים למודול Wam בינארי. אומנם השתמשנו שני הכלים המשלימים האלה מאפשרים לבדוק את קובצי ה-WebAssembly שלנו, wasm-strip כדי להיות המועילים ביותר. הקטעים המיותרים יוסרו על ידי wasm-strip ואת המטא-נתונים ממודול WebAssembly:

$ wasm-strip rotate_bg.wasm

כך גודל הקובץ של מודול החלודה יקטן מ-7.5KB ל-6.6KB (לאחר gzip).

wasm-opt

wasm-opt הוא כלי של Binaryen. הוא לוקח מודול WebAssembly ומנסה לבצע אופטימיזציה שלו גם מבחינת גודל וגם על סמך קוד בייט בלבד. כלים מסוימים, כמו Emscripten כבר מופעלים את הכלי הזה, ויש כאלה שלא. בדרך כלל כדאי לנסות ולחסוך בייטים נוספים באמצעות הכלים האלה.

wasm-opt -O3 -o rotate_bg_opt.wasm rotate_bg.wasm

בעזרת wasm-opt אנחנו יכולים לגזור עוד כמה בייטים כדי להשאיר 6.2KB אחרי gzip.

#![no_std]

לאחר התייעצות ומחקר, שכתבנו את קוד החלודה שלנו בלי להשתמש הספרייה הרגילה של Rust באמצעות #![no_std] . הפעולה הזו גם משביתה לחלוטין את הקצאות הזיכרון הדינמיות, ומסירים את את הקוד המוקצה מהמודול שלנו. מתבצעת הידור של קובץ ה-Rust הזה עם

$ rustc --target=wasm32-unknown-unknown -C opt-level=3 -o rust.wasm rotate.rs

הניב מודול Wam בנפח של 1.6KB אחרי wasm-opt, wasm-strip ו-gzip. אומנם עדיין גדול יותר מהמודולים שנוצרו על ידי C ו-AssemblyScript, הוא קטן מספיק כדי להיחשב כמשקל קל.

ביצועים

לפני שאנחנו מסיקים מסקנות על סמך גודל הקובץ בלבד – התחלנו בתהליך הזה כדי לבצע אופטימיזציה של הביצועים, ולא את גודל הקובץ. איך מדדנו ביצועים מה היו התוצאות?

איך מתבצע ההשוואה לשוק

למרות ש-WebAssembly הוא פורמט בייטקוד ברמה נמוכה, עדיין צריך לשלוח אותו באמצעות מהדר כדי ליצור קוד מכונה ספציפי למארח. בדיוק כמו ב-JavaScript, המהדר פועל במספר שלבים. בפשטות: השלב הראשון מהר יותר בהידור, אבל נוטה ליצור קוד איטי יותר. ברגע שהמודול מתחיל פועל, הדפדפן מזהה את החלקים שנמצאים בשימוש לעיתים קרובות ושולח אותם באמצעות מהדר אופטימיזציה יותר אבל איטי יותר.

התרחיש לדוגמה שלנו מעניין בכך שהקוד לסיבוב תמונה ישמש פעם אחת, אולי פעמיים. כך שברוב המכריע של המקרים לעולם לא נקבל היתרונות של המהדר לאופטימיזציה. חשוב לזכור זאת כאשר השוואה לשוק. הרצת מודולים של WebAssembly 10,000 פעמים בלולאה תספק מתוצאות בלתי מציאותיות. כדי לקבל מספרים ריאליים, צריך להפעיל את המודול פעם אחת לקבל החלטות על סמך המספרים מאותה נקודה.

השוואת ביצועים

השוואת מהירות לפי שפה
השוואת מהירות לכל דפדפן

שני התרשימים האלה מייצגים צפיות שונות באותם נתונים. בגרף הראשון, בהשוואה לכל דפדפן, בתרשים השני אנחנו משווים לפי שפה. נשמח אם תוכלו לסמן בכוכב שימו לב שבחרתי טווח זמן לוגריתמי. חשוב גם שכל נקודות ההשוואה השתמשו באותה תמונת בדיקה בגודל 16 מגה-פיקסל ובאותו מארח למעט דפדפן אחד, שלא ניתן להפעיל באותו מחשב.

מבלי לנתח את התרשימים יותר מדי, ברור שפתרנו את הבעיה המקורית בעיית ביצועים: כל המודולים של WebAssembly פועלים תוך כ-500 אלפיות השנייה. הזה מאשר את מה שהסברנו בהתחלה: WebAssembly מספקת נתונים חזויים או של ביצועים. לא משנה באיזו שפה אנו בוחרים, ההבדלים בין הדפדפנים ושפות הוא מינימלי. ליתר דיוק: סטיית התקן של JavaScript בכל הדפדפנים היא בערך 400 אלפיות השנייה, בעוד שסטיית התקן של כל מודולים של WebAssembly בכל הדפדפנים הם באורך של כ-80 אלפיות שנייה.

השקעת מאמץ

מדד נוסף הוא כמות המאמץ שהשקענו כדי ליצור ולשלב את מודול WebAssembly שלנו ל-squoosh. קשה להקצות ערך מספרי ל לכן לא אצור גרפים, אבל ארצה לדעת כמה דברים נקודה:

AssemblyScript היה חלק בצורה חלקה. היא מאפשרת לא רק להשתמש ב-TypeScript כדי לכתוב WebAssembly, מה שמאפשר לעמיתים שלי לבצע בדיקת קוד בקלות, אבל זה גם מייצרת מודולים של WebAssembly ללא דבק שהם קטנים מאוד ומתאימים או של ביצועים. הכלים בסביבה העסקית של TypeScript, כמו יפה יותר ו-tslint, כנראה פשוט יפעלו.

גם חלודה בשילוב עם wasm-pack היא נוחה מאוד, אבל מעולה בפרויקטים גדולים יותר של WebAssembly היו קישורים, וניהול הזיכרון הדרושים. היינו צריכים להתנתק קצת מהדרך השמחה כדי להשיג תחרות גודל הקובץ.

C ו-Emscripten יצרו מודול WebAssembly קטן מאוד ועם ביצועים גבוהים. מחוץ לקופסה, אבל בלי אומץ להיכנס לקוד דבק ולהפחית אותו את הפריטים החיוניים הגודל הכולל (מודול WebAssembly + קוד דבק) מגיע להיות די גדול.

סיכום

אז באיזו שפה להשתמש אם יש לכם נתיב חם של JS ואתם רוצים לבצע אותו? מהיר או עקבי יותר עם WebAssembly. כמו תמיד עם ביצועים התשובה היא: תלוי. מה שלחנו?

תרשים השוואה

השוואת גודל המודול / שילוב הביצועים של השפות השונות שבה השתמשנו, הבחירה הטובה ביותר היא C או AssemblyScript. החלטנו לשלוח את Rust. יש יש כמה סיבות להחלטה הזו: כל רכיבי הקודק שנשלחו ב-Squoosh עד עכשיו עוברים הידור באמצעות Emscripten. רצינו להרחיב את הידע שלנו על בסביבה העסקית של WebAssembly ובשפה אחרת בייצור. AssemblyScript הוא חלופה חזקה, אבל הפרויקט צעיר יחסית המהדר לא בוגר כמו המהדר של Rust.

ההבדל בגודל הקובץ בין Rust לבין השפות האחרות נראה די קיצוני בתרשים הפיזור, זה לא כזה דבר גדול במציאות: טעינה בנפח של 500B או 1.6KB אפילו יותר מ-2G נמשכת פחות מ-1/10 שנייה. וגם חלודה תסגור בקרוב את הפער מבחינת גודל המודול.

מבחינת ביצועים בזמן ריצה, ל-Rust יש ממוצע מהיר יותר בדפדפנים שונים מאשר AssemblyScript. במיוחד בפרויקטים גדולים יותר, יש יותר סיכוי ל-Rust יוצרת קוד מהיר יותר בלי שיהיה צורך באופטימיזציות ידניות של קוד. אבל לפעמים לא אמורה למנוע ממך להשתמש במה שנוח לך.

עם זאת, AssemblyScript היה תגלית מעולה. הוא מאפשר כניסה מפתחים לייצר מודולים של WebAssembly בלי שיצטרכו ללמוד בשפת היעד. צוות AssemblyScript פועל במהירות ופעיל עובדים על שיפור 'צרור הכלים' שלהם. אנחנו בהחלט נעקוב AssemblyScript בעתיד.

עדכון: חלודה

אחרי פרסום המאמר, ניק פיצג'רלד מצוות Rust הפנה אותנו אל הספר המעולה שלו, Rust Wasm, קטע שעוסק באופטימיזציה של גודל קובץ. ביצוע הפעולות הבאות: הוראות להתאמה אישית (בעיקר פעילות של אופטימיזציה של זמן קישור טיפול בפחדות) אפשר לנו לכתוב קוד חלודה "רגיל" ולחזור להשתמש Cargo (npm של חלודה) בלי להגדיל את גודל הקובץ. מודול החלודה מסתיים עד 370B אחרי gzip. לפרטים נוספים, אפשר לעיין ביחס גובה-רוחב שפתחתי ב-Squoosh.

תודה מיוחדת לאשלי ויליאמס, סטיב קלבניק, ניק פיצג'רלד ומקס גריי על כל העזרה שלהם במסע הזה.