Tổng quan về môi trường thời gian chạy V8

Trong Google Apps Script và JavaScript, thời gian chạy hoặc môi trường thời gian chạy chứa công cụ JavaScript phân tích cú pháp và thực thi mã tập lệnh. Thời gian chạy cung cấp các quy tắc về cách truy cập bộ nhớ, cách chương trình có thể tương tác với hệ điều hành của máy tính và cú pháp chương trình nào là hợp lệ. Mỗi trình duyệt web đều có một môi trường thời gian chạy cho JavaScript.

Trước đây, Apps Script được hỗ trợ bởi trình thông dịch JavaScript Rhino của Mozilla. Mặc dù Rhino cung cấp một cách thuận tiện cho Apps Script thực thi tập lệnh của nhà phát triển, nhưng nó cũng ràng buộc Apps Script với một phiên bản JavaScript cụ thể (ES5). Nhà phát triển Apps Script không thể sử dụng cú pháp và tính năng JavaScript hiện đại hơn trong các tập lệnh sử dụng thời gian chạy Rhino.

Để giải quyết mối lo ngại này, Apps Script hiện được hỗ trợ bởi thời gian chạy V8 hỗ trợ Chrome và Node.js. Di chuyển các tập lệnh hiện có sang V8 để tận dụng cú pháp và tính năng JavaScript hiện đại.

Trang này mô tả các tính năng mới do V8 bật và cách bạn có thể bật V8 để sử dụng trong tập lệnh. Di chuyển tập lệnh sang V8 mô tả các bước di chuyển tập lệnh hiện có để sử dụng thời gian chạy V8.

Các tính năng của thời gian chạy V8

Các tập lệnh sử dụng thời gian chạy V8 có thể tận dụng các tính năng sau:

Cú pháp ECMAScript hiện đại

Sử dụng cú pháp ECMAScript hiện đại trong các tập lệnh được hỗ trợ bởi thời gian chạy V8. Cú pháp này bao gồm let, const và nhiều tính năng phổ biến khác.

Hãy xem ví dụ về cú pháp V8 để biết danh sách ngắn gọn về các cải tiến cú pháp phổ biến mà bạn có thể thực hiện bằng thời gian chạy V8.

Thời gian chạy Apps Script V8 có một số giới hạn và điểm khác biệt chính so với các thời gian chạy JavaScript phổ biến khác. Xem phần Giới hạn thời gian chạy Apps Script V8 để biết thêm thông tin chi tiết.

Cải thiện tính năng phát hiện hàm

Tính năng phát hiện hàm Apps Script được cải thiện cho các tập lệnh sử dụng V8. Thời gian chạy mới nhận dạng các định dạng định nghĩa hàm sau:

      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 () => {}

Gọi phương thức đối tượng từ điều kiện kích hoạt và lệnh gọi lại

Các tập lệnh sử dụng V8 có thể gọi phương thức đối tượng và phương thức tĩnh của lớp từ những nơi mà bạn đã có thể gọi phương thức thư viện. Những nơi này bao gồm:

Ví dụ sau đây về V8 cho thấy cách sử dụng phương thức đối tượng khi tạo các mục trình đơn trong Google Trang tính:

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');
  }
}

Xem nhật ký

Apps Script cung cấp hai dịch vụ ghi nhật ký: dịch vụ Logger và lớp console. Cả hai dịch vụ này đều ghi nhật ký vào cùng một dịch vụ Stackdriver Logging.

Để hiện nhật ký Loggerconsole, ở đầu trình chỉnh sửa tập lệnh, hãy nhấp vào Nhật ký thực thi.

Xem quá trình thực thi

Để xem nhật ký thực thi của tập lệnh, hãy mở dự án Apps Script rồi ở bên trái, nhấp vào Quá trình thực thi .

Bảng điều khiển Quá trình thực thi không cung cấp nhật ký có dấu thời gian của các lệnh gọi dịch vụ Apps Script riêng lẻ. Sử dụng dịch vụ console để tạo thông báo nhật ký thích hợp. Tất cả nhật ký được tạo bằng console đều xuất hiện trong bảng điều khiển Quá trình thực thi.

Ví dụ về cú pháp V8

Sau đây là danh sách ngắn gọn về các tính năng cú pháp phổ biến có sẵn cho các tập lệnh sử dụng thời gian chạy V8.

