סקירה כללית על סביבת זמן הריצה של V8

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

בעבר, Apps Script הופעל על ידי Rhino, מתורגמן JavaScript של Mozilla. ‫Rhino סיפק דרך נוחה ל-Apps Script להריץ סקריפטים של מפתחים, אבל הוא גם קשר את Apps Script לגרסה ספציפית של JavaScript‏ (ES5). מפתחי Apps Script לא יכולים להשתמש בתחביר ובמאפיינים מודרניים יותר של JavaScript בסקריפטים שמשתמשים בסביבת זמן הריצה של Rhino.

כדי לפתור את הבעיה הזו, Apps Script נתמך עכשיו על ידי זמן הריצה V8 שמפעיל את Chrome ו-Node.js. אתם יכולים להעביר סקריפטים קיימים ל-V8 כדי ליהנות מהתחביר והתכונות המודרניים של JavaScript.

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

תכונות של סביבת זמן הריצה V8

סקריפטים שמשתמשים בסביבת ההרצה של V8 יכולים ליהנות מהתכונות הבאות:

תחביר ECMAScript מודרני

אתם יכולים להשתמש בתחביר מודרני של ECMAScript בסקריפטים שמופעלים על ידי זמן הריצה של V8. התחביר הזה כולל את let, את const ועוד הרבה תכונות פופולריות.

במאמר דוגמאות לתחביר V8 מופיעה רשימה קצרה של שיפורים פופולריים בתחביר שאפשר לבצע באמצעות סביבת ההרצה של V8.

זיהוי פונקציות משופר

השיפורים בזיהוי פונקציות ב-Apps Script חלים על סקריפטים שמשתמשים ב-V8. סביבת זמן הריצה החדשה מזהה את פורמטי ההגדרה הבאים של פונקציות:

      function normalFunction() {}
      async function asyncFunction() {}
      function* generatorFunction() {}

      var varFunction = function() {}
      let letFunction = function() {}
      const constFunction = function() {}

      var namedVarFunction = function alternateNameVarFunction() {}
      let namedLetFunction = function alternateNameLetFunction() {}
      const namedConstFunction = function alternateNameConstFunction() {}

      var varAsyncFunction = async function() {}
      let letAsyncFunction = async function() {}
      const constAsyncFunction = async function() {}

      var namedVarAsyncFunction = async function alternateNameVarAsyncFunction() {}
      let namedLetAsyncFunction = async function alternateNameLetAsyncFunction() {}
      const namedConstAsyncFunction = async function alternateNameConstAsyncFunction() {}

      var varGeneratorFunction = function*() {}
      let letGeneratorFunction = function*() {}
      const constGeneratorFunction = function*() {}

      var namedVarGeneratorFunction = function* alternateNameVarGeneratorFunction() {}
      let namedLetGeneratorFunction = function* alternateNameLetGeneratorFunction() {}
      const namedConstGeneratorFunction = function* alternateNameConstGeneratorFunction() {}

      var varLambda = () => {}
      let letLambda = () => {}
      const constLambda = () => {}

      var varAsyncLambda = async () => {}
      let letAsyncLambda = async () => {}
      const constAsyncLambda = async () => {}

הפעלת שיטות של אובייקט Call מטריגרים ומקריאות חוזרות

סקריפטים שמשתמשים ב-V8 יכולים להפעיל שיטות של אובייקטים ושיטות סטטיות של מחלקות ממקומות שבהם כבר הייתה לכם אפשרות להפעיל שיטות של ספריות. המקומות האלה כוללים את:

בדוגמה הבאה של V8 אפשר לראות איך משתמשים בשיטות של אובייקטים כשיוצרים פריטים בתפריט ב-Google Sheets:

function onOpen() {
  const ui = SpreadsheetApp.getUi(); // Or DocumentApp, SlidesApp, or FormApp.
  ui.createMenu('Custom Menu')
      .addItem('First item', 'menu.item1')
      .addSeparator()
      .addSubMenu(ui.createMenu('Sub-menu')
          .addItem('Second item', 'menu.item2'))
      .addToUi();
}

const menu = {
  item1: function() {
    SpreadsheetApp.getUi().alert('You clicked: First item');
  },
  item2: function() {
    SpreadsheetApp.getUi().alert('You clicked: Second item');
  }
}

צפייה ביומנים

ב-Apps Script יש שני שירותי רישום ביומן: השירות Logger והסיווג console. שני השירותים האלה כותבים יומנים לאותו שירות Stackdriver Logging.

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

הצגת הביצועים

כדי לראות את היסטוריית ההרצה של הסקריפט, פותחים את פרויקט Apps Script ובצד ימין לוחצים על הפעלות .

דוגמאות לתחביר ב-V8

בהמשך מופיעה רשימה קצרה של תכונות תחביריות פופולריות שזמינות לסקריפטים באמצעות סביבת ההרצה של V8.

let וגם const

