在 Apps Script 和 JavaScript 中,執行階段或執行階段環境包含 JavaScript 引擎,可剖析及執行指令碼程式碼。執行階段會提供記憶體存取方式、程式與電腦作業系統互動方式,以及合法程式語法的規則。每個網頁瀏覽器都有 JavaScript 的執行階段環境。
過去,Apps Script 一直採用 Mozilla 的 Rhino JavaScript 解譯器。Rhino 雖然能讓 Apps Script 輕鬆執行開發人員指令碼,但也將 Apps Script 綁定至特定 JavaScript 版本 (ES5)。Apps Script 開發人員無法在採用 Rhino 執行階段的指令碼中,使用更現代的 JavaScript 語法和功能。
為解決這項問題,Apps Script 現在支援 Chrome 和 Node.js 採用的 V8 執行階段。您可以將現有指令碼遷移至 V8,以便使用新版 JavaScript 語法和功能。
本頁面說明 V8 啟用的新功能,以及如何啟用 V8 以供指令碼使用。「將指令碼遷移至 V8」一文說明如何遷移現有指令碼,改用 V8 執行階段。
V8 執行階段的功能
使用 V8 執行階段的指令碼可運用下列功能:
新式 ECMAScript 語法
在 V8 執行階段支援的指令碼中,您可以使用新版 ECMAScript 語法。這項語法包括 let、const 和許多其他熱門功能。
如需使用 V8 執行階段可進行的常用語法改良項目簡短清單,請參閱 V8 語法範例。
提升函式偵測準確度
使用 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 () => {}
從觸發條件和回呼呼叫物件方法
使用 V8 的指令碼可以從您已可呼叫程式庫方法的位置,呼叫物件方法和類別靜態方法。包括:
- Google Workspace 外掛程式 資訊清單觸發條件
- 可安裝的觸發條件
- Google Workspace 編輯器中的選單項目
- 使用者回呼函式,例如
ScriptApp.newStateToken()程式碼範例中說明的函式。
以下 V8 範例說明在 Google 試算表中建構選單項目時,如何使用物件方法:
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)); |
類別
類別 提供一種方法,可透過繼承從概念上整理程式碼。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
下列標準 JavaScript API「不」適用於 Apps Script V8 執行階段:
- 計時器:
setTimeout、setInterval、clearTimeout、clearInterval - 串流:
ReadableStream、WritableStream、TextEncoder、TextDecoder - 網路 API:
fetch、FormData、File、Blob、URL、URLSearchParams、DOMException、atob、btoa - 加密:
crypto、SubtleCrypto - 全域物件:
window、navigator、performance、process(Node.js)
請改用下列 Apps Script API:
- 計時器:使用
Utilities.sleep同步暫停。不支援非同步計時器。 - 擷取:使用
UrlFetchApp.fetch(url, params)發出 HTTP(S) 要求。 - atob:使用
Utilities.base64Decode解碼 Base64 編碼字串。 - btoa:使用
Utilities.base64Encode以 Base64 編碼字串。 - 加密:使用
Utilities進行加密編譯函式,例如computeDigest、computeHmacSha256Signature和computeRsaSha256Signature。
如果 API 沒有 Apps Script 替代方案 (例如 TextEncoder),有時可以使用 Polyfill。Polyfill 是一種程式庫,可複製執行階段環境預設不提供的 API 功能。使用 Polyfill 前,請先確認其與 Apps Script 的 V8 執行階段相容。
非同步限制
V8 執行階段支援 async 和 await 語法,以及 Promise 物件。不過,Apps Script 執行階段環境基本上是同步的。
- 微任務 (支援):目前的呼叫堆疊清除後,執行階段會處理微任務佇列 (發生
Promise.then回呼和await解析的位置)。 - 巨集工作 (不支援):Apps Script 沒有巨集工作的標準事件迴圈。無法使用
setTimeout和setInterval等函式。 - WebAssembly 例外狀況: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 程式庫機制,或將程式碼及其依附元件組合為單一指令碼檔案。(問題追蹤器) - 檔案執行順序:專案中的所有指令碼檔案都會在全域範圍內執行。建議您避免使用具有副作用的頂層程式碼,並確保函式和類別是在跨檔案使用前定義。如果檔案之間存在依附元件,請在編輯器中明確排序檔案。
啟用 V8 執行階段
如果指令碼使用 Rhino 執行階段,您可以按照下列步驟切換至 V8:
- 開啟 Apps Script 專案。
- 按一下左側的「專案設定」圖示 。
- 勾選「啟用 Chrome V8 執行階段」核取方塊。
或者,您也可以編輯指令碼資訊清單檔案,直接指定指令碼執行階段:
- 開啟 Apps Script 專案。
- 按一下左側的「專案設定」圖示 。
- 勾選「在編輯器中顯示『appsscript.json』資訊清單檔案」核取方塊。
- 按一下左側的「編輯器」圖示 >
appsscript.json。 - 在
appsscript.json資訊清單檔案中,將runtimeVersion欄位設為V8值。 - 按一下頂端的「儲存專案」圖示 。
「將指令碼遷移至 V8」一文說明瞭其他步驟,可確保指令碼在 V8 中正常運作。
啟用 Rhino 執行階段
如果您的指令碼使用 V8,且需要切換為原始 Rhino 執行階段,請按照下列步驟操作:
- 開啟 Apps Script 專案。
- 按一下左側的「專案設定」圖示 。
- 取消勾選「Enable Chrome V8 runtime」(啟用 Chrome V8 執行階段) 核取方塊。
或者,也可以編輯指令碼資訊清單:
- 開啟 Apps Script 專案。
- 按一下左側的「專案設定」圖示 。
- 勾選「在編輯器中顯示『appsscript.json』資訊清單檔案」核取方塊。
- 按一下左側的「編輯器」圖示 >
appsscript.json。 - 在
appsscript.json資訊清單檔案中,將runtimeVersion欄位設為DEPRECATED_ES5值。 - 按一下頂端的「儲存專案」圖示 。
如何遷移現有指令碼?
「將指令碼遷移至 V8」指南說明如何將現有指令碼遷移至 V8。包括啟用 V8 執行階段,以及檢查指令碼是否有任何已知的不相容問題。
自動將指令碼遷移至 V8
自 2020 年 2 月 18 日起,Google 會開始將通過自動相容性測試的現有指令碼,逐步遷移至 V8。遷移後,受影響的指令碼會繼續正常運作。
如要讓指令碼不進行自動遷移,請將資訊清單中的 runtimeVersion 欄位設為 DEPRECATED_ES5。之後您隨時可以選擇手動將指令碼遷移至 V8。
如何回報錯誤?
支援指南說明如何在 Stack Overflow 上取得程式設計方面的協助、搜尋現有問題回報、回報新錯誤,以及提出新功能要求。