Se você já tem um script que usa o ambiente de execução do Rhino e quer usá-lo da sintaxe e dos recursos do V8, é necessário migrar o script para o V8.
A maioria dos scripts escritos com o tempo de execução do Rhino podem operar usando um tempo de execução V8 sem ajuste. Muitas vezes, o único pré-requisito para adicionar a sintaxe do V8 e recursos a um script Ativar o ambiente de execução do V8.
No entanto, há um pequeno conjunto de incompatibilidades e outras diferenças que podem resultar em um script falhando ou se comportando de maneira inesperada após ativar o ambiente de execução V8. Ao migrar um script para usar o V8, você deve procurar esses problemas no projeto de script e corrigir os que você encontrar.
Procedimento de migração do V8
Para migrar um script para o V8, siga este procedimento:
- Ativar o ambiente de execução do V8 para o script.
- Analisar cuidadosamente as incompatibilidades listadas abaixo. Examine seu script para determinar se alguma das incompatibilidades; se houver uma ou mais incompatibilidades, ajustar o código do script para remover ou evitar o problema.
- Analise com atenção as outras diferenças listadas abaixo. Examine seu script para determinar se alguma das diferenças listadas impacta o comportamento do código. Ajuste o script para corrigir o comportamento.
- Depois de corrigir as incompatibilidades ou outras você pode começar a atualizar seu código para usar Sintaxe do V8 e outros recursos (link em inglês) como quiser.
- Depois de concluir os ajustes de código, teste o script por completo para garantir se ele se comporta como esperado.
- Se o script for um app da Web ou um complemento publicado, você precisa criar uma nova versão do script com os ajustes do V8. Para disponibilizar a versão V8 para você precisará publicar o script novamente com essa versão.
Incompatibilidades
Infelizmente, o tempo de execução original do Apps Script baseado no Rhino permitia vários comportamentos ECMAScript não padrão. Como o V8 é compatível com os padrões, esses após a migração. A falha na correção desses problemas resulta em erros ou comportamento incorreto do script quando o ambiente de execução V8 é ativado.
As seções a seguir descrevem cada um desses comportamentos e etapas que você precisa seguir para corrigir o código do script durante a migração para o V8.
Evite for each(variable in object)
O
for each (variable in object)
foi adicionada ao JavaScript 1.6 e removida em favor de for...of
.
Ao migrar seu script para o V8, evite usar for each (variable in object)
.
comuns.
Em vez disso, use 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); } |
Evite Date.prototype.getYear()
No ambiente de execução original do Rhino,
Date.prototype.getYear()
retorna anos de dois dígitos para anos de 1900 a 1999, mas anos de quatro dígitos para outras
datas, que era o comportamento no JavaScript 1.2 e versões anteriores.
No ambiente de execução do V8,
Date.prototype.getYear()
retorna o ano menos 1900 em vez disso, conforme exigido pelo
ECMAScript.
Ao migrar seu script para o V8, sempre use
Date.prototype.getFullYear()
,
que retorna um ano com quatro dígitos, independentemente da data.
Evite usar palavras-chave reservadas como nomes
O ECMAScript proíbe o uso de determinados palavras-chave reservadas em nomes de funções e variáveis. O tempo de execução do Rhino permitia muitas dessas palavras, então, se o seu código os usar, você deve renomear suas funções ou variáveis.
Ao migrar seu script para o V8, evite nomear variáveis ou funções
usando um dos
palavras-chave reservadas.
Renomeie as variáveis ou funções para evitar o uso do nome da palavra-chave. Os usos comuns
de palavras-chave como nomes são class
, import
e export
.
Evite reatribuir variáveis const
No ambiente de execução original do Rhino, é possível declarar uma variável usando const
, o que
significa que o valor do símbolo nunca muda e as atribuições futuras para o
símbolo são ignoradas.
No novo ambiente de execução do V8, a palavra-chave const
é compatível com padrão e atribuindo
como uma variável declarada como const
resulta em uma
TypeError: Assignment to constant variable
erro de tempo de execução.
Ao migrar seu script para o V8, não tente reatribuir o valor de
uma variável 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 |
Evite literais XML e o objeto XML.
Isso extensão não padrão ao ECMAScript permite que os projetos do Apps Script usem a sintaxe XML diretamente.
Ao migrar seu script para o V8, evite usar literais XML diretos ou o objeto XML.
Em vez disso, use o XmlService para analisar 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 |
Não crie funções iteradoras personalizadas usando __iterator__
.
O JavaScript 1.7 adicionou um recurso para permitir a adição de um iterador personalizado a qualquer clas.
s declarando uma função __iterator__
no protótipo dessa classe. isso era
também foi adicionado ao tempo de execução do Rhino do Apps Script para facilitar o desenvolvimento. No entanto,
esse recurso nunca fez parte
Padrão ECMA-262
e foi removida em mecanismos JavaScript compatíveis com ECMAScript. Scripts usando a V8
não é possível usar essa construção de iterador.
Ao migrar seu script para o V8, evite criar a função __iterator__
iteradores personalizados. Em vez disso,
usar iteradores ECMAScript 6.
Considere a seguinte construção de matriz:
// 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. |
Os exemplos de código a seguir mostram como um iterador pode ser construído na Tempo de execução do Rhino e como criar um iterador substituto no ambiente de execução do 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); } |
Evitar cláusulas catch condicionais
O ambiente de execução V8 não oferece suporte a cláusulas de captura condicional catch..if
, porque elas
não são compatíveis com o padrão.
Ao migrar seu script para o V8, mova todas as condições de catch para dentro do corpo de catch:
// 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 } } |
Evitar usar Object.prototype.toSource()
O JavaScript 1.3 continha um método Object.prototype.toSource() que nunca fez parte de nenhum padrão ECMAScript. Ele não é compatível com o ambiente de execução do V8.
Ao migrar seu script para o V8, remova qualquer uso de Object.prototype.toSource() do seu código.
Outras diferenças
Além das incompatibilidades acima que podem causar falhas de script, há Há algumas outras diferenças que, se não forem corrigidas, podem resultar em erros o comportamento do script de tempo de execução.
As seções a seguir explicam como atualizar o código do script para evitar essas de surpresas inesperadas.
Ajustar a formatação de data e hora específica da localidade
O Date
métodos toLocaleString()
,
toLocaleDateString()
,
e toLocaleTimeString()
se comportam
de forma diferente no tempo de execução do V8 em comparação com o Rhino.
No Rhino, o formato padrão é o longo e todos os parâmetros transmitidos são ignorados.
No ambiente de execução do V8, o formato padrão é o formato curto e os parâmetros
transmitidos são tratados de acordo com o padrão ECMA (consulte a
Documentação do toLocaleDateString()
para mais detalhes).
Ao migrar seu script para o V8, teste e ajuste as expectativas do código com relação à saída de métodos de data e hora específicos da localidade:
// 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' })); |
Evite usar Error.fileName
e Error.lineNumber
No untime do V8, o JavaScript padrão
Error
O objeto não oferece suporte à fileName
ou lineNumber
como parâmetros do construtor.
ou propriedades de objetos.
Ao migrar seu script para o V8,
remova qualquer dependência de Error.fileName
e Error.lineNumber
.
Uma alternativa é usar o
Error.prototype.stack
.
Essa pilha também não é padrão, mas é compatível com o Rhino e o V8. O
do stack trace produzido pelas duas plataformas é um pouco diferente:
// 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) |
Ajustar o processamento de objetos "enum" em strings
No tempo de execução original do Rhino, usando o JavaScript
JSON.stringify()
em um objeto de tipo enumerado retorna apenas {}
.
No V8, usar o mesmo método em um objeto de tipo enumerado redefine o nome do tipo enumerado.
Ao migrar seu script para o V8,
testar e ajustar as expectativas do código em relação ao resultado
JSON.stringify()
em objetos de tipo enumerado:
// 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" |
Ajustar o tratamento de parâmetros indefinidos
No ambiente de execução original do Rhino, transmitir undefined
para um método como parâmetro
resultou na transmissão da string "undefined"
para esse método.
No V8, transmitir undefined
aos métodos é equivalente a transmitir null
.
Ao migrar seu script para o V8,
Teste e ajuste as expectativas do código em relação aos parâmetros 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. |
Ajuste do processamento de this
global
O tempo de execução do Rhino define um contexto especial implícito para os scripts que o usam.
O código de script é executado nesse contexto implícito, diferente do código global
this
: Isso significa que as referências ao "this
global" no código,
avaliar para o contexto especial, que contém apenas o código e as variáveis
definido no script. Os serviços integrados do Apps Script e os objetos ECMAScript
estão excluídos do uso de this
. Essa situação era semelhante a esta
estrutura de 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. }(); |
No V8, o contexto especial implícito é removido. Variáveis e funções globais
definidas no script são colocadas no contexto global, além dos serviços integrados
do Apps Script e ECMAScript integrados, como Math
e Date
.
Ao migrar seu script para o V8, teste e ajuste as expectativas do seu código
sobre o uso de this
em um contexto global. Na maioria dos casos, as diferenças
só ficam aparentes se o código examinar as chaves ou os nomes de propriedades do
objeto 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)); } |
Ajustar o processamento de instanceof
nas bibliotecas
O uso de instanceof
em uma biblioteca em um objeto transmitido como parâmetro em uma
função de outro projeto pode gerar falsos negativos. No ambiente de execução do V8,
o projeto e as bibliotecas dele são executados em diferentes contextos de execução e, portanto, têm
redes globais e de protótipos.
Isso só acontece se a biblioteca usar instanceof
em um objeto
que não foi criado no projeto. Ele é usado em um objeto criado
em seu projeto, seja no mesmo script ou em um diferente dentro dele,
deve funcionar conforme o esperado.
Se um projeto executado no V8 usar seu script como uma biblioteca, verifique se o
O script usa instanceof
em um parâmetro que será transmitido de outro projeto. Ajustar
o uso de instanceof
e outras alternativas viáveis de acordo com seu uso;
caso.
Uma alternativa para a instanceof b
pode ser usar o construtor de a
no
casos em que você não precisa pesquisar toda a cadeia de protótipos e apenas verificar
o construtor.
Uso: a.constructor.name == "b"
Considere o Projeto A e o Projeto B, em que o Projeto A usa o Projeto B como uma 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 } |
Outra alternativa pode ser introduzir uma função que verifica instanceof
no projeto principal
e transmitir a função além de outros parâmetros ao chamar uma função de biblioteca. A função transmitida
pode ser usada para conferir o instanceof
na biblioteca.
//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); } |
Ajustar a transmissão de recursos não compartilhados para bibliotecas
A transmissão de um recurso não compartilhado do script principal para uma biblioteca funciona de maneira diferente no tempo de execução do V8.
No ambiente de execução do Rhino, a transmissão de um recurso não compartilhado não funciona. Em vez disso, a biblioteca usa o próprio recurso.
No ambiente de execução do V8, é possível transmitir um recurso não compartilhado para a biblioteca. A biblioteca usa o recurso não compartilhado transmitido.
Não transmita recursos não compartilhados como parâmetros de função. Sempre declare recursos não compartilhados no mesmo script que os utiliza.
Considere o Projeto A e o Projeto B, em que o Projeto A usa o Projeto B como uma biblioteca. Neste exemplo, PropertiesService
é um recurso não compartilhado.
// 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')); } |
Atualizar o acesso a scripts independentes
Para scripts independentes em execução no ambiente de execução do V8, você precisa fornecer aos usuários pelo menos acesso de leitura ao script para que os acionadores funcionem corretamente.