ภาพรวมรันไทม์ V8

ใน Apps Script และ JavaScript รันไทม์หรือสภาพแวดล้อมรันไทม์มี เครื่องมือ JavaScript ที่แยกวิเคราะห์และเรียกใช้โค้ดสคริปต์ รันไทม์มี กฎเกี่ยวกับวิธีเข้าถึงหน่วยความจำ วิธีที่โปรแกรมโต้ตอบกับ ระบบปฏิบัติการของคอมพิวเตอร์ และไวยากรณ์ของโปรแกรมที่ถูกต้อง เว็บเบราว์เซอร์แต่ละรายการมีสภาพแวดล้อมรันไทม์สำหรับ JavaScript

ในอดีต Apps Script ขับเคลื่อนด้วยตัวแปล JavaScript ของ Rhino จาก 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 () => {}

เรียกเมธอดออบเจ็กต์การโทรจากทริกเกอร์และการเรียกกลับ

สคริปต์ที่ใช้ 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 มีบริการบันทึก 2 รายการ ได้แก่ Logger และคลาส console บริการทั้ง 2 รายการนี้ จะเขียนบันทึกลงในบริการ Stackdriver Logging เดียวกัน

หากต้องการแสดงบันทึก Logger และ console ให้คลิก Execution log ที่ด้านบนของโปรแกรมแก้ไขสคริปต์

ดูการดำเนินการ

หากต้องการดูประวัติการดำเนินการของสคริปต์ ให้เปิดโปรเจ็กต์ 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

รันไทม์ V8 ของ Apps Script ไม่ใช่สภาพแวดล้อมมาตรฐานของ Node.js หรือเบราว์เซอร์ ซึ่งอาจทำให้เกิดปัญหาความเข้ากันได้เมื่อคุณเรียกใช้ไลบรารีของบุคคลที่สาม หรือปรับตัวอย่างโค้ดจากสภาพแวดล้อม JavaScript อื่นๆ

API ที่ไม่พร้อมใช้งาน

API มาตรฐานของ JavaScript ต่อไปนี้ไม่พร้อมใช้งานใน รันไทม์ V8 ของ Apps Script

  • ตัวจับเวลา: setTimeout, setInterval, clearTimeout, clearInterval
  • สตรีม: ReadableStream, WritableStream, TextEncoder, TextDecoder
  • Web API: fetch, FormData, File, Blob, URL, URLSearchParams, DOMException, atob, btoa
  • คริปโต: crypto, SubtleCrypto
  • ออบเจ็กต์ส่วนกลาง: window, navigator, performance, process (Node.js)

ใช้ Apps Script API ต่อไปนี้แทน

สำหรับ API ที่ไม่มีทางเลือก Apps Script เช่น TextEncoder บางครั้งคุณสามารถใช้ Polyfill ได้ Polyfill คือไลบรารีที่จำลองฟังก์ชันการทำงานของ API ที่ไม่พร้อมใช้งานโดยค่าเริ่มต้นในสภาพแวดล้อมรันไทม์ ก่อนใช้ Polyfill ให้ตรวจสอบว่าเข้ากันได้กับรันไทม์ V8 ของ Apps Script

ข้อจำกัดแบบอะซิงโครนัส

รันไทม์ V8 รองรับไวยากรณ์ async และ await รวมถึงออบเจ็กต์ Promise อย่างไรก็ตาม สภาพแวดล้อมรันไทม์ของ Apps Script เป็นแบบ ซิงโครนัสโดยพื้นฐาน

  • Microtask (รองรับ): รันไทม์จะประมวลผลคิว Microtask (ที่ซึ่งมีการเรียกกลับ Promise.then และการแก้ปัญหา await) หลังจากที่สแต็กการเรียกใช้ปัจจุบันว่าง
  • มาโครทาสก์ (ไม่รองรับ): Apps Script ไม่มี ลูปเหตุการณ์มาตรฐานสำหรับมาโครทาสก์ ฟังก์ชันอย่าง setTimeout และ setInterval จะไม่พร้อมใช้งาน
  • ข้อยกเว้นของ WebAssembly: WebAssembly API เป็นฟีเจอร์ในตัวเพียงอย่างเดียว ที่ทำงานในลักษณะที่ไม่บล็อกภายในรันไทม์ ซึ่งช่วยให้ ใช้รูปแบบการคอมไพล์แบบอะซิงโครนัสที่เฉพาะเจาะจงได้ (WebAssembly.instantiate)

การดำเนินการ I/O ทั้งหมด เช่น UrlFetchApp.fetch จะ บล็อก หากต้องการส่งคำขอเครือข่ายพร้อมกัน ให้ใช้ UrlFetchApp.fetchAll

ข้อจำกัดของชั้นเรียน

