V8 in Google Apps Script - Files are parsed in a certain order

208 views
Skip to first unread message

Alan Wells

unread,
Feb 25, 2020, 12:42:35 PM2/25/20
to Google Apps Script Community
Avoid calling functions before they are parsed


From the documentation, it seems that there is only a problem if somehow a global variable is involved.  That's what I'm hoping.  Am I wrong?

All my functions are in the "normal" format of:

File A1
function abc_() {
 
//code
}

File Z30
function xyz_() {
 
//code
}

I don't have functions assigned to global variables:

var myFunction = function() {
 
//code
}

If I have 30 "gs" server files, and there is a function in the file that gets parsed first, that calls a function in the 30th file that gets parsed last, could there ever be a problem with that function in the 30th file not being found because it hasn't been parsed yet?

File That Gets Parsed First.gs
function abc_() {
  xyz_
();//Call function xyz_() in file number 30 that gets parsed last
}

If the new V8 version does work exactly like <script> tags in the browser, (which the documentation says it does) then I'm assuming that there could be a problem.

But the example only covers a variable being used in the global scope.

So, I'm not sure what to think.  And when trying to test this, it would seem that it might work 100 times, and then randomly fail on the 101st run.
So, we might think that it is working, and then be wrong.

I understand what to do about the global variables with the V8 version, but do I need to know the exact parse order of every file, and make sure that every function is never calling a function that is in a file that gets parsed aftwards?

CBMServices Web

unread,
Feb 25, 2020, 12:54:39 PM2/25/20
to google-apps-sc...@googlegroups.com
This seems to me like a bug in Google V8. Order of functions should not affect execution per Javascript rules. Rhino respected that and V8 should as well.

Did anyone open a ticket on this?

--
You received this message because you are subscribed to the Google Groups "Google Apps Script Community" group.
To unsubscribe from this group and stop receiving emails from it, send an email to google-apps-script-c...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/google-apps-script-community/5d746098-8907-46bd-8598-5e90cd3897f9%40googlegroups.com.

Adam Morris

unread,
Feb 26, 2020, 6:33:29 AM2/26/20
to google-apps-sc...@googlegroups.com
I don't think there is a bug, nor do I think we can expect Rhino to do what V8. I'll try to explain.

We have to understand that V8 is a modern JavaScript engine that optimizes everything it possibly can, including when it is "parsed." What parsing does is convert the human-entered code into a syntax tree (which will eventually become machine code) and by changing how parsing occurs we can exact performance improvements. So the V8 engine is lazy about it (lazy=delay until the last possible moment to avoid parsing everything), which is why the behaviour is different from Rhino.

If the engine were to parse the files in the above way, it can avoid parsing all of the files, which is why lazy is a thing in the engine.

So back to the core problem. Variables and functions cannot be guaranteed to be available when executing from within the top-level global scope context. What is that exactly? That's the part of the file that gets parsed before the target endpoint is executed. And then it executes the endpoint, at which point we can assume all of the needed files are parsed, and thus all variables and functions are available.

Digging deeper, take this example:

// Code.gs
const thisIsParsedBeforeMyEndpoint = 'variable in the global scope';

function myEndpoint () {
   const thisIsParsedAfterAllOtherFilesHaveBeenParsed = 'variable defined in the endpoint';
   anotherFunction();
}

// Code2.gs
const thisIsParsedSecondMaybe = 'another variable in the global scope';
// const nope = thisIsParsedBeforeMyEndpoint;  // this would throw an error if wasn't commented out

function anotherFunction () {
  Logger.log(thisIsParsedBeforeMyEndpoint); // all good
}

What I'm trying to illustrate above with bad variable names is how I think of it working. Any code that is being executed as a result of the endpoint being executed will have all the stuff that was in the global scope. But we can't assume that variables defined in the global scope in one file will be available in other.

Hope it helps.






