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

ב-Google 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.

לסביבת זמן הריצה V8 של Apps Script יש כמה מגבלות והבדלים משמעותיים בהשוואה לסביבות זמן ריצה נפוצות אחרות של JavaScript. פרטים נוספים זמינים במאמר בנושא מגבלות של סביבת ההרצה של Apps Script 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 ובצד ימין לוחצים על הפעלות .

בחלונית Executions לא מוצגים יומנים עם חותמות זמן של כל קריאה לשירות Apps Script. משתמשים בשירות console כדי ליצור הודעות יומן מתאימות. כל היומנים שנוצרו באמצעות console מופיעים בחלונית Executions.

דוגמאות לתחביר 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));
      

שיעורים

מחלקות מספקות אמצעי לארגון קוד באופן מושגי באמצעות ירושה. מחלקות ב-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!"

      

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

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

// 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, ‏ SubtleCrypto
  • אובייקטים גלובליים: window, ‏ navigator, ‏ performance, ‏ process (Node.js)

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

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

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

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

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

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

מגבלות בכיתה

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

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

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

  • מודולים של ES6: סביבת ההרצה של V8 לא תומכת במודולים של ES6 ‏ (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, איך לחפש דוחות קיימים על בעיות, איך לדווח על באגים חדשים ואיך לשלוח בקשות לתכונות חדשות.