Si vous disposez déjà d'un script utilisant l'environnement d'exécution Rhino et souhaitez l'utiliser de la syntaxe et des fonctionnalités V8, vous devez migrer le script vers V8.
La plupart des scripts écrits à l'aide de l'environnement d'exécution Rhino peuvent fonctionner avec un environnement d'exécution V8 sans aucun ajustement. Souvent la seule condition préalable à l'ajout de la syntaxe V8 et à un script est l'activation de l'environnement d'exécution V8.
Cependant, il existe un petit ensemble d'incompatibilités et d'autres différences pouvant entraîner la création d'un script une défaillance ou un comportement inattendu après l'activation de l'environnement d'exécution V8. Lorsque vous migrez un script vers V8, vous devez rechercher ces problèmes dans le projet de script et les corriger.
Procédure de migration V8
Pour migrer un script vers V8, procédez comme suit:
- Activez l'environnement d'exécution V8 pour le script.
- Examinez attentivement les incompatibilités. comme indiqué ci-dessous. Examinez votre script pour déterminer si des incompatibilités sont présentes ; en cas d'incompatibilité, ajustez le code de votre script pour supprimer ou éviter le problème.
- Examinez attentivement les autres différences listées ci-dessous. Examinez votre script pour déterminer si l'une des différences listées a un impact sur le comportement de votre code. Modifiez votre script pour corriger le comportement.
- Une fois que vous avez corrigé les éventuelles incompatibilités ou autres différentes, vous pouvez commencer à mettre à jour votre code pour utiliser Syntaxe V8 et autres fonctionnalités comme vous le souhaitez.
- Une fois les ajustements de code terminés, testez minutieusement votre script pour pour s'assurer qu'elle fonctionne comme prévu.
- Si votre script est une application Web ou un complément publié, vous devez créer une nouvelle version du script avec les ajustements V8. Pour que la version V8 soit accessible aux vous devez republier le script avec cette version.
Incompatibilités
L'environnement d'exécution Apps Script d'origine basé sur Rhino permettait malheureusement à plusieurs et les comportements ECMAScript non standards. V8 étant conforme aux normes, ces ne sont pas pris en charge après la migration. Si vous ne corrigez pas ces problèmes, des erreurs ou un comportement incorrect du script se produiront une fois l'environnement d'exécution V8 activé.
Les sections suivantes décrivent chacun de ces comportements et les étapes à suivre pour corriger le code de votre script lors de la migration vers V8.
Éviter la requête for each(variable in object)
La
for each (variable in object)
a été ajoutée à JavaScript 1.6 et supprimée au profit de for...of
.
Lorsque vous migrez votre script vers V8, évitez d'utiliser for each (variable in object)
.
de commande.
Utilisez plutôt 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); } |
Éviter la requête Date.prototype.getYear()
Dans l'environnement d'exécution initial de Rhino,
Date.prototype.getYear()
renvoie des années à deux chiffres pour les années 1900 à 1999, mais à quatre chiffres pour les autres
les dates, ce qui correspondait au comportement
dans JavaScript 1.2 et versions antérieures.
Dans l'environnement d'exécution V8, Date.prototype.getYear()
renvoie l'année moins 1900, comme l'exigent les normes ECMAScript.
Lorsque vous migrez votre script vers V8, utilisez toujours
Date.prototype.getFullYear()
,
qui renvoie une année à quatre chiffres, quelle que soit la date.
Évitez d'utiliser des mots clés réservés comme noms
ECMAScript interdit l'utilisation de certains mots clés réservés dans les noms de fonctions et de variables. L'environnement d'exécution Rhino autorisait de nombreux de ces mots. Par conséquent, si votre code les utilise, vous devez renommer vos fonctions ou variables.
Lorsque vous migrez votre script vers V8, évitez de nommer des variables ou des fonctions à l'aide de l'un des mots clés réservés.
Renommez toute variable ou fonction pour éviter d'utiliser le nom du mot clé. Utilisations courantes
des mots clés en tant que noms sont class
, import
et export
.
Éviter de réattribuer les variables const
Dans l'environnement d'exécution Rhino d'origine, vous pouvez déclarer une variable à l'aide de const
, qui
signifie que la valeur du symbole ne change jamais et que les futures attributions au
sont ignorés.
Dans le nouvel environnement d'exécution V8, le mot clé const
est conforme aux normes, et l'attribution à une variable déclarée comme const
génère une erreur d'exécution TypeError: Assignment to constant variable
.
Lorsque vous migrez votre script vers V8, n'essayez pas de redéfinir la valeur d'une variable 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 |
Éviter les littéraux XML et l'objet XML
Ce extension non standard à ECMAScript permet aux projets Apps Script d'utiliser directement la syntaxe XML.
Lorsque vous migrez votre script vers V8, évitez d'utiliser des littéraux XML directs ou le fichier XML objet.
Utilisez plutôt XmlService pour analyser un fichier 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 |
Ne pas créer de fonctions d'itérateur personnalisés à l'aide de __iterator__
JavaScript 1.7 a ajouté une fonctionnalité permettant d'ajouter un itérateur personnalisé à n'importe quelle clause clas.
en déclarant une fonction __iterator__
dans le prototype de cette classe ; c'était
également ajouté à l'environnement d'exécution Rhino d'Apps Script pour plus de commodité. Toutefois,
cette fonctionnalité n'a jamais fait partie
Norme ECMA-262
et a été supprimé des moteurs JavaScript compatibles ECMAScript. Scripts utilisant V8
ne peut pas utiliser cette construction d'itérateur.
Lorsque vous migrez votre script vers V8, évitez la fonction __iterator__
pour compiler
des itérateurs personnalisés. À la place,
Utilisez les itérateurs ECMAScript 6.
Prenons la construction de tableau suivante:
// 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. |
Les exemples de code suivants montrent comment construire un itérateur dans le Environnement d'exécution Rhino et comment créer un itérateur de remplacement dans l'environnement d'exécution 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); } |
Éviter les clauses catch conditionnelles
L'environnement d'exécution V8 n'est pas compatible avec les clauses Catch conditionnelle catch..if
, car elles
ne sont pas conformes à la norme.
Lorsque vous migrez votre script vers V8, déplacez les conditions de capture dans le corps de la capture :
// 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 } } |
Évitez d'utiliser Object.prototype.toSource()
JavaScript 1.3 contenait un Object.prototype.toSource() qui n'a jamais fait partie d'une norme ECMAScript. Elle n'est pas prise en charge dans l'environnement d'exécution V8.
Lorsque vous migrez votre script vers V8, supprimez toute utilisation de Object.prototype.toSource() de votre code.
Autres différences
En plus des incompatibilités ci-dessus qui peuvent entraîner des échecs de script, il existe quelques autres différences qui, si elles ne sont pas corrigées, peuvent entraîner un comportement inattendu du script d'exécution V8.
Les sections suivantes expliquent comment mettre à jour le code de votre script pour éviter ces surprises inattendues.
Ajuster la mise en forme de la date et de l'heure en fonction des paramètres régionaux
Date
méthodes toLocaleString()
,
toLocaleDateString()
,
et le comportement de toLocaleTimeString()
différemment dans l'environnement d'exécution V8
par rapport à Rhino.
Dans Rhino, le format par défaut est le format long. Tous les paramètres transmis sont ignorés.
Dans l'environnement d'exécution V8, le format par défaut est le format court et les paramètres.
transmises sont traitées conformément à la norme ECMA (consultez la
Documentation toLocaleDateString()
pour plus de détails).
Lorsque vous migrez votre script vers V8, testez et ajustez les attentes de votre code concernant la sortie des méthodes de date et d'heure spécifiques à la langue :
// 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' })); |
Évitez d'utiliser Error.fileName
et Error.lineNumber
.
Dans la version V8, le code JavaScript standard
Error
ne prend pas en charge fileName
ou lineNumber
comme paramètres de constructeur
ou les propriétés d'objet.
Lors de la migration de votre script vers V8,
supprimer toute dépendance à Error.fileName
et Error.lineNumber
.
Vous pouvez aussi utiliser la classe
Error.prototype.stack
Cette pile n'est pas non plus standard, mais elle est compatible avec Rhino et V8. La
format de la trace de la pile produite par les deux plates-formes est légèrement différent:
// 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) |
Ajuster le traitement des objets d'énumération concaténés
Dans l'environnement d'exécution d'origine de Rhino, en utilisant le code JavaScript
JSON.stringify()
sur un objet enum ne renvoie que {}
.
Dans V8, l'utilisation de la même méthode sur un objet enum réinitialise le nom d'énumération.
Lors de la migration de votre script vers V8,
de tester et d'ajuster les attentes de votre code par rapport à la sortie
JSON.stringify()
sur les objets 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" |
Ajuster le traitement des paramètres non définis
Dans l'environnement d'exécution Rhino d'origine, transmettre undefined
à une méthode en tant que paramètre.
a permis de transmettre la chaîne "undefined"
à cette méthode.
Dans V8, transmettre undefined
aux méthodes équivaut à transmettre null
.
Lorsque vous migrez votre script vers V8, testez et ajustez les attentes de votre code concernant les paramètres 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. |
Ajuster la gestion des this
globaux
L'environnement d'exécution Rhino définit un contexte spécial implicite pour les scripts qui l'utilisent.
Le code du script s'exécute dans ce contexte implicite, distinct du contexte global réel
this
Cela signifie que les références au "this
global" dans le code,
évaluer le contexte spécial, qui ne contient que le code et les variables
défini dans le script. Services Apps Script intégrés et objets ECMAScript
sont exclus de cette utilisation de this
. Cette situation était semblable à la structure JavaScript suivante :
// 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. }(); |
Dans V8, le contexte spécial implicite est supprimé. Variables et fonctions globales
définies dans le script sont placés dans le contexte global, à côté de l'élément
Services Apps Script et composants ECMAScript intégrés comme Math
et Date
Lors de la migration de votre script vers la version 8, testez votre code et ajustez ses attentes.
concernant l'utilisation de this
dans un contexte global. Dans la plupart des cas, les différences
ne sont visibles que si votre code examine les clés ou les noms de propriétés
objet this
global:
// 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)); } |
Ajuster le traitement de instanceof
dans les bibliothèques
Utiliser instanceof
dans une bibliothèque sur un objet transmis en tant que paramètre dans un
d'un autre projet peut donner des faux négatifs. Dans l'environnement d'exécution V8,
et ses bibliothèques s'exécutent dans des contextes d'exécution différents.
différents éléments généraux et
chaînes de prototypes.
Notez que ce n'est le cas que si votre bibliothèque utilise instanceof
sur un objet.
qui n'est pas créé dans votre projet. Son utilisation sur un objet créé
que ce soit dans le même script ou dans un script différent au sein de votre projet,
doit fonctionner comme prévu.
Si un projet exécuté sur V8 utilise votre script comme bibliothèque, vérifiez si votre
script utilise instanceof
sur un paramètre qui sera transmis depuis un autre projet. Ajuster
l'utilisation de instanceof
et d'autres alternatives possibles selon votre utilisation
cas.
Une alternative à a instanceof b
peut consister à utiliser le constructeur de a
dans
les cas où vous n'avez pas besoin d'effectuer une
recherche dans l'ensemble de la chaîne de prototypes et de vérifier
au constructeur.
Utilisation: a.constructor.name == "b"
Prenons l'exemple des projets A et B, où le projet A utilise le projet B comme bibliothèque.
//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 } |
Une autre alternative peut consister à introduire une fonction qui vérifie instanceof
dans le projet principal
et transmettre la fonction en plus d'autres paramètres lors de l'appel d'une fonction de bibliothèque. La fonction transmise
peut ensuite être utilisé pour vérifier instanceof
dans la bibliothèque.
//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); } |
Ajuster la transmission de ressources non partagées aux bibliothèques
La transmission d'une ressource non partagée du script principal à une bibliothèque fonctionne différemment dans l'environnement d'exécution V8.
Dans l'environnement d'exécution Rhino, la transmission d'une ressource non partagée ne fonctionne pas. La bibliothèque utilise à la place sa propre ressource.
Dans l'environnement d'exécution V8, la transmission d'une ressource non partagée à la bibliothèque fonctionne. La bibliothèque utilise la ressource non partagée transmise.
Ne transmettez pas de ressources non partagées en tant que paramètres de fonction. Déclarez toujours les ressources non partagées dans le script qui les utilise.
Prenons l'exemple des projets A et B, dans lesquels le projet A utilise le projet B comme bibliothèque. Dans cet exemple, PropertiesService
est une ressource non partagée.
// 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')); } |
Modifier l'accès aux scripts autonomes
Pour les scripts autonomes exécutés sur l'environnement d'exécution V8, vous devez fournir aux utilisateurs au moins un accès en lecture au script pour que ses déclencheurs fonctionnent correctement.