DISCLAIMER:
This e-mail and the attachment is intended solely for the person to whom they are addressed and may be confidential and privileged. If you are not the intended recipient, you are notified that disclosing, distributing, copying or taking any action in reliance on the contents of this information is strictly prohibited. Please notify the sender immediately if you have received this email and delete it from your system. The recipient should check the email and any attachments for the presence of viruses that could be transmitted via email. Email transmission cannot be guaranteed to be secure or error-free as information could be intercepted, corrupted, lost, destroyed, incomplete or contain viruses. Detik Harapan Sdn. Bhd. accepts no liability for any errors or omissions in the contents of this message which arise as a result of email transmission. Opinions, conclusions and other information in this email that does not relate to Detik Harapan Sdn. Bhd.'s official business shall be understood as neither given nor endorsed by Detik Harapan Sdn. Bhd.

Alan Wells

unread,
Feb 26, 2020, 10:41:30 AM2/26/20
to Google Apps Script Community
Please correct me if I'm wrong on any logic or terminology.
My (probably limited) understanding of the situation
  • Anything outside of any code block (Curly braces) is in the global scope.
  • When something triggers code to run, the code is first "parsed" (Hopefully that's the correct term)
  • During the parsing, and even before the parsing is completely done, lines of code in the global scope will be executed.  (This is where the potential problem happens)
    • "Execution" meaning a function call or a variable being assigned a value.
If I don't have a variable, or constant or a function call in the global scope, or something like an Immediately Invoked Function Expression (IIFE) then the order in which the files get parsed should be immaterial to me.  Everything will get parsed, and then the function (Not run from the global scope) will run.  No problems.
To unsubscribe from this group and stop receiving emails from it, send an email to google-apps-script-community+unsub...@googlegroups.com.

--
You received this message because you are subscribed to the Google Groups "Google Apps Script Community" group.
To unsubscribe from this group and stop receiving emails from it, send an email to google-apps-script-community+unsub...@googlegroups.com.

Adam Morris

unread,
Feb 26, 2020, 12:15:21 PM2/26/20
to google-apps-sc...@googlegroups.com
More or less.

Consider that in order to even have functions available at all, the global scope has to be parsed. The function declaration is also code in the global scope, but not the body. 

Making functions is just making variables with special powers. I always tell my students that. 


To unsubscribe from this group and stop receiving emails from it, send an email to google-apps-script-c...@googlegroups.com.

--
You received this message because you are subscribed to the Google Groups "Google Apps Script Community" group.
To unsubscribe from this group and stop receiving emails from it, send an email to google-apps-script-c...@googlegroups.com.
DISCLAIMER:
This e-mail and the attachment is intended solely for the person to whom they are addressed and may be confidential and privileged. If you are not the intended recipient, you are notified that disclosing, distributing, copying or taking any action in reliance on the contents of this information is strictly prohibited. Please notify the sender immediately if you have received this email and delete it from your system. The recipient should check the email and any attachments for the presence of viruses that could be transmitted via email. Email transmission cannot be guaranteed to be secure or error-free as information could be intercepted, corrupted, lost, destroyed, incomplete or contain viruses. Detik Harapan Sdn. Bhd. accepts no liability for any errors or omissions in the contents of this message which arise as a result of email transmission. Opinions, conclusions and other information in this email that does not relate to Detik Harapan Sdn. Bhd.'s official business shall be understood as neither given nor endorsed by Detik Harapan Sdn. Bhd.

--
You received this message because you are subscribed to the Google Groups "Google Apps Script Community" group.
To unsubscribe from this group and stop receiving emails from it, send an email to google-apps-script-c...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/google-apps-script-community/c1c67d9b-5a21-4b9c-9d3c-fcf1a933fc5f%40googlegroups.com.

Alex

unread,
Feb 26, 2020, 12:25:58 PM2/26/20
to google-apps-sc...@googlegroups.com
There is a part of the question https://groups.google.com/forum/#!topic/google-apps-script-community/Pb_8yxRmvpE

Also I'd like say that I'm thinking for using a singleton as a global variable

const _global_ = {
  a
: 10;
}

class App {
  constructor
(){
   
if(! App.instance){
     
Object.assign(this, _global_);
     
App.instance = this;
   
}
   
return App.instance;
 
}
}

Another file

console.log(new App().a);

works fine.

CBM Services

unread,
Feb 26, 2020, 1:02:37 PM2/26/20
to google-apps-sc...@googlegroups.com
I read your description of the issue and it seems to me the core issue is the choice of making V8 be a lazy parser as compared to Rhino. I do understand need for efficiency but it needs to be mindful of not breaking functionality.

I do have global variables in multiple files. Trying to sort out what scenario will work and which will not on an application that has 30k+ LOC will be complicated if not confusing.

I hope migration tools to V8 will be extremely helpful otherwise, many will probably stay on Rhino for a while to come.

From: Adam Morris
Sent: ‎2020-‎02-‎26 9:15 AM
To: google-apps-sc...@googlegroups.com
Subject: Re: [Apps-Script] V8 in Google Apps Script - Files are parsed in acertain order

Alan Wells

unread,
Feb 26, 2020, 1:31:23 PM2/26/20
to Google Apps Script Community
I put all my global variables in one file.  I put them into a file that is high on the list of "gs" files in order, right behind "Code dot gs".  If the files are parsed in the order in which they are shown in the code editor, without the "View" "Sort files alphabetically" checked, then that file with your globals should be parsed soon enough so that there isn't a problem. (As long as your Code_gs file doesn't need them)  As a rule, I only put simple triggers into the Code dot gs file.
In order to avoid lots of global variable names, I have a global object, and in that global object you can put any properties that you need.  So, if you want to reuse code in some other app that won't have the same global variable names, but can have the same generic global object name, then all you need to worry about is the property (key) names.

