V8 ランタイムの概要

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 ランタイムでサポートされるようになりました。最新の JavaScript 構文と機能を利用するには、既存のスクリプトを V8 に移行します。

このページでは、V8 によって有効になる新機能と、スクリプトで使用するために V8 を有効にする方法について説明します。スクリプトを V8 に移行するでは、既存のスクリプトを移行して V8 ランタイムを使用する手順について説明します。

V8 ランタイムの機能

V8 ランタイムを使用するスクリプトでは、次の機能を利用できます。

最新の ECMAScript 構文

V8 ランタイムを搭載したスクリプトでは、最新の ECMAScript 構文を使用できます。この構文には、letconst など、多くの人気機能が含まれています。

V8 ランタイムを使用して行うことができる一般的な構文の改善の簡単なリストについては、V8 構文の例をご覧ください。

関数検出の改善

V8 を使用するスクリプトの Apps Script 関数の検出が改善されました。新しいランタイムは、次の関数定義形式を認識します。

      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 を使用するスクリプトは、ライブラリ メソッドを呼び出すことができる場所から、オブジェクト メソッドとクラスの静的メソッドを呼び出すことができます。これらの場所には、次のようなものがあります。

次の 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 クラスの 2 つのロギング サービスがあります。これらのサービスはどちらも、同じ Stackdriver Logging サービスにログを書き込みます。

Logger ログと console ログを表示するには、スクリプト エディタの上部にある [実行ログ] をクリックします。

実行を表示する

スクリプトの実行履歴を表示するには、Apps Script プロジェクトを開き、左側の [実行] をクリックします。

V8 構文の例

V8 ランタイムを使用するスクリプトで使用できる一般的な構文機能の簡単なリストは次のとおりです。

letconst

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 ランタイムでは使用できません。

  • タイマー: setTimeoutsetIntervalclearTimeoutclearInterval
  • ストリーム: ReadableStreamWritableStreamTextEncoderTextDecoder
  • ウェブ API: fetchFormDataFileBlobURLURLSearchParamsDOMExceptionatobbtoa
  • Crypto: cryptoSubtleCrypto
  • グローバル オブジェクト: windownavigatorperformanceprocess(Node.js)

代替手段として、次の Apps Script API を使用します。

TextEncoder など、Apps Script の代替手段がない API の場合は、ポリフィルを使用できることがあります。ポリフィルは、ランタイム環境でデフォルトで使用できない API 機能を複製するライブラリです。ポリフィルを使用する前に、Apps Script の V8 ランタイムと互換性があることを確認してください。

非同期の制限事項

V8 ランタイムは、async 構文と await 構文、および Promise オブジェクトをサポートしています。ただし、Apps Script ランタイム環境は基本的に同期型です。

  • マイクロタスク(サポート対象): ランタイムは、現在のコールスタックがクリアされた後、マイクロタスク キュー(Promise.then コールバックと await 解決が発生する場所)を処理します。
  • マクロタスク(サポート対象外): Apps Script には、マクロタスク用の標準イベント ループはありません。setTimeoutsetInterval などの関数は使用できません。
  • WebAssembly 例外: WebAssembly API は、ランタイム内でノンブロッキング方式で動作する唯一の組み込み機能であり、特定の非同期コンパイル パターン(WebAssembly.instantiate)を可能にします。

UrlFetchApp.fetch などのすべての I/O オペレーションはブロッキングされます。ネットワーク リクエストを並行して行うには、UrlFetchApp.fetchAll を使用します。

クラスの制限事項

V8 ランタイムには、最新の ES6+ クラス機能に関する特定の制限があります。

  • プライベート フィールド: プライベート クラス フィールド(#field など)はサポートされておらず、解析エラーが発生します。真のカプセル化には、クロージャまたは WeakMap の使用を検討してください。
  • 静的フィールド: クラス本体内の静的フィールドの直接宣言(static count = 0; など)はサポートされていません。クラスの定義後に(たとえば MyClass.count = 0;)、静的プロパティをクラスに割り当てます。

モジュールの制限事項

  • ES6 モジュール: V8 ランタイムは ES6 モジュール(import / export)をサポートしていません。ライブラリを使用するには、 Apps Script ライブラリ メカニズムを使用するか、コードとその依存関係を 1 つのスクリプト ファイルにバンドルする必要があります。(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 への自動移行

2020 年 2 月 18 日より、Google は自動互換性テストに合格した既存のスクリプトを V8 に段階的に移行します。影響を受けるスクリプトは、移行後も正常に機能します。

スクリプトを自動移行から除外する場合は、マニフェストの runtimeVersion フィールドを DEPRECATED_ES5 に設定します。その後、いつでも手動でスクリプトを V8 に移行できます。

バグを報告するにはどうすればよいですか?

サポートガイドでは、Stack Overflow でプログラミングのヘルプを利用する方法、既存の問題レポートを検索する方法、新しいバグを報告する方法、新しい機能リクエストを行う方法について説明しています。