【问题标题】:How to use global variables while avoiding permission errors?如何在避免权限错误的同时使用全局变量?
【发布时间】:2020-12-04 20:21:29
【问题描述】:

请看下面的例子,

function doSomething1(){/*needs ss*/const ss = SpreadsheetApp.openById(/*SPREADSHEET_ID*/);}
function doSomething2(){/*needs ss*/const ss = SpreadsheetApp.openById(/*SPREADSHEET_ID*/);}
function doItAll(){
  doSomething1();
  doSomething2();
}

不用在两个函数中调用电子表格,这可以使用全局变量来简化

const ss = SpreadsheetApp.openById(/*SPREADSHEET_ID*/);
function doSomething1(){/*do something with ss*/}
function doSomething2(){/*do something with ss*/}
function doItAll(){
  doSomething1();
  doSomething2();
}

这里的问题可以在不使用全局变量的情况下解决,只需在函数之间传递ss变量即可。但是,如果需要访问ss 变量的多个函数,这将变得更加复杂。传递ss 很麻烦。没有很多方法可以避免 Apps 脚本中的全局变量。不支持模块。如果您使用 IIFE,则所有函数都对 IDE 隐藏 - 从 IDE 或其他任何地方调用函数是不可能的。在这里使用全局变量要优雅得多。但是如果我有一个简单的触发器就会出现问题:

const ss = SpreadsheetApp.openById(/*SPREADSHEET_ID*/);
function doSomething1(){/*do something with ss*/}
function doSomething2(){/*do something with ss*/}
function doItAll(){
  doSomething1();
  doSomething2();
}
function onOpen(){/*Adds a menu*/}

菜单添加onOpen 将失败,因为此行在onOpen 之前加载了SpreadsheetApp.openById(/*SPREADSHEET_ID*/),并且该行需要权限/授权,而onOpen 作为一个简单的触发器不会运行任何需要授权的代码。

如何在不遇到授权错误的情况下声明全局变量?

【问题讨论】:

    标签: google-apps-script google-sheets global-variables lazy-loading


    【解决方案1】:

    这个问题可以通过使用getter 来解决。 getter 仅在从任何地方调用时才执行代码,从而将代码的执行封装在全局上下文中。但是 getter 将在每次调用变量时执行。如果在两个函数中调用ss,则SpreadsheetApp.openById 会执行两次。我们可以使用 MDN 中提到的lazy loading technique 来避免这种情况。

    const config = {
      get ss() {
        delete this.ss;
        return (this.ss = SpreadsheetApp.openById(/*SPREADSHEET_ID*/));
      },
    };
    function doSomething1(){/*do something with config.ss*/}
    function doSomething2(){/*do something with config.ss*/}
    function doItAll(){
      doSomething1();
      doSomething2();
    }
    function onOpen(){/*Adds a menu*/}
    

    在这里,我们在对象内部使用getter,而不是直接声明ss。以这种方式使用,SpreadsheetApp.openById() 永远不会在全局范围内调用,尽管它是在全局范围内声明的。只有在执行doSomething1 时才会加载它。另外,从doSomething2访问该方法时不会再次调用该方法,因为getter在第一次访问时被删除并替换为实际值。

    虽然代码变得有点笨重,但这解决了很多问题,而且更加优雅。

    样品:

    【讨论】:

    • 嗨!遇到了同样的问题,但我不确定您的示例是否完全适用于我的问题。那么,我将如何添加更多ss's? get ss1get ss2 等等会起作用吗?
    • @santosOnit 你读过我回答中的样本吗?
    【解决方案2】:

    我发现你这里不用回车return (this.ss = SpreadsheetApp.openById(/*SPREADSHEET_ID*/)

    有一天我在搞砸这个。我尝试过这种方式,它可以像真正的全局变量一样维护函数调用之间的状态,而无需通过启动属性服务的额外步骤。但是,它确实要求您每次都必须运行 readInit。

     let gobj={get init(){delete this.init;this.globals=getGlobals();this.init=PropertiesService.getScriptProperties().getProperties();}};
         readInit();
        
        function readInit() {
          gobj.init;
          console.log(JSON.stringify(gobj.globals));
          console.log(JSON.stringify(gobj.init))
        }
    

    只是想知道您的想法,这是另一种表达缺点的方式。我还添加了我经常在我的代码中访问的 getGlobals。直到现在我才能使用 gobj.globals.key 等访问它

    【讨论】:

    • 我认为readInit 一次就足够了。事实上,一旦你访问gobj.init,一切都应该自动初始化。
    猜你喜欢
    • 1970-01-01
    • 2012-05-04
    • 2020-09-02
    • 2012-12-19
    • 1970-01-01
    • 1970-01-01
    • 2016-03-19
    • 2012-02-02
    • 2015-12-26
    相关资源
    最近更新 更多