รันไทม์ V8 มีข้อจำกัดเฉพาะเกี่ยวกับฟีเจอร์คลาส ES6+ สมัยใหม่ ดังนี้

  • ฟิลด์ส่วนตัว: ไม่รองรับฟิลด์คลาสส่วนตัว (เช่น #field) และจะทำให้เกิดข้อผิดพลาดในการแยกวิเคราะห์ ลองใช้ Closure หรือ WeakMap เพื่อ การแคปซูลที่แท้จริง
  • ฟิลด์แบบคงที่: ระบบไม่รองรับการประกาศฟิลด์แบบคงที่โดยตรงภายในเนื้อหาของคลาส (เช่น static count = 0;) กำหนดพร็อพเพอร์ตี้แบบคงที่ ให้กับคลาสหลังจากกำหนดแล้ว (เช่น MyClass.count = 0;)

ข้อจำกัดของโมดูล

  • โมดูล ES6: รันไทม์ V8 ไม่รองรับโมดูล ES6 (import / export) หากต้องการใช้ไลบรารี คุณต้องใช้ กลไกไลบรารีของ Apps Script หรือรวมโค้ดและทรัพยากร Dependency ไว้ในไฟล์สคริปต์เดียว (เครื่องมือติดตามปัญหา)
  • ลำดับการเรียกใช้ไฟล์: ระบบจะเรียกใช้ไฟล์สคริปต์ทั้งหมดในโปรเจ็กต์ใน ขอบเขตส่วนกลาง คุณควรหลีกเลี่ยงโค้ดระดับบนสุดที่มีผลข้างเคียง และตรวจสอบว่าได้กำหนดฟังก์ชันและคลาสก่อนที่จะนำไปใช้ในไฟล์ต่างๆ จัดเรียงไฟล์ในเอดิเตอร์อย่างชัดเจนหากมีทรัพยากรที่ขึ้นต่อกัน

การเปิดใช้รันไทม์ V8

หากสคริปต์ใช้รันไทม์ Rhino คุณสามารถเปลี่ยนไปใช้ V8 ได้โดย ทำดังนี้

  1. เปิดโปรเจ็กต์ Apps Script
  2. คลิกการตั้งค่าโปรเจ็กต์ ทางด้านซ้าย
  3. เลือกช่องทำเครื่องหมายเปิดใช้รันไทม์ Chrome V8

หรือจะระบุรันไทม์ของสคริปต์โดยตรงได้ด้วยการ แก้ไขไฟล์ Manifest ของสคริปต์

  1. เปิดโปรเจ็กต์ Apps Script
  2. คลิกการตั้งค่าโปรเจ็กต์ ทางด้านซ้าย
  3. เลือกช่องทำเครื่องหมายแสดงไฟล์ Manifest "appsscript.json" ในเครื่องมือแก้ไข
  4. ทางด้านซ้าย ให้คลิกเอดิเตอร์ > appsscript.json
  5. ในไฟล์ Manifest ของ appsscript.json ให้ตั้งค่าฟิลด์ runtimeVersion เป็นค่า V8
  6. คลิกบันทึกโปรเจ็กต์ ที่ด้านบน

การย้ายข้อมูลสคริปต์ไปยัง V8 อธิบาย ขั้นตอนอื่นๆ ที่คุณควรทำเพื่อให้สคริปต์ทำงานได้ดีโดยใช้ V8

การเปิดใช้รันไทม์ของ Rhino

หากสคริปต์ใช้ V8 และคุณต้องการเปลี่ยนให้ใช้รันไทม์ Rhino ดั้งเดิม ให้ทำดังนี้

  1. เปิดโปรเจ็กต์ Apps Script
  2. คลิกการตั้งค่าโปรเจ็กต์ ทางด้านซ้าย
  3. ยกเลิกการเลือกช่องทำเครื่องหมายเปิดใช้รันไทม์ Chrome V8

หรือจะแก้ไขไฟล์ Manifest ของสคริปต์ก็ได้

  1. เปิดโปรเจ็กต์ Apps Script
  2. คลิกการตั้งค่าโปรเจ็กต์ ทางด้านซ้าย
  3. เลือกช่องทำเครื่องหมายแสดงไฟล์ Manifest "appsscript.json" ในเครื่องมือแก้ไข
  4. ทางด้านซ้าย ให้คลิกเอดิเตอร์ > appsscript.json
  5. ในไฟล์ Manifest ของ appsscript.json ให้ตั้งค่าฟิลด์ runtimeVersion เป็นค่า DEPRECATED_ES5
  6. คลิกบันทึกโปรเจ็กต์ ที่ด้านบน

ฉันจะย้ายข้อมูลสคริปต์ที่มีอยู่ได้อย่างไร

คำแนะนำการย้ายข้อมูลสคริปต์ไปยัง V8 อธิบายขั้นตอนที่คุณต้องทำเพื่อย้ายข้อมูลสคริปต์ที่มีอยู่ไปใช้ V8 ซึ่งรวมถึงการเปิดใช้รันไทม์ V8 และการตรวจสอบสคริปต์เพื่อหา ความไม่เข้ากันที่ทราบ

การย้ายข้อมูลสคริปต์ไปยัง V8 โดยอัตโนมัติ

ตั้งแต่วันที่ 18 กุมภาพันธ์ 2020 เป็นต้นไป Google จะเริ่มทยอยย้ายข้อมูลสคริปต์ที่มีอยู่ ซึ่งผ่านการทดสอบความเข้ากันได้อัตโนมัติของเราไปยัง V8 สคริปต์ที่ได้รับผลกระทบจะยังคงทำงานได้ตามปกติหลังจากการย้ายข้อมูล

หากต้องการเลือกไม่ให้สคริปต์ย้ายข้อมูลโดยอัตโนมัติ ให้ตั้งค่าฟิลด์ runtimeVersion ในไฟล์ Manifest เป็น DEPRECATED_ES5 คุณเลือกที่จะย้ายข้อมูลสคริปต์ไปยัง V8 ด้วยตนเองได้ทุกเมื่อหลังจากนั้น

ฉันจะรายงานข้อบกพร่องได้อย่างไร

คู่มือการสนับสนุนอธิบายวิธีรับความช่วยเหลือด้านการเขียนโปรแกรมใน Stack Overflow, ค้นหารายงานปัญหาที่มีอยู่, ยื่นข้อบกพร่องใหม่ และส่งคำขอฟีเจอร์ใหม่