Die Rhino-Laufzeitumgebung wird am oder nach dem 31. Januar 2026 eingestellt. Wenn Sie ein vorhandenes Skript mit der Rhino-Laufzeitumgebung haben, müssen Sie es zu V8 migrieren.
Oft ist die einzige Voraussetzung, um einem Skript V8-Syntax und -Funktionen hinzuzufügen, die Aktivierung der V8-Laufzeitumgebung. Es gibt jedoch einige Inkompatibilitäten und andere Unterschiede, die dazu führen können, dass ein Skript in der V8-Laufzeitumgebung fehlschlägt oder sich unerwartet verhält. Wenn Sie ein Skript zu V8 migrieren, müssen Sie im Skriptprojekt nach diesen Problemen suchen und alle gefundenen Probleme beheben.
V8-Migrationsverfahren
So migrieren Sie ein Skript zu V8:
- Aktivieren Sie die V8-Laufzeitumgebung
für das Skript. Die
runtimeVersionkann im Manifest für das Google Apps Script Projekt geprüft werden. - Prüfen Sie die folgenden Inkompatibilitäten sorgfältig. Untersuchen Sie Ihr Skript, um festzustellen, ob eine der Inkompatibilitäten vorliegt. Wenn eine oder mehrere Inkompatibilitäten vorhanden sind, passen Sie den Skriptcode an, um das Problem zu beheben oder zu vermeiden.
- Prüfen Sie die folgenden anderen Unterschiede sorgfältig. Untersuchen Sie Ihr Skript, um festzustellen, ob einer der aufgeführten Unterschiede das Verhalten Ihres Codes beeinträchtigt. Passen Sie Ihr Skript an, um das Verhalten zu korrigieren.
- Nachdem Sie alle gefundenen Inkompatibilitäten oder anderen Unterschiede behoben haben, aktualisieren Sie Ihren Code, um die V8-Syntax und andere Funktionen zu verwenden.
- Testen Sie Ihr Skript nach Abschluss der Codeanpassungen gründlich, um sicherzustellen, dass es sich wie erwartet verhält.
- Wenn Ihr Skript eine Webanwendung oder ein veröffentlichtes Add-on ist, müssen Sie eine neue Version des Skripts mit den V8-Anpassungen erstellen und die Bereitstellung auf die neu erstellte Version verweisen. Damit die V8-Version für Nutzer verfügbar ist, müssen Sie das Skript mit dieser Version noch einmal veröffentlichen.
- Wenn Ihr Skript als Bibliothek verwendet wird, erstellen Sie eine neue versionierte Bereitstellung des Skripts. Informieren Sie alle Skripts und Nutzer, die Ihre Bibliothek verwenden, über diese neue Version und fordern Sie sie auf, auf die V8-fähige Version zu aktualisieren. Prüfen Sie, ob ältere, auf Rhino basierende Versionen Ihrer Bibliothek nicht mehr aktiv verwendet werden oder nicht mehr zugänglich sind.
- Prüfen Sie, ob keine Instanzen Ihres Skripts mehr mit der alten Rhino-Laufzeitumgebung ausgeführt werden. Prüfen Sie, ob alle Bereitstellungen mit einer Version verknüpft sind, die auf V8 basiert. Archivieren Sie alte Bereitstellungen. Prüfen Sie alle Versionen und löschen Sie die Versionen , die nicht die V8-Laufzeitumgebung verwenden.
Inkompatibilitäten
Die ursprüngliche auf Rhino basierende Apps Script-Laufzeitumgebung erlaubte leider mehrere nicht standardmäßige ECMAScript-Verhaltensweisen. Da V8 den Standards entspricht, werden diese Verhaltensweisen nach der Migration nicht unterstützt. Wenn Sie diese Probleme nicht beheben, führt dies zu Fehlern oder zu einem fehlerhaften Skriptverhalten, sobald die V8-Laufzeitumgebung aktiviert ist.
In den folgenden Abschnitten werden diese Verhaltensweisen und die Schritte beschrieben, die Sie unternehmen müssen, um den Skriptcode während der Migration zu V8 zu korrigieren.
for each(variable in object) vermeiden
Die
for each (variable in object)
Anweisung wurde in JavaScript 1.6 hinzugefügt und zugunsten von for...of entfernt.
Verwenden Sie beim Migrieren Ihres Skripts zu V8 keine for each (variable in object)
Anweisungen.
Verwenden Sie stattdessen for (variable in object):
// Rhino runtime var obj = {a: 1, b: 2, c: 3}; // Don't use 'for each' in V8 for each (var value in obj) { Logger.log("value = %s", value); } |
// V8 runtime var obj = {a: 1, b: 2, c: 3}; for (var key in obj) { // OK in V8 var value = obj[key]; Logger.log("value = %s", value); } |
Date.prototype.getYear() vermeiden
In der ursprünglichen Rhino-Laufzeitumgebung
Date.prototype.getYear()
gibt für Jahre von 1900 bis 1999 zweistellige Jahreszahlen zurück, für andere
Daten jedoch vierstellige Jahreszahlen. Das war das Verhalten in JavaScript 1.2 und früher.
In der V8-Laufzeitumgebung,
Date.prototype.getYear()
gibt das Jahr minus 1900 zurück, wie es von den ECMAScript-Standards gefordert wird.
Verwenden Sie beim Migrieren Ihres Skripts zu V8 immer
Date.prototype.getFullYear(),
Diese Funktion gibt unabhängig vom Datum eine vierstellige Jahreszahl zurück.
Reservierte Keywords nicht als Namen verwenden
ECMAScript verbietet die Verwendung bestimmter reservierter Keywords in Funktions- und Variablennamen. Die Rhino-Laufzeitumgebung erlaubte viele dieser Wörter. Wenn Ihr Code sie verwendet, müssen Sie Ihre Funktionen oder Variablen umbenennen.
Verwenden Sie beim Migrieren Ihres Skripts zu V8 keine der
reservierten Keywords
als Namen für Variablen oder Funktionen.
Benennen Sie alle Variablen oder Funktionen um, um die Verwendung des Keyword-Namens zu vermeiden. Häufig werden Keywords als Namen für class, import und export verwendet.
Eine Ausnahme besteht darin, dass Objektliterale reservierte Keywords verwenden dürfen (in allen Laufzeitumgebungen):
function class() {} // Syntax error in V8. var obj = { class: 1 }; // Allowed.
const-Variablen nicht neu zuweisen
In der ursprünglichen Rhino-Laufzeitumgebung können Sie eine Variable mit const deklarieren. Das bedeutet, dass sich der Wert des Symbols nie ändert und zukünftige Zuweisungen an das Symbol ignoriert werden.
In der neuen V8-Laufzeitumgebung entspricht das const Keyword dem Standard. Wenn Sie
einer als const deklarierten Variablen einen Wert zuweisen, führt dies zu einem
TypeError: Assignment to constant variable Laufzeitfehler.
Versuchen Sie beim Migrieren Ihres Skripts zu V8 nicht, den Wert einer
const Variablen neu zuzuweisen:
// Rhino runtime const x = 1; x = 2; // No error console.log(x); // Outputs 1 |
// V8 runtime const x = 1; x = 2; // Throws TypeError console.log(x); // Never executed |
XML-Literale und das XML-Objekt vermeiden
Mit dieser nicht standardmäßigen Erweiterung von ECMAScript können Apps Script-Projekte direkt die XML-Syntax verwenden.
Verwenden Sie beim Migrieren Ihres Skripts zu V8 keine direkten XML-Literale oder das XML-Objekt.
Verwenden Sie stattdessen XmlService, um XML zu parsen:
// V8 runtime var incompatibleXml1 = <container><item/></container>; // Don't use var incompatibleXml2 = new XML('<container><item/></container>'); // Don't use var xml3 = XmlService.parse('<container><item/></container>'); // OK |
Keine benutzerdefinierten Iteratorfunktionen mit __iterator__ erstellen
In JavaScript 1.7 wurde eine Funktion hinzugefügt, mit der jeder Klasse ein benutzerdefinierter Iterator hinzugefügt werden kann, indem eine __iterator__-Funktion im Prototyp dieser Klasse deklariert wird. Diese Funktion wurde auch in die Rhino-Laufzeitumgebung von Apps Script aufgenommen, um Entwicklern die Arbeit zu erleichtern. Diese Funktion war jedoch nie Teil des
ECMA-262-Standards
und wurde in ECMAScript-konformen JavaScript-Engines entfernt. Skripts, die V8 verwenden, können diese Iteratorkonstruktion nicht verwenden.
Verwenden Sie beim Migrieren Ihres Skripts zu V8 nicht die __iterator__ Funktion, um
benutzerdefinierte Iteratoren zu erstellen. Verwenden Sie stattdessen
ECMAScript 6-Iteratoren.
Betrachten Sie die folgende Array-Konstruktion:
// Create a sample array var myArray = ['a', 'b', 'c']; // Add a property to the array myArray.foo = 'bar'; // The default behavior for an array is to return keys of all properties, // including 'foo'. Logger.log("Normal for...in loop:"); for (var item in myArray) { Logger.log(item); // Logs 0, 1, 2, foo } // To only log the array values with `for..in`, a custom iterator can be used. |
Die folgenden Codebeispiele zeigen, wie ein Iterator in der Rhino-Laufzeitumgebung erstellt werden kann und wie ein Ersatziterator in der V8-Laufzeitumgebung erstellt wird:
// Rhino runtime custom iterator function ArrayIterator(array) { this.array = array; this.currentIndex = 0; } ArrayIterator.prototype.next = function() { if (this.currentIndex >= this.array.length) { throw StopIteration; } return "[" + this.currentIndex + "]=" + this.array[this.currentIndex++]; }; // Direct myArray to use the custom iterator myArray.__iterator__ = function() { return new ArrayIterator(this); } Logger.log("With custom Rhino iterator:"); for (var item in myArray) { // Logs [0]=a, [1]=b, [2]=c Logger.log(item); } |
// V8 runtime (ECMAScript 6) custom iterator myArray[Symbol.iterator] = function() { var currentIndex = 0; var array = this; return { next: function() { if (currentIndex < array.length) { return { value: "[${currentIndex}]=" + array[currentIndex++], done: false}; } else { return {done: true}; } } }; } Logger.log("With V8 custom iterator:"); // Must use for...of since // for...in doesn't expect an iterable. for (var item of myArray) { // Logs [0]=a, [1]=b, [2]=c Logger.log(item); } |
In der V8-Laufzeitumgebung müssen Sie for...of verwenden, wenn Sie Arrays mit benutzerdefinierten Iteratoren durchlaufen, da for..in keine iterierbaren Objekte erwartet.
Bedingte Catch-Klauseln vermeiden
Die V8-Laufzeitumgebung unterstützt keine bedingten catch..if-Klauseln, da sie nicht standardkonform sind.
Verschieben Sie beim Migrieren Ihres Skripts zu V8 alle bedingten Catch-Klauseln in den Catch-Body:
// Rhino runtime try { doSomething(); } catch (e if e instanceof TypeError) { // Don't use // Handle exception } |
// V8 runtime try { doSomething(); } catch (e) { if (e instanceof TypeError) { // Handle exception } } |
Object.prototype.toSource() vermeiden
JavaScript 1.3 enthielt eine Object.prototype.toSource() Methode, die nie Teil eines ECMAScript-Standards war. Sie wird in der V8-Laufzeitumgebung nicht unterstützt.
Entfernen Sie beim Migrieren Ihres Skripts zu V8 alle Verwendungen von Object.prototype.toSource() aus Ihrem Code.
Weitere Unterschiede
Neben den oben genannten Inkompatibilitäten, die zu Skriptfehlern führen können, gibt es noch einige andere Unterschiede, die ohne Korrektur zu einem unerwarteten Skriptverhalten in der V8-Laufzeitumgebung führen können.
In den folgenden Abschnitten wird erläutert, wie Sie Ihren Skriptcode aktualisieren, um diese unerwarteten Überraschungen zu vermeiden.
Gebietsschemaspezifische Datums- und Zeitformatierung anpassen
Die Date
Methoden toLocaleString(),
toLocaleDateString(),
und toLocaleTimeString()
verhalten sich in der V8-Laufzeitumgebung anders als in Rhino.
In Rhino ist das Standardformat das lange Format und alle übergebenen Parameter werden ignoriert.
In der V8-Laufzeitumgebung ist das Standardformat das kurze Format und Parameter
übergebene werden gemäß dem ECMA-Standard verarbeitet (weitere Informationen finden Sie in der
toLocaleDateString() Dokumentation
).
Testen und passen Sie beim Migrieren Ihres Skripts zu V8 die Erwartungen Ihres Codes hinsichtlich der Ausgabe von gebietsschemaspezifischen Datums- und Zeitmethoden an:
// Rhino runtime var event = new Date( Date.UTC(2012, 11, 21, 12)); // Outputs "December 21, 2012" in Rhino console.log(event.toLocaleDateString()); // Also outputs "December 21, 2012", // ignoring the parameters passed in. console.log(event.toLocaleDateString( 'de-DE', { year: 'numeric', month: 'long', day: 'numeric' })); |
// V8 runtime var event = new Date( Date.UTC(2012, 11, 21, 12)); // Outputs "12/21/2012" in V8 console.log(event.toLocaleDateString()); // Outputs "21. Dezember 2012" console.log(event.toLocaleDateString( 'de-DE', { year: 'numeric', month: 'long', day: 'numeric' })); |
Error.fileName und Error.lineNumber vermeiden
In der V8-Laufzeitumgebung unterstützt das Standard-JavaScript
Error
Objekt die Parameter fileName oder lineNumber nicht als Konstruktorparameter
oder Objekteigenschaften.
Entfernen Sie beim Migrieren Ihres Skripts zu V8
alle Abhängigkeiten von Error.fileName und Error.lineNumber.
Eine Alternative ist die Verwendung von
Error.prototype.stack.
Dieser Stack ist ebenfalls nicht standardmäßig, wird aber in V8 unterstützt. Das Format des von den beiden Plattformen erstellten Stacktrace ist etwas anders:
// Rhino runtime Error.prototype.stack // stack trace format at filename:92 (innerFunction) at filename:97 (outerFunction) |
// V8 runtime Error.prototype.stack // stack trace format Error: error message at innerFunction (filename:92:11) at outerFunction (filename:97:5) |
Umgang mit String-Enum-Objekten anpassen
In der ursprünglichen Rhino-Laufzeitumgebung gibt die Verwendung der JavaScript
JSON.stringify()
Methode für ein Enum-Objekt nur {} zurück.
In V8 gibt die Verwendung derselben Methode für ein Enum-Objekt den Enum-Namen zurück.
Testen und passen Sie beim Migrieren Ihres Skripts zu V8 die Erwartungen Ihres Codes
hinsichtlich der Ausgabe von
JSON.stringify()
für Enum-Objekte an:
// Rhino runtime var enumName = JSON.stringify(Charts.ChartType.BUBBLE); // enumName evaluates to {} |
// V8 runtime var enumName = JSON.stringify(Charts.ChartType.BUBBLE); // enumName evaluates to "BUBBLE" |
Umgang mit nicht definierten Parametern anpassen
In der ursprünglichen Rhino-Laufzeitumgebung führte die Übergabe von undefined an eine Methode als Parameter
dazu, dass der String "undefined" an diese Methode übergeben wurde.
In V8 entspricht die Übergabe von undefined an Methoden der Übergabe von null.
Testen und passen Sie beim Migrieren Ihres Skripts zu V8 die Erwartungen Ihres Codes
hinsichtlich undefined Parametern an:
// Rhino runtime SpreadsheetApp.getActiveRange() .setValue(undefined); // The active range now has the string // "undefined" as its value. |
// V8 runtime SpreadsheetApp.getActiveRange() .setValue(undefined); // The active range now has no content, as // setValue(null) removes content from // ranges. |
Umgang mit globalem this anpassen
Die Rhino-Laufzeitumgebung definiert einen impliziten Sonderkontext für Skripts, die sie verwenden.
Der Skriptcode wird in diesem impliziten Kontext ausgeführt, der sich vom tatsächlichen globalen this unterscheidet. Das bedeutet, dass Verweise auf das „globale this“ im Code tatsächlich zum Sonderkontext ausgewertet werden, der nur den Code und die Variablen enthält, die im Skript definiert sind. Die integrierten Apps Script-Dienste und ECMAScript-Objekte sind von dieser Verwendung von this ausgeschlossen. Diese Situation entsprach dieser JavaScript-Struktur:
// Rhino runtime // Apps Script built-in services defined here, in the actual global context. var SpreadsheetApp = { openById: function() { ... } getActive: function() { ... } // etc. }; function() { // Implicit special context; all your code goes here. If the global this // is referenced in your code, it only contains elements from this context. // Any global variables you defined. var x = 42; // Your script functions. function myFunction() { ... } // End of your code. }(); |
In V8 wird der implizite Sonderkontext entfernt. Globale Variablen und Funktionen, die im Skript definiert sind, werden neben den integrierten Apps Script-Diensten und ECMAScript-Funktionen wie Math und Date in den globalen Kontext eingefügt.
Testen und passen Sie beim Migrieren Ihres Skripts zu V8 die Erwartungen Ihres Codes
hinsichtlich der Verwendung von this in einem globalen Kontext an. In den meisten Fällen sind die Unterschiede nur sichtbar, wenn Ihr Code die Schlüssel oder Eigenschaftsnamen des globalen this-Objekts untersucht:
// Rhino runtime var myGlobal = 5; function myFunction() { // Only logs [myFunction, myGlobal]; console.log(Object.keys(this)); // Only logs [myFunction, myGlobal]; console.log( Object.getOwnPropertyNames(this)); } |
// V8 runtime var myGlobal = 5; function myFunction() { // Logs an array that includes the names // of Apps Script services // (CalendarApp, GmailApp, etc.) in // addition to myFunction and myGlobal. console.log(Object.keys(this)); // Logs an array that includes the same // values as above, and also includes // ECMAScript built-ins like Math, Date, // and Object. console.log( Object.getOwnPropertyNames(this)); } |
Umgang mit instanceof in Bibliotheken anpassen
Die Verwendung von instanceof in einer Bibliothek für ein Objekt, das als Parameter in einer Funktion aus einem anderen Projekt übergeben wird, kann zu falsch negativen Ergebnissen führen. In der V8-Laufzeitumgebung werden ein Projekt und seine Bibliotheken in verschiedenen Ausführungskontexten ausgeführt und haben daher unterschiedliche globale Variablen und Prototypketten.
Dies ist nur der Fall, wenn Ihre Bibliothek instanceof für ein Objekt verwendet, das nicht in Ihrem Projekt erstellt wurde. Die Verwendung für ein Objekt, das in Ihrem Projekt erstellt wurde, unabhängig davon, ob im selben oder in einem anderen Skript in Ihrem Projekt, sollte wie erwartet funktionieren.
Wenn ein Projekt, das unter V8 ausgeführt wird, Ihr Skript als Bibliothek verwendet, prüfen Sie, ob Ihr
Skript instanceof für einen Parameter verwendet, der aus einem anderen Projekt übergeben wird.
Passen Sie die Verwendung von instanceof an und verwenden Sie je nach Anwendungsfall andere geeignete Alternativen.
Eine Alternative für a instanceof b kann die Verwendung des Konstruktors von a in
Fällen sein, in denen Sie nicht die gesamte Prototypkette durchsuchen müssen und nur
den Konstruktor prüfen möchten. Verwendung: a.constructor.name == "b"
Betrachten Sie Projekt A und Projekt B, wobei Projekt A Projekt B als Bibliothek verwendet.
//Rhino runtime //Project A function caller() { var date = new Date(); // Returns true return B.callee(date); } //Project B function callee(date) { // Returns true return(date instanceof Date); } |
//V8 runtime //Project A function caller() { var date = new Date(); // Returns false return B.callee(date); } //Project B function callee(date) { // Incorrectly returns false return(date instanceof Date); // Consider using return (date.constructor.name == // “Date”) instead. // return (date.constructor.name == “Date”) -> Returns // true } |
Eine weitere Alternative besteht darin, eine Funktion einzuführen, die instanceof im Hauptprojekt prüft, und die Funktion zusätzlich zu anderen Parametern zu übergeben, wenn eine Bibliotheksfunktion aufgerufen wird. Die übergebene Funktion kann dann verwendet werden, um instanceof in der Bibliothek zu prüfen.
//V8 runtime //Project A function caller() { var date = new Date(); // Returns True return B.callee(date, date => date instanceof Date); } //Project B function callee(date, checkInstanceOf) { // Returns True return checkInstanceOf(date); } |
Übergabe von nicht freigegebenen Ressourcen an Bibliotheken anpassen
Die Übergabe einer nicht freigegebenen Ressource vom Hauptskript an eine Bibliothek funktioniert in der V8-Laufzeitumgebung anders.
In der Rhino-Laufzeitumgebung funktioniert die Übergabe einer nicht freigegebenen Ressource nicht. Die Bibliothek verwendet stattdessen ihre eigene Ressource.
In der V8-Laufzeitumgebung funktioniert die Übergabe einer nicht freigegebenen Ressource an die Bibliothek. Die Bibliothek verwendet die übergebene nicht freigegebene Ressource.
Übergeben Sie keine nicht freigegebenen Ressourcen als Funktionsparameter. Deklarieren Sie nicht freigegebene Ressourcen immer im selben Skript, in dem sie verwendet werden.
Betrachten Sie Projekt A und Projekt B, wobei Projekt A Projekt B als Bibliothek verwendet. In diesem Beispiel ist PropertiesService eine nicht freigegebene Ressource.
// Rhino runtime // Project A function testPassingNonSharedProperties() { PropertiesService.getScriptProperties() .setProperty('project', 'Project-A'); B.setScriptProperties(); // Prints: Project-B Logger.log(B.getScriptProperties( PropertiesService, 'project')); } |
// V8 runtime // Project A function testPassingNonSharedProperties() { PropertiesService.getScriptProperties() .setProperty('project', 'Project-A'); B.setScriptProperties(); // Prints: Project-A Logger.log(B.getScriptProperties( PropertiesService, 'project')); } |
JDBC-Empfehlungen in der V8-Laufzeitumgebung
Mit der V8-Laufzeitumgebung haben wir dem JDBC-Dienst neue Funktionen hinzugefügt.
executeBatch für Batchvorgänge verwenden
Verwenden Sie executeBatch(params)-Vorgänge, um Batch-Datenbankvorgänge auszuführen.
Das folgende Beispiel zeigt, wie mehrere Zeilen mithilfe von Batching in eine Datenbank eingefügt werden:
Rhino-Laufzeitumgebung (alte Methode):
var conn = Jdbc.getCloudSqlConnection("jdbc:google:mysql://..."); var stmt = conn.prepareStatement("INSERT INTO employees (name, age) VALUES (?, ?)"); var params = [["John Doe", 30], ["John Smith", 25]]; for (var i = 0; i < params.length; i++) { stmt.setString(1, params[i][0]); stmt.setInt(2, params[i][1]); stmt.execute(); }
V8-Laufzeitumgebung (neue Methode):
var conn = Jdbc.getCloudSqlConnection("jdbc:google:mysql://..."); var stmt = conn.prepareStatement("INSERT INTO employees (name, age) VALUES (?, ?)"); var params = [["John Doe", 30], ["John Smith", 25]]; stmt.executeBatch(params);
getRows zum Abrufen der Ergebnismenge verwenden
Verwenden Sie getRows(queryString), um die Daten der Ergebnismenge in einem Aufruf abzurufen. The
queryString besteht aus durch Kommas getrennten Aufrufen von Getter-Methoden von
JdbcResultSet, z. B. "getString(1), getDouble('price'), getDate(3,
'UTC')". Unterstützte Methoden umfassen alle Getter-Methoden, die für das Lesen von Spaltendaten zuständig sind. getHoldability, getMetaData usw. werden nicht unterstützt. Argumente können ganzzahlige Spaltenindizes (beginnend mit 1) oder in einfachen oder doppelten Anführungszeichen stehende Spaltenlabels sein.
Das folgende Beispiel zeigt, wie Sie Zeilen aus der Ergebnismenge abrufen:
Rhino-Laufzeitumgebung (alte Methode):
var conn = Jdbc.getCloudSqlConnection("jdbc:google:mysql://..."); var stmt = conn.createStatement(); var rs = stmt.executeQuery("SELECT name, age FROM employees"); while (rs.next()) { Logger.log(rs.getString('name') + ", " + rs.getInt('age')); }
V8-Laufzeitumgebung (neue Methode):
var conn = Jdbc.getCloudSqlConnection("jdbc:google:mysql://..."); var stmt = conn.createStatement(); var rs = stmt.executeQuery("SELECT name, age FROM employees"); var rows = rs.getRows("getString('name'), getInt('age')"); for (var i = 0; i < rows.length; i++) { Logger.log(rows[i][0] + ", " + rows[i][1]); }
Zugriff auf eigenständige Skripts aktualisieren
Für eigenständige Skripts, die in der V8-Laufzeitumgebung ausgeführt werden, müssen Sie Nutzern mindestens Lesezugriff auf das Skript gewähren, damit die Trigger des Skripts ordnungsgemäß funktionieren.