英文:
Function not being called/running unless I comment out the calling of the function before it (asynchronicity problem)
问题
I understand you want a translation of the provided code in Chinese without translating the code itself. Here's the translated text:
"我对Google Apps Script仍然很陌生,但我真的很感谢您的帮助!
我正在编写一个Google Apps脚本,用于在提交Google表单时创建证书并自动发送给用户。该脚本获取与Google表单连接的工作表中新增的行,然后发送电子邮件,接着获取第四列(参与者的姓名)以创建自定义证书。自动化部分让我有些困扰。我已经设置了一个触发器函数(OnForm()),以自动使用演示文稿的第一张幻灯片(作为模板)并创建另一张幻灯片,带有参与者的姓名,我将此函数命名为sheetToSlide。我的下一步是将此幻灯片转换为PNG格式并保存它,我将此函数命名为createPNG。当您手动运行它时,它可以正常工作,但是当我在触发器函数内部调用它之后,它不会运行。我的理论是问题可能与异步性有关,因为当我尝试注释掉sheetToSlide函数时,createPNG函数可以正常工作。
我已经尝试了多种方法。我尝试使用Utilities.sleep()在两个函数之间设置延迟,还尝试使用代码中所示的async/await对象。然而,这些方法都没有奏效。我还尝试将这两个函数合并为一个。
我会非常感谢任何帮助或建议,因为我已经卡在这个问题上很长时间了。
谢谢"
英文:
I am still quite new to the google Apps Script, but I would really appreciate help with this!
I am writing a google apps script that is to create certificates when a google forms is submitted and send it automatically to the user. The script is taking the newly added row to the sheets that is connected to the Google forms and sends an email then takes the 4th column which is the name of the participant to create a custom certificate. The automatic part is giving me some trouble. I have set up a trigger function (OnForm()) to automatically use the first slide from a presentation ( as a template) and create another slide with the name of the participant, I named this function as sheetToSlide. My next step is to convert this slide to a png and save it, I named this function createPNG. it works when you run it manually, but does not run when I call it within the trigger function after the sheetToSlide function. My theory is that the issue could be with asynchronicity, and that is because when I tried commenting out the sheetToSlide function, the createPNG function worked perfectly.
async function sheetToSlide(sheetData) {
var name = sheetData[4];
var presentation = SlidesApp.getActivePresentation();
var slideTemplate = presentation.getSlideById('p'); //ID for certificate template
//Logger.log(slideTemplate);
var newSlide = slideTemplate.duplicate();
var newSlideID = newSlide.getObjectId();
var shapes = presentation.getSlideById(newSlideID).getShapes();
shapes.forEach(function (shape) {
shape.getText().replaceAllText('{{name}}', name);
});
var numberOfSlides = presentation.getSlides().length;
newSlide.move(numberOfSlides); // last row = last slide
}
async function createPNG() {
var presentation = SlidesApp.getActivePresentation();
var presentationId = presentation.getId();
var parameters = {
method: "GET",
headers: { Authorization: "Bearer " + ScriptApp.getOAuthToken() },
contentType: "application/json",
};
var slides = presentation.getSlides();
var lastSlide = slides[slides.length - 1];
var slideId = lastSlide.getObjectId();
var url = "https://slides.googleapis.com/v1/presentations/" + presentationId + "/pages/" + slideId + "/thumbnail";
var response = JSON.parse(UrlFetchApp.fetch(url, parameters)); // sending message to web server to perform that actions resulting in an HTTPResponse object
var blob = UrlFetchApp.fetch(response.contentUrl, parameters).getBlob(); // fetch image thumbnail and then blob is used to convert it into binary data
var image = DriveApp.createFile(blob).setName("test12" + ".png"); //file name for each slide
var imageId = image.getId();
var folder = DriveApp.getFolderById('14gY2e12mcCYRCuTPP_RLNQ9hE7AKIg1h')
DriveApp.getFileById(imageId).moveTo(folder);
}
function createOnFormSubmitTrigger() {
ScriptApp.newTrigger('sendEmailOnFormSubmit')
.forSpreadsheet('1Uwas2AN5L5-487Bu8NGYZYq3WZ8PlcVd2wSyJtHZgfI')
.onFormSubmit()
.create();
//.forForm('1G1Yjm6JH_3jy5fx-AuURpOxnzFi1E-uatnv-t1pEaiE')
}
async function sendEmailOnFormSubmit(e) {
const ss = SpreadsheetApp.openById('1Uwas2AN5L5-487Bu8NGYZYq3WZ8PlcVd2wSyJtHZgfI'); // Access the sheet
const sheet = ss.getSheetByName('Form Responses 1');
const lastRow = sheet.getLastRow();
const rowRange = sheet.getRange(lastRow, 1, 1, sheet.getLastColumn());
const rowData = rowRange.getValues()[0];
const name = rowData[4];
const recipient = e.response.getRespondentEmail();
const subject = 'Test';
const body = 'I am testing this. Score: ' + name + ' (' + typeof name + ')';
GmailApp.sendEmail(recipient, subject, body);
await sheetToSlide(rowData);
await createPNG();
//Utilities.sleep(30000); //30 seconds
//GmailApp.sendEmail(recipient, subject, body);
}
I have tried multiple things. I tried putting a delay between the two functions using the utilities.sleep(), i have also tries using the async/await objects as you can see in the code. However, non of this worked. I have also tried putting the two functions into one.
I would appreciate any help or advice as I have been stuck on this for too long.
Thank you
答案1
得分: 1
首先,在当前阶段,Google Apps Script 的方法是以同步进程运行的。所以我认为在您的脚本中,不需要使用 async/await。至于“但当我在 sheetToSlide 函数之后调用触发函数时它却没有运行”,我认为您的脚本运行了 createPNG()。但是在这种情况下,我认为在 sheetToSlide 中对 Google Slide 的修改可能不会反映在 Google Slide 中。如果我的理解是正确的,可以尝试以下修改:
### 修改后的脚本:
请将 `sheetToSlide` 修改如下。
#### 从:
newSlide.move(numberOfSlides); // 最后一行 = 最后一张幻灯片
#### 到:
newSlide.move(numberOfSlides); // 最后一行 = 最后一张幻灯片
presentation.saveAndClose(); // <--- 添加
当您整个脚本进行了修改后,它将如下所示。
<!-- begin snippet: js hide: true console: true babel: false -->
<!-- language: lang-js -->
function sheetToSlide(sheetData) {
var name = sheetData[4];
var presentation = SlidesApp.getActivePresentation();
var slideTemplate = presentation.getSlideById('p'); // 证书模板的 ID
//Logger.log(slideTemplate);
var newSlide = slideTemplate.duplicate();
var newSlideID = newSlide.getObjectId();
var shapes = presentation.getSlideById(newSlideID).getShapes();
shapes.forEach(function (shape) {
shape.getText().replaceAllText('{{name}}', name);
});
var numberOfSlides = presentation.getSlides().length;
newSlide.move(numberOfSlides); // 最后一行 = 最后一张幻灯片
presentation.saveAndClose(); // <--- 添加
}
function createPNG() {
// ...
}
function createOnFormSubmitTrigger() {
// ...
}
function sendEmailOnFormSubmit(e) {
// ...
}
<!-- end snippet -->
### 参考:
- [Class Presentation 的 saveAndClose() 方法](https://developers.google.com/apps-script/reference/slides/presentation#saveandclose)
英文:
First, in the current stage, the methods of Google Apps Script are run with a synchronous process. So, I think that in your script, async/await is not required to be used. And, about but does not run when I call it within the trigger function after the sheetToSlide function.
, I think that your script runs createPNG()
. But, in this case, I think that the modification of Google Slide in sheetToSlide
might not be reflected in the Google Slide. If my understanding is correct, how about the following modification?
Modified script:
Please modify sheetToSlide
as follows.
From:
newSlide.move(numberOfSlides); // last row = last slide
}
To:
newSlide.move(numberOfSlides); // last row = last slide
presentation.saveAndClose(); // <--- Added
}
When your showing whole script is modified, it becomes as follows.
<!-- begin snippet: js hide: true console: true babel: false -->
<!-- language: lang-js -->
function sheetToSlide(sheetData) {
var name = sheetData[4];
var presentation = SlidesApp.getActivePresentation();
var slideTemplate = presentation.getSlideById('p'); //ID for certificate template
//Logger.log(slideTemplate);
var newSlide = slideTemplate.duplicate();
var newSlideID = newSlide.getObjectId();
var shapes = presentation.getSlideById(newSlideID).getShapes();
shapes.forEach(function (shape) {
shape.getText().replaceAllText('{{name}}', name);
});
var numberOfSlides = presentation.getSlides().length;
newSlide.move(numberOfSlides); // last row = last slide
presentation.saveAndClose(); // <--- Added
}
function createPNG() {
var presentation = SlidesApp.getActivePresentation();
var presentationId = presentation.getId();
var parameters = {
method: "GET",
headers: { Authorization: "Bearer " + ScriptApp.getOAuthToken() },
contentType: "application/json",
};
var slides = presentation.getSlides();
var lastSlide = slides[slides.length - 1];
var slideId = lastSlide.getObjectId();
var url = "https://slides.googleapis.com/v1/presentations/" + presentationId + "/pages/" + slideId + "/thumbnail";
var response = JSON.parse(UrlFetchApp.fetch(url, parameters)); // sending message to web server to perform that actions resulting in an HTTPResponse object
var blob = UrlFetchApp.fetch(response.contentUrl, parameters).getBlob(); // fetch image thumbnail and then blob is used to convert it into binary data
var image = DriveApp.createFile(blob).setName("test12" + ".png"); //file name for each slide
var imageId = image.getId();
var folder = DriveApp.getFolderById('14gY2e12mcCYRCuTPP_RLNQ9hE7AKIg1h')
DriveApp.getFileById(imageId).moveTo(folder);
}
function createOnFormSubmitTrigger() {
ScriptApp.newTrigger('sendEmailOnFormSubmit')
.forSpreadsheet('1Uwas2AN5L5-487Bu8NGYZYq3WZ8PlcVd2wSyJtHZgfI')
.onFormSubmit()
.create();
//.forForm('1G1Yjm6JH_3jy5fx-AuURpOxnzFi1E-uatnv-t1pEaiE')
}
function sendEmailOnFormSubmit(e) {
const ss = SpreadsheetApp.openById('1Uwas2AN5L5-487Bu8NGYZYq3WZ8PlcVd2wSyJtHZgfI'); // Access the sheet
const sheet = ss.getSheetByName('Form Responses 1');
const lastRow = sheet.getLastRow();
const rowRange = sheet.getRange(lastRow, 1, 1, sheet.getLastColumn());
const rowData = rowRange.getValues()[0];
const name = rowData[4];
const recipient = e.response.getRespondentEmail();
const subject = 'Test';
const body = 'I am testing this. Score: ' + name + ' (' + typeof name + ')';
GmailApp.sendEmail(recipient, subject, body);
sheetToSlide(rowData);
createPNG();
//Utilities.sleep(30000); //30 seconds
//GmailApp.sendEmail(recipient, subject, body);
}
<!-- end snippet -->
Reference:
答案2
得分: 0
你需要从异步函数中 return 一些内容(或在其中抛出错误),否则它将表现得像一个永远挂起的承诺。
根据MDN:
Await 表达式使返回承诺的函数表现得像它们是同步的,通过暂停执行,直到返回的承诺被履行或拒绝
所以你需要返回 一些内容。我会说不管你返回什么,只要它确实在函数体的末尾有 return
即可。
参见这里
英文:
You need to return something from an async function (or throw an error inside it), otherwise it behaves as if it where a forever-pending-promise.
According to MDN:
> Await expressions make promise-returning functions behave as though they're synchronous by suspending execution until the returned promise is fulfilled or rejected
So you need to return something. I would say it doesn't matter what you return, just that it needs to literally have return
at the end of the function body.
See here
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论