Alan Wells

unread,
Feb 26, 2020, 2:09:01 PM2/26/20
to Google Apps Script Community
Even though the function declaration is in the global scope, given the following example, only the log line in the global scope will run and get printed to the logs.

Code.gs

Logger.log('This runs when file is parsed')

function myFunction() {//Function declaration
 
Logger.log('This wont print to the logs when the file is parsed');
 
Logger.log('this only runs if this function is called')
}


So, even though the function declaration is in the global scope, it doesn't seem to react to the file being parsed.
To unsubscribe from this group and stop receiving emails from it, send an email to google-apps-script-community+unsub...@googlegroups.com.

--
You received this message because you are subscribed to the Google Groups "Google Apps Script Community" group.
To unsubscribe from this group and stop receiving emails from it, send an email to google-apps-script-community+unsub...@googlegroups.com.
DISCLAIMER:
This e-mail and the attachment is intended solely for the person to whom they are addressed and may be confidential and privileged. If you are not the intended recipient, you are notified that disclosing, distributing, copying or taking any action in reliance on the contents of this information is strictly prohibited. Please notify the sender immediately if you have received this email and delete it from your system. The recipient should check the email and any attachments for the presence of viruses that could be transmitted via email. Email transmission cannot be guaranteed to be secure or error-free as information could be intercepted, corrupted, lost, destroyed, incomplete or contain viruses. Detik Harapan Sdn. Bhd. accepts no liability for any errors or omissions in the contents of this message which arise as a result of email transmission. Opinions, conclusions and other information in this email that does not relate to Detik Harapan Sdn. Bhd.'s official business shall be understood as neither given nor endorsed by Detik Harapan Sdn. Bhd.

--
You received this message because you are subscribed to the Google Groups "Google Apps Script Community" group.
To unsubscribe from this group and stop receiving emails from it, send an email to google-apps-script-community+unsub...@googlegroups.com.

Alex