letconst

Từ khoá letconst cho phép bạn xác định các biến cục bộ phạm vi khối và hằng số phạm vi khối tương ứng.

// 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
      

Hàm mũi tên

Hàm mũi tên cung cấp một cách ngắn gọn để xác định hàm trong biểu thức.

// 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));
      

Lớp

Lớp cung cấp một phương tiện để sắp xếp mã theo khái niệm bằng tính kế thừa. Các lớp trong V8 chủ yếu là đường cú pháp trên tính kế thừa dựa trên nguyên mẫu 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)
      

Phân tách các phép gán

Biểu thức phân tách phép gán là một cách nhanh chóng để giải nén các giá trị từ mảng và đối tượng thành các biến riêng biệt.

// 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


      

Chuỗi ký tự mẫu

Chuỗi ký tự mẫu là chuỗi ký tự cho phép biểu thức nhúng. Chúng giúp bạn tránh các câu lệnh nối chuỗi phức tạp hơn.

// 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}`;


      

Tham số mặc định

Tham số mặc định cho phép bạn chỉ định giá trị mặc định cho các tham số hàm trong khai báo hàm. Điều này có thể đơn giản hoá mã trong phần thân hàm vì nó loại bỏ nhu cầu gán giá trị mặc định một cách rõ ràng cho các tham số bị thiếu.

// 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!"

      

Chuỗi nhiều dòng

Xác định chuỗi nhiều dòng bằng cách sử dụng cùng một cú pháp như chuỗi ký tự mẫu. Giống như chuỗi ký tự mẫu, cú pháp này cho phép bạn tránh việc nối chuỗi và đơn giản hoá định nghĩa chuỗi.

// 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`;
      

Giới hạn thời gian chạy V8

Thời gian chạy Apps Script V8 không phải là môi trường Node.js hoặc trình duyệt tiêu chuẩn. Điều này có thể dẫn đến các vấn đề về khả năng tương thích khi bạn gọi thư viện của bên thứ ba hoặc điều chỉnh các ví dụ về mã từ các môi trường JavaScript khác.

API không có sẵn

Các API JavaScript tiêu chuẩn sau đây KHÔNG có sẵn trong thời gian chạy Apps Script V8:

  • Timers: setTimeout, setInterval, clearTimeout, clearInterval
  • Streams: ReadableStream, WritableStream, TextEncoder, TextDecoder
  • Web APIs: fetch, FormData, File, Blob, URL, URLSearchParams, DOMException, atob, btoa
  • Crypto: crypto, SubtleCrypto
  • Global Objects: window, navigator, performance, process (Node.js)

Sử dụng các API Apps Script sau đây làm giải pháp thay thế:

Đối với các API không có giải pháp thay thế Apps Script, chẳng hạn như TextEncoder, đôi khi bạn có thể sử dụng polyfill. Polyfill là một thư viện sao chép chức năng API không có sẵn theo mặc định trong môi trường thời gian chạy. Trước khi sử dụng polyfill, hãy xác nhận rằng polyfill đó tương thích với thời gian chạy V8 của Apps Script.

Giới hạn không đồng bộ

Thời gian chạy V8 hỗ trợ cú pháp asyncawait cũng như đối tượng Promise. Tuy nhiên, môi trường thời gian chạy Apps Script về cơ bản là đồng bộ.

  • Microtasks (Supported): The runtime processes the microtask queue (where Promise.then callbacks and await resolutions occur) after the current call stack clears.
  • Macrotasks (Not Supported): Apps Script doesn't have a standard event loop for macrotasks. Functions like setTimeout and setInterval aren't available.
  • WebAssembly Exception: The WebAssembly API is the only built-in feature that operates in a non-blocking manner within the runtime, allowing for specific asynchronous compilation patterns (WebAssembly.instantiate).

Tất cả các thao tác I/O, chẳng hạn như UrlFetchApp.fetch, đều bị chặn. Để thực hiện các yêu cầu mạng song song, hãy sử dụng UrlFetchApp.fetchAll.

Giới hạn của lớp