מילות המפתח let ו-const מאפשרות להגדיר משתנים מקומיים בהיקף של בלוק וקבועים בהיקף של בלוק, בהתאמה.

// V8 runtime
let s = "hello";
if (s === "hello") {
  s = "world";
  console.log(s);  // Prints "world"
}
console.log(s);  // Prints "hello"

const N = 100;
N = 5; // Results in TypeError
      

פונקציות חץ

פונקציות חץ מספקות דרך קומפקטית להגדרת פונקציות בתוך ביטויים.

// Rhino runtime
function square(x) {
  return x * x;
}

console.log(square(5));  // Outputs 25
      
// V8 runtime
const square = x => x * x;
console.log(square(5));  // Outputs 25

// Outputs [1, 4, 9]
console.log([1, 2, 3].map(x => x * x));
      

שיעורים

Classes מספקות אמצעי לארגון קוד באופן מושגי באמצעות ירושה. מחלקות ב-V8 הן בעיקר תחביר נוח לשימוש בירושה מבוססת-אב טיפוס של JavaScript.

// V8 runtime
class Rectangle {
  constructor(width, height) { // class constructor
    this.width = width;
    this.height = height;
  }

  logToConsole() { // class method
    console.log(`Rectangle(width=${this.width}, height=${this.height})`);
  }
}

const r = new Rectangle(10, 20);
r.logToConsole();  // Outputs Rectangle(width=10, height=20)
      

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

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

// Rhino runtime
var data = {a: 12, b: false, c: 'blue'};
var a = data.a;
var c = data.c;
console.log(a, c);  // Outputs 12 "blue"

var a = [1, 2, 3];
var x = a[0];
var y = a[1];
var z = a[2];
console.log(x, y, z);  // Outputs 1 2 3
      
// V8 runtime
const data = {a: 12, b: false, c: 'blue'};
const {a, c} = data;
console.log(a, c);  // Outputs 12 "blue"


const array = [1, 2, 3];
const [x, y, z] = array;
console.log(x, y, z);  // Outputs 1 2 3


      

תבניות מילוליות

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

// Rhino runtime
var name =
  'Hi ' + first + ' ' + last + '.';
var url =
  'http://localhost:3000/api/messages/'
  + id;
      
// V8 runtime
const name = `Hi ${first} ${last}.`;
const url =
  `http://localhost:3000/api/messages/${id}`;


      

פרמטרים שמוגדרים כברירת מחדל

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

// Rhino runtime
function hello(greeting, name) {
    greeting = greeting || "hello";
    name = name || "world";
    console.log(
        greeting + " " + name + "!");
}

hello();  // Outputs "hello world!"
      
// V8 runtime
const hello =
  function(greeting="hello", name="world") {
      console.log(
        greeting + " " + name + "!");
  }

hello();  // Outputs "hello world!"

      

מחרוזות מרובות שורות

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

// Rhino runtime
var multiline = "This string is sort of\n"
+ "like a multi-line string,\n"
+ "but it's not really one.";
      
// V8 runtime
const multiline = `This on the other hand,
actually is a multi-line string,
thanks to JavaScript ES6`;
      

מגבלות של סביבת ההרצה V8

סביבת זמן הריצה של Apps Script V8 היא לא סביבת Node.js או דפדפן סטנדרטית. זה עלול לגרום לבעיות תאימות כשקוראים לספריות של צד שלישי או כשמתאימים דוגמאות קוד מסביבות JavaScript אחרות.

ממשקי API לא זמינים

ממשקי ה-API הבאים של JavaScript רגיל לא זמינים בזמן הריצה של V8 ב-Apps Script:

  • טיימרים: setTimeout, setInterval, clearTimeout, clearInterval
  • ערוצים: ReadableStream, WritableStream, TextEncoder, TextDecoder
  • Web APIs: fetch, FormData, File, Blob, URL, URLSearchParams, DOMException, atob, btoa
  • Crypto: crypto, SubtleCrypto
  • אובייקטים גלובליים: window, ‏ navigator, ‏ performance, ‏ process (Node.js)

אפשר להשתמש בממשקי Apps Script API הבאים כחלופות:

לפעמים אפשר להשתמש ב-polyfill עבור ממשקי API שאין להם חלופה ב-Apps Script, כמו TextEncoder. ‫Polyfill היא ספריה שמשכפלת פונקציונליות של API שלא זמינה כברירת מחדל בסביבת זמן הריצה. לפני שמשתמשים ב-polyfill, צריך לוודא שהוא תואם לסביבת ההרצה של V8 ב-Apps Script.

מגבלות אסינכרוניות