unread,
Feb 27, 2020, 11:24:41 PM2/27/20
to Google Apps Script Community
Caution: It's not best practice to rely on a specific file parse order to avoid this issue. The sequence of script file parsing can change if script files are copied, removed, renamed, or otherwise rearranged. It's better to remove any global variable dependency on function calls if possible.

Nathan Hendricks

unread,
Jun 9, 2021, 11:36:03 AM6/9/21
to Google Apps Script Community
Hi Folks,

I'm trying to figure out if this is related. I have some global variables I declare in my script,. They were working on Rhino but now they're not. 

//file globalVariables.gs
var doc = DocumentApp.getActiveDocument();
var coolArray = [doc.getName(), 'cat', 'potato', 'microphone'] 

They're in the same file, so I'm wondering if the DocumentApp service functions are read into the global context after my global variable declaration. 

Related or nah?

-- Nathan 

Alan Wells

unread,
Jun 9, 2021, 1:13:02 PM6/9/21
to Google Apps Script Community
Unless there is an error message, then I'm guessing that the issue is related to V8.

Nathan Hendricks

unread,
Jun 9, 2021, 1:18:08 PM6/9/21
to google-apps-sc...@googlegroups.com
Yeah, error message is: 

TypeError: doc.getName is not a function at [unknown function]

--
You received this message because you are subscribed to a topic in the Google Groups "Google Apps Script Community" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/google-apps-script-community/wqIdm0Cfj0g/unsubscribe.
To unsubscribe from this group and all its topics, send an email to google-apps-script-c...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/google-apps-script-community/fae945a7-cf6d-485e-a85d-cb95e47a6cb8n%40googlegroups.com.

CBMServices Web

unread,
Jun 9, 2021, 1:23:58 PM6/9/21
to google-apps-sc...@googlegroups.com
Have never tried to put code (getActiveDoc) in my global variables. But looks like V8 does not like it.

Those may be better to have inside you functions rather than global variables though.

--
You received this message because you are subscribed to the Google Groups "Google Apps Script Community" group.
To unsubscribe from this group and stop receiving emails from it, send an email to google-apps-script-c...@googlegroups.com.

Alan Wells

unread,
Jun 9, 2021, 1:30:26 PM6/9/21
to Google Apps Script Community
The error message is not stating that "doc" is undefined.
If "doc" were undefined, then I'd say that somehow the line:
var doc = DocumentApp.getActiveDocument();
was not getting executed before your next line.
That error message makes me think that you omitted the parenthesis on the end.
getName is not a function call but  getName() is.

Nathan Hendricks

unread,
Jun 9, 2021, 1:40:44 PM6/9/21
to google-apps-sc...@googlegroups.com
Yeah, it's confusing because the parentheses are there. "doc" logs as "Document," as I'd expect, but its methods aren't callable. 

Code:
var doc = DocumentApp.getActiveDocument();
Logger.log(doc);
var docName = doc.getName();
Logger.log(docName);

Output:
Jun 9, 2021, 1:34:24 PM
Info
Document
Jun 9, 2021, 1:34:24 PM
Error
TypeError: doc.getName is not a function at [unknown function](Global Variables:21:19)

You received this message because you are subscribed to a topic in the Google Groups "Google Apps Script Community" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/google-apps-script-community/wqIdm0Cfj0g/unsubscribe.
To unsubscribe from this group and all its topics, send an email to google-apps-script-c...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/google-apps-script-community/56e4b5a8-9dbb-45bd-a52f-ae27ac22a01en%40googlegroups.com.

Nathan Hendricks

unread,
Jun 9, 2021, 1:45:56 PM6/9/21
to google-apps-sc...@googlegroups.com
oh, and when I turn off V8, everything works (no logging though). 

Alan Wells

unread,
Jun 9, 2021, 1:52:13 PM6/9/21
to Google Apps Script Community
Try:

(function(){
  //file globalVariables.gs
  doc = DocumentApp.getActiveDocument();
  coolArray = [doc.getName(), 'cat', 'potato', 'microphone'] 
})();

