Se disponi già di uno script che utilizza il runtime di Rhino e vuoi usare della sintassi e delle funzionalità di V8, devi eseguire la migrazione dello script alla versione V8.
La maggior parte degli script scritti con il runtime Rhino può funzionare con un runtime V8 senza aggiustamenti. Spesso l'unico prerequisito per l'aggiunta della sintassi V8 caratteristiche di uno script è l'attivazione del runtime V8.
Tuttavia, esiste un piccolo insieme incompatibilità e altre differenze che possono comportare non riesce o si comporta in modo imprevisto dopo aver abilitato il runtime V8. Durante la migrazione uno script per utilizzare V8, devi cercare questi problemi nel progetto dello script e correggili.
Procedura di migrazione V8
Per eseguire la migrazione di uno script alla versione V8, segui questa procedura:
- Attiva il runtime V8 per lo script.
- Esamina attentamente le incompatibilità elencati di seguito. Esamina lo script per determinare se uno dei sono presenti incompatibilità; in presenza di una o più incompatibilità Modificare il codice dello script per rimuovere o evitare il problema.
- Esamina attentamente le altre differenze elencate di seguito. Esamina lo script per determinare se una delle differenze elencate influisce il comportamento del codice. Modifica lo script per correggere il comportamento.
- Una volta corrette eventuali incompatibilità o altri differenze, puoi iniziare ad aggiornare il codice per utilizzare Sintassi di V8 e altre funzionalità in base alle tue esigenze.
- Dopo aver terminato le modifiche al codice, testa accuratamente lo script per per assicurarti che si comporti nel modo previsto.
- Se lo script è un'app web o un componente aggiuntivo pubblicato: devi crea una nuova versione dello script con le modifiche V8. Per rendere disponibile la versione V8 devi pubblicare nuovamente lo script con questa versione.
Incompatibilità
Purtroppo il runtime Apps Script originale basato su Rhino ha consentito diverse comportamenti ECMAScript non standard. Poiché V8 è conforme agli standard, questi I comportamenti non sono supportati dopo la migrazione. Mancata correzione di questi problemi provoca errori o un comportamento dello script non funzionante dopo l'attivazione del runtime V8.
Le sezioni seguenti descrivono ognuno di questi comportamenti e i passaggi da intraprendere per correggere il codice dello script durante la migrazione a V8.
Evita for each(variable in object)
La
for each (variable in object)
è stata aggiunta a JavaScript 1.6 e rimossa a favore di for...of
.
Quando esegui la migrazione dello script a V8, evita di utilizzare for each (variable in object)
estratti conto.
Usa invece 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); } |
Evita Date.prototype.getYear()
Nel runtime originale di Rhino,
Date.prototype.getYear()
restituisce gli anni a due cifre per gli anni dal 1900 al 1999, mentre gli anni a quattro cifre per le altre
date, che era il comportamento in JavaScript 1.2 e precedenti.
Nel runtime V8,
Date.prototype.getYear()
restituisce l'anno meno 1900 come richiesto
standard ECMAScript.
Quando esegui la migrazione dello script a V8, usa sempre
Date.prototype.getFullYear()
,
che restituisce un anno a quattro cifre indipendentemente dalla data.
Evita di utilizzare parole chiave riservate come nomi.
ECMAScript vieta l'uso di alcune parole chiave prenotate nei nomi di funzioni e variabili. Il runtime di Rhino consentiva di utilizzare molte di queste parole, pertanto, se nel codice le utilizzi, devi rinominare le funzioni o le variabili.
Quando esegui la migrazione dello script a V8, evita di nominare variabili o funzioni
utilizzando uno dei
parole chiave prenotate.
Rinomina qualsiasi variabile o funzione per evitare di utilizzare il nome della parola chiave. Utilizzi comuni
di parole chiave come nomi sono class
, import
e export
.
Evita di riassegnare const
variabili
Nel runtime di Rhino originale, puoi dichiarare una variabile utilizzando const
, che
indica che il valore del simbolo non cambia mai e le assegnazioni future
vengono ignorati.
Nel nuovo runtime V8, la parola chiave const
è conforme allo standard e assegna
a una variabile dichiarata come const
genera un
Errore di runtime TypeError: Assignment to constant variable
.
Quando esegui la migrazione dello script a V8, non tentare di riassegnare il valore
una variabile const
:
// 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 |
Evita i valori letterali XML e l'oggetto XML
Questo estensione non standard a ECMAScript consente ai progetti Apps Script di utilizzare direttamente la sintassi XML.
Quando esegui la migrazione dello script alla versione V8, evita di utilizzare valori letterali XML diretti o .
Usa invece XmlService per analizzare XML:
// 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 |
Non creare funzioni di iteratore personalizzate utilizzando __iterator__
JavaScript 1.7 ha aggiunto una funzionalità che consente l'aggiunta di un iteratore personalizzato a qualsiasi clas
s dichiarando una funzione __iterator__
nel prototipo di quella classe; questo era
è stato aggiunto anche al runtime Rhino di Apps Script per praticità. Tuttavia,
questa funzionalità non ha mai fatto parte
Standard ECMA-262
ed è stato rimosso nei motori JavaScript conformi a ECMAScript. Script che utilizzano V8
non è possibile utilizzare questa
costruzione dell'iteratore.
Quando esegui la migrazione dello script a V8, evita la funzione __iterator__
di creare
personalizzati. Invece,
utilizzare iteratori ECMAScript 6.
Considera la seguente costruzione di array:
// 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. |
I seguenti esempi di codice mostrano come potrebbe essere costruito un iteratore Runtime Rhino e come creare un iteratore sostitutivo nel runtime V8:
// 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); } |
Evitare le clausole di cattura condizionali
Il runtime V8 non supporta catch..if
clausole di cattura condizionale, poiché
non sono conformi agli standard.
Quando esegui la migrazione dello script a V8, sposta tutte le condizionali di cattura all'interno della 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 } } |
Evita di usare Object.prototype.toSource()
JavaScript 1.3 conteneva un'istruzione Object.prototype.toSource() che non ha mai fatto parte di nessuno standard ECMAScript. Non è supportata in il runtime V8.
Quando esegui la migrazione dello script a V8, rimuovi qualsiasi utilizzo di Object.prototype.toSource() dal codice.
Altre differenze
Oltre alle incompatibilità di cui sopra che possono causare errori dello script, ci sono alcune altre differenze che, se non corrette, possono generare errori V8 imprevisti il comportamento dello script di runtime.
Le sezioni seguenti spiegano come aggiornare il codice dello script per evitare questi sorprese inaspettate.
Modificare la formattazione di data e ora specifiche per le impostazioni internazionali
La Date
metodi toLocaleString()
,
toLocaleDateString()
,
e toLocaleTimeString()
si comportano
in modo diverso nel runtime V8 rispetto a Rhino.
In Rhino, il formato predefinito è il formato lungo e gli eventuali parametri passati vengono ignorate.
Nel runtime V8, il formato predefinito è il formato breve e i parametri
vengono gestiti secondo lo standard ECMA (vedi
Documentazione di toLocaleDateString()
per maggiori dettagli).
Quando esegui la migrazione del tuo script a V8, testa e modifica le aspettative del codice relativi all'output di metodi di data e ora specifici per le impostazioni internazionali:
// 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' })); |
Evita di usare Error.fileName
e Error.lineNumber
.
Nell'untime V8, lo standard JavaScript
Error
non supporta fileName
o lineNumber
come parametri del costruttore
o proprietà degli oggetti.
Quando esegui la migrazione dello script a V8,
rimuovere eventuali dipendenze da Error.fileName
e Error.lineNumber
.
Un'alternativa è utilizzare
Error.prototype.stack
Anche questo stack non è standard, ma è supportato sia in Rhino sia in V8. La
dell'analisi dello stack prodotta dalle due piattaforme è leggermente diverso:
// 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) |
Regola la gestione degli oggetti enum con stringa
Nel runtime di Rhino originale, utilizzando il linguaggio JavaScript
JSON.stringify()
su un oggetto enum restituisce solo {}
.
In V8, utilizzando lo stesso metodo su un oggetto enum, viene restituito il nome enum.
Quando esegui la migrazione dello script a V8,
testare e modificare le aspettative del codice relative all'output
JSON.stringify()
sugli oggetti enum:
// 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" |
Regola la gestione dei parametri non definiti
Nel runtime di Rhino originale, passaggio di undefined
a un metodo come parametro
ha comportato il passaggio della stringa "undefined"
a tale metodo.
In V8, trasferire undefined
ai metodi equivale a passare null
.
Quando esegui la migrazione dello script a V8,
testa e modifica le aspettative del codice relative ai parametri undefined
:
// 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. |
Regola gestione this
globale
Il runtime di Rhino definisce un contesto speciale implicito per gli script che lo utilizzano.
Il codice dello script viene eseguito in questo contesto implicito, distinto dall'effettivo contesto globale
this
. Ciò significa che i riferimenti al campo "this
globale" nel codice
valuta il contesto speciale, che contiene solo il codice e le variabili
definita nello script. I servizi Apps Script integrati e gli oggetti ECMAScript
sono esclusi da questo uso di this
. La situazione è simile a questa
Struttura JavaScript:
// 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, il contesto speciale implicito viene rimosso. Variabili e funzioni globali
definiti nello script vengono posizionati nel contesto globale, accanto alle
Servizi Apps Script ed ECMAScript integrati come Math
e Date
.
Quando esegui la migrazione del tuo script a V8, testa e modifica le aspettative del codice
sull'utilizzo di this
in un contesto globale. Nella maggior parte dei casi, le differenze
sono evidenti solo se il codice esamina le chiavi o i nomi delle proprietà
oggetto this
globale:
// 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)); } |
Regola la gestione di instanceof
nelle librerie
Utilizzo di instanceof
in una libreria su un oggetto passato come parametro in un
di un altro progetto può dare falsi negativi. Nel runtime V8,
il progetto e le sue librerie vengono eseguiti in diversi contesti di esecuzione e, di conseguenza,
diverse catene globali e prototipi.
Tieni presente che questo è possibile solo se la libreria utilizza instanceof
su un oggetto
non creato nel tuo progetto. Utilizzo su un oggetto creato
all'interno del progetto, che sia nello stesso o in
uno script diverso all'interno del progetto,
dovrebbe funzionare come previsto.
Se un progetto in esecuzione su V8 utilizza il tuo script come libreria, controlla se
lo script utilizza instanceof
su un parametro che verrà passato da un altro progetto. Modifica
l'utilizzo di instanceof
e altre alternative possibili in base al tuo utilizzo
.
Un'alternativa a a instanceof b
è l'utilizzo del costruttore di a
in
nei casi in cui non è necessario cercare l'intera catena di prototipi e
il costruttore.
Utilizzo: a.constructor.name == "b"
Considera i progetti A e B, dove il progetto A utilizza il progetto B come biblioteca.
//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 } |
Un'altra alternativa può essere introdurre una funzione che verifichi instanceof
nel progetto principale
e passare la funzione in aggiunta ad altri parametri quando si chiama una funzione di libreria. La funzione passata
può essere utilizzato per controllare instanceof
nella raccolta.
//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); } |
Modifica il passaggio di risorse non condivise alle librerie
Il passaggio di una risorsa non condivisa dallo script principale a una libreria funziona in modo diverso nel runtime V8.
Nel runtime di Rhino, non è possibile trasferire una risorsa non condivisa. La libreria utilizza invece la propria risorsa.
Nel runtime V8, il passaggio di una risorsa non condivisa alla libreria funziona. La libreria utilizza la risorsa non condivisa passata.
Non trasferire risorse non condivise come parametri della funzione. Dichiara sempre le risorse non condivise nello stesso script che le utilizza.
Considera i progetti A e B, dove il progetto A utilizza il progetto B come biblioteca. In questo esempio, PropertiesService
è una risorsa non condivisa.
// 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')); } |
Aggiornare l'accesso agli script autonomi
Per gli script autonomi in esecuzione sul runtime V8, devi fornire agli utenti almeno accesso in visualizzazione allo script in modo che i trigger dello script funzionino correttamente.