סביבת זמן הריצה V8 תומכת בתחביר async ו-await ובאובייקט Promise. עם זאת, סביבת זמן הריצה של Apps Script היא סינכרונית באופן בסיסי.

  • משימות קטנות (נתמכות): סביבת זמן הריצה מעבדת את תור המשימות הקטנות (שבו מתרחשים קריאות חוזרות של Promise.then ופתרונות של await) אחרי שערמת הקריאות הנוכחית מתרוקנת.
  • משימות מאקרו (לא נתמכות): ב-Apps Script אין לולאת אירועים רגילה למשימות מאקרו. פונקציות כמו setTimeout ו-setInterval לא זמינות.
  • WebAssembly Exception: ה-API של WebAssembly הוא התכונה המובנית היחידה שפועלת באופן לא חוסם בסביבת זמן הריצה, ומאפשרת דפוסי קומפילציה אסינכרוניים ספציפיים (WebAssembly.instantiate).

כל פעולות הקלט/פלט (I/O), כמו UrlFetchApp.fetch, הן פעולות חסימה. כדי להשיג בקשות רשת מקבילות, משתמשים ב-UrlFetchApp.fetchAll.

מגבלות על כיתות

לסביבת זמן הריצה V8 יש מגבלות ספציפיות לגבי תכונות מודרניות של מחלקות ES6+:

  • שדות פרטיים: שדות פרטיים של מחלקה (לדוגמה, #field) לא נתמכים וגורמים לשגיאות בניתוח. כדאי להשתמש בסגירות או ב-WeakMap כדי להשיג אנקפסולציה אמיתית.
  • שדות סטטיים: הצהרות ישירות על שדות סטטיים בגוף המחלקה (לדוגמה, static count = 0;) לא נתמכות. מקצים מאפיינים סטטיים לכיתה אחרי ההגדרה שלה (לדוגמה, MyClass.count = 0;).

מגבלות המודול

  • ES6 Modules: סביבת ההרצה של V8 לא תומכת ב-ES6 Modules‏ (import / export). כדי להשתמש בספריות, צריך להשתמש ב מנגנון הספריות של Apps Script או לארוז את הקוד ואת התלויות שלו בקובץ סקריפט יחיד. (Issue Tracker)
  • סדר ההרצה של הקובץ: כל קובצי הסקריפט בפרויקט מורצים בהיקף גלובלי. מומלץ להימנע מקוד ברמה העליונה עם תופעות לוואי, ולהקפיד להגדיר פונקציות ומחלקות לפני שמשתמשים בהן בקבצים. אם יש יחסי תלות בין הקבצים, צריך לסדר אותם באופן מפורש בעורך.

הפעלת סביבת זמן הריצה V8

אם סקריפט משתמש בסביבת זמן הריצה של Rhino, אפשר להעביר אותו ל-V8 באופן הבא:

  1. פותחים את פרויקט Apps Script.
  2. בצד ימין, לוחצים על הגדרות הפרויקט .
  3. מסמנים את תיבת הסימון הפעלה של 'סביבת זמן הריצה' של Chrome V8.

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

  1. פותחים את פרויקט Apps Script.
  2. בצד ימין, לוחצים על הגדרות הפרויקט .
  3. מסמנים את התיבה הצגת קובץ המניפסט 'appsscript.json' בעורך.
  4. בצד ימין, לוחצים על עריכה > appsscript.json.
  5. בקובץ המניפסט appsscript.json, מגדירים את השדה runtimeVersion לערך V8.
  6. למעלה, לוחצים על שמירת הפרויקט .

במאמר העברת סקריפטים ל-V8 מוסבר על שלבים נוספים שצריך לבצע כדי לוודא שהסקריפט יפעל בצורה תקינה באמצעות V8.

הפעלת סביבת זמן הריצה של Rhino

אם הסקריפט שלכם משתמש ב-V8 ואתם רוצים להעביר אותו לשימוש בסביבת ההרצה המקורית של Rhino, אתם צריכים לעשות את הפעולות הבאות:

  1. פותחים את פרויקט Apps Script.
  2. בצד ימין, לוחצים על הגדרות הפרויקט .
  3. מבטלים את הסימון בתיבת הסימון הפעלת סביבת זמן הריצה של Chrome V8.

אפשר גם לערוך את קובץ המניפסט של הסקריפט:

  1. פותחים את פרויקט Apps Script.
  2. בצד ימין, לוחצים על הגדרות הפרויקט .
  3. מסמנים את התיבה הצגת קובץ המניפסט 'appsscript.json' בעורך.
  4. בצד ימין, לוחצים על עריכה > appsscript.json.
  5. בקובץ המניפסט appsscript.json, מגדירים את השדה runtimeVersion לערך DEPRECATED_ES5.
  6. למעלה, לוחצים על שמירת הפרויקט .

איך מעבירים סקריפטים קיימים?

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

העברה אוטומטית של סקריפטים ל-V8

החל מ-18 בפברואר 2020, ‏ Google תתחיל להעביר בהדרגה ל-V8 סקריפטים קיימים שעוברים את בדיקת התאימות האוטומטית שלנו. הסקריפטים המושפעים ממשיכים לפעול כרגיל אחרי ההעברה.

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

איך מדווחים על באגים?

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