Thời gian chạy V8 có những giới hạn cụ thể liên quan đến các tính năng lớp ES6+ hiện đại:

  • Private Fields: Private class fields (for example, #field) aren't supported and cause parsing errors. Consider using closures or WeakMap for true encapsulation.
  • Static Fields: Direct static field declarations within the class body (for example, static count = 0;) aren't supported. Assign static properties to the class after its definition (for example, MyClass.count = 0;).

Giới hạn của mô-đun

  • ES6 Modules: The V8 runtime doesn't support ES6 modules (import / export). To use libraries, you must either use the Apps Script library mechanism or bundle your code and its dependencies into a single script file. (Issue Tracker)
  • File Execution Order: All script files in your project are executed in a global scope. It's best to avoid top-level code with side effects and ensure functions and classes are defined before being used across files. Explicitly order your files in the editor if dependencies exist between them.

Bật thời gian chạy V8

Nếu một tập lệnh đang sử dụng thời gian chạy Rhino, hãy chuyển sang V8 bằng cách thực hiện như sau:

  1. Mở dự án Apps Script.
  2. Ở bên trái, hãy nhấp vào Cài đặt dự án .
  3. Chọn hộp đánh dấu Bật thời gian chạy Chrome V8.

Ngoài ra, hãy chỉ định trực tiếp thời gian chạy tập lệnh bằng cách chỉnh sửa tệp kê khai tập lệnh:

  1. Mở dự án Apps Script.
  2. Ở bên trái, hãy nhấp vào Cài đặt dự án .
  3. Chọn hộp đánh dấu Hiển thị tệp kê khai "appsscript.json" trong trình chỉnh sửa.
  4. Ở bên trái, hãy nhấp vào Trình chỉnh sửa > appsscript.json.
  5. Trong tệp kê khai appsscript.json, hãy đặt trường runtimeVersion thành giá trị V8.
  6. Ở trên cùng, hãy nhấp vào Lưu dự án .

Di chuyển tập lệnh sang V8 giải thích các bước khác mà bạn nên thực hiện để đảm bảo tập lệnh hoạt động tốt khi sử dụng V8.

Bật thời gian chạy Rhino

Nếu tập lệnh của bạn đang sử dụng V8 và bạn cần chuyển sang sử dụng thời gian chạy Rhino ban đầu, hãy làm như sau:

  1. Mở dự án Apps Script.
  2. Ở bên trái, hãy nhấp vào Cài đặt dự án .
  3. Xoá hộp đánh dấu Bật thời gian chạy Chrome V8.

Ngoài ra, hãy chỉnh sửa tệp kê khai tập lệnh:

  1. Mở dự án Apps Script.
  2. Ở bên trái, hãy nhấp vào Cài đặt dự án .
  3. Chọn hộp đánh dấu Hiển thị tệp kê khai "appsscript.json" trong trình chỉnh sửa.
  4. Ở bên trái, hãy nhấp vào Trình chỉnh sửa > appsscript.json.
  5. Trong tệp kê khai appsscript.json, hãy đặt trường runtimeVersion thành giá trị DEPRECATED_ES5.
  6. Ở trên cùng, hãy nhấp vào Lưu dự án .

Làm cách nào để di chuyển các tập lệnh hiện có?

Hướng dẫn Di chuyển tập lệnh sang V8 mô tả các bước bạn cần thực hiện để di chuyển một tập lệnh hiện có sang sử dụng V8. Điều này bao gồm việc bật thời gian chạy V8 và kiểm tra tập lệnh để tìm mọi vấn đề không tương thích đã biết.

Tự động di chuyển tập lệnh sang V8

Kể từ ngày 18 tháng 2 năm 2020, Google sẽ dần dần di chuyển các tập lệnh hiện có vượt qua bài kiểm tra khả năng tương thích tự động của chúng tôi sang V8. Các tập lệnh bị ảnh hưởng sẽ tiếp tục hoạt động bình thường sau khi di chuyển.

Nếu bạn muốn chọn không di chuyển tự động một tập lệnh, hãy đặt trường runtimeVersion trong tệp kê khai của tập lệnh đó thành DEPRECATED_ES5. Chọn di chuyển tập lệnh sang V8 theo cách thủ công bất cứ lúc nào sau đó.

Làm cách nào để báo cáo lỗi?

Hướng dẫn Hỗ trợ giải thích cách nhận trợ giúp về lập trình trên Stack Overflow, tìm kiếm các báo cáo vấn đề hiện có, gửi lỗi mới và đưa ra yêu cầu về tính năng mới.