Edward Wu

unread,
Jun 10, 2021, 2:35:39 PM6/10/21
to google-apps-sc...@googlegroups.com
We seem to be running into this issue more and more recently. Is anyone else having these problems and is there a better way to deal with them?

The issue: formulas in Google Sheets don't seem to be returning the most up-to-date info when a script runs. But when the script is run manually, it seems to be fine.
(This seems especially unstable when the formulas deal with importranges. I really *feel* like Google Sheets has been caching importranges more heavily recently...at least when it comes to getting up-to-date data when the GS is "closed" (i.e. no human has it open))

e.g. we have a Google Sheet that has a formula (named range: "wasHoliday") that tries to determine if yesterday was a holiday by looking at the info on the Sheet. Then it returns a "yes" or a "no".

The script runs at night on a daily trigger. The GAS grabs the value with this:
  var holiday = ss.getSheetByName("evaluateYesterdayForEmails").getRange('wasHoliday').getDisplayValue();

Then we have an if state that does stuff depending on whether it's a "yes" or a "no".

That's been working fine for a long time, but recently, it seems to grab incorrect values once in a while.

So I'm trying to workaround this: grab the formula, blank it out, then set the formula back in *before* trying to grab the value:

  var holidayFormula = ss.getSheetByName("evaluateYesterdayForEmails").getRange('wasHoliday').getFormula();  
  ss.getSheetByName("evaluateYesterdayForEmails").getRange('wasHoliday').setValue("");
  ss.getSheetByName("evaluateYesterdayForEmails").getRange('wasHoliday').setFormula(holidayFormula);
  SpreadsheetApp.flush();

That seems to be working so far, but it seems a bit overengineered and not ideal, and I'm not sure if it will keep working, since the problem is sporatic.

Does anyone have any idea what's going on? GAS seems to be a bit unstable lately, and I'm wondering if, long term, we should be coding these sorts of things differently. Or is this just a blip and "deal with it" for now?

Alan Wells

unread,
Jun 10, 2021, 2:45:59 PM6/10/21
to Google Apps Script Community
It's probably better to have a new thread for your post.

Edward Wu

unread,
Jun 10, 2021, 2:56:56 PM6/10/21
to google-apps-sc...@googlegroups.com
Sorry, I'm not sure what you mean. This is a new thread.

--
You received this message because you are subscribed to the Google Groups "Google Apps Script Community" group.
To unsubscribe from this group and stop receiving emails from it, send an email to google-apps-script-c...@googlegroups.com.

Alan Wells

unread,
Jun 10, 2021, 9:03:17 PM6/10/21
to Google Apps Script Community

Adam Morris

unread,
Jun 11, 2021, 1:09:30 AM6/11/21
to google-apps-sc...@googlegroups.com
This is a curious error. In a brand new container-bound script with V8 enabled, it works as expected. Code and output below.

The only thing I can think that would cause what you're seeing is if you redefine DocumentApp somewhere else in your project. A library that uses the same identifier?

const doc = DocumentApp.getActiveDocument();
Logger.log(doc);
const name = doc.getName();
Logger.log({name});

function hey () {

}

image.png

--
You received this message because you are subscribed to the Google Groups "Google Apps Script Community" group.
To unsubscribe from this group and stop receiving emails from it, send an email to google-apps-script-c...@googlegroups.com.

Edward Wu

unread,
Jun 11, 2021, 1:46:57 PM6/11/21
to google-apps-sc...@googlegroups.com

Edward Wu

unread,
Jun 14, 2021, 9:30:02 PM6/14/21
to google-apps-sc...@googlegroups.com
(I apologize in advance if this shows up on the "V8 in Google Apps Script - Files are parsed in a certain order" thread again. I'm not sure why that's happening. I'm creating this email from scratch).
Reply all
Reply to author
Forward
0 new messages