Skriptlaufzeit in Google Apps Script reduzieren?

Nov 19 2020

Ich habe ein Skript erstellt, das die Teilnahme am Fernunterricht protokolliert. Nach einer Weile tritt eine Zeitüberschreitung auf, sodass ich denke, dass ich Probleme mit zu vielen Aufrufen der Google Classroom-API habe. Ich sehe jedoch keine Möglichkeit, diese zu ändern, um diese Aufrufe aus einer Schleife herauszunehmen.

Das Skript verwendet alle Google Classroom-Klassen, für die mein Apps-Skriptkonto ein Co-Lehrer ist. Durch die Verwendung von zeitgesteuerten Triggern wird eine tägliche Anwesenheitszuweisung mit einer Frage erstellt, die "hier" lautet. Die Schüler sollen dann die Frage beantworten, und ein weiterer Auslöser in der Nacht führt die Funktion aus, um jede Aufgabe zu „benoten“ und meine Tabelle zu füllen, damit die Schulsekretäre sie am Morgen anzeigen und die Anwesenheit der vorherigen Tage aufzeichnen können.

Der Teil, der den Engpass zu haben scheint, ist meine Funktion getStudentResponses (). Ich habe versucht, die Zeit zu verkürzen, indem ich Schüler herausgefiltert habe, die die Aufgabe nicht eingereicht haben, aber es war nicht genug. Hat jemand eine Möglichkeit gesehen, dies schneller zu machen? Ich habe mich über die Verwendung des Cache-Dienstes informiert, konnte aber nicht herausfinden, wie ich das zum Laufen bringen kann. Jede Hilfe wäre dankbar.

var ss = SpreadsheetApp.getActive();
var date = new Date();

/*
creates a button to programmatically create all necessary timed triggers for easy deployment
*/
function onOpen() {
  var ui = SpreadsheetApp.getUi();
  ui.createMenu('Attendance')
      .addItem('Create Triggers', 'createTriggers')
      .addToUi();
}

/*
auto accepts any co-teacher invites
*/
function acceptInvite() {
  try{
    var optionalArgs = {
      userId: "me"
    };
    var invites = Classroom.Invitations.list(optionalArgs);
    for(var i = 0; i < invites.invitations.length; i++) {
      Classroom.Invitations.accept(invites.invitations[i].id);
    }
  }
  catch(e){}
}

/*
populates a spreadsheet with all the classes that the script Google account is a co-teacher of
the sheet has two columns one with the course name and two with the course id
*/
function listCourses() {
  var optionalArgs = {courseStates: "ACTIVE"};
  var response = Classroom.Courses.list(optionalArgs);
  var courses = response.courses;
  var classSheet;
  
  try{
    classSheet = ss.insertSheet("Classes", 0);
    ss.insertSheet("Assignments", 1);
  }
  catch(e) {
    classSheet = ss.getSheetByName("Classes");
  }
  classSheet.clear();
  if (courses && courses.length > 0) {
    for (i = 0; i < courses.length; i++) {
      var course = courses[i];
      classSheet.appendRow([course.name, course.id]);
    }
  }
}

/*
reads the sheet to get all the classes and creates a new array with all the class IDs
*/
function getCourses() {
  var classSheet = ss.getSheetByName("Classes");
  var classList = new Array();
  var range = classSheet.getDataRange();
  var values = range.getValues();
  
  for(var i in values) {
    var row = values[i];
    var courseId = row[1]+"";
    classList.push(Classroom.Courses.get(courseId));
  }
  createTopics(classList);
}

/*
called immediatly after getCourses, creates topics in each class that will contain the daily attendance assignment
*/
function createTopics(classList) {
  for(i = 0; i < classList.length; i++) {
    var topic;
    var resource = {name: "Daily Online Attendance"};
    
    try {
      topic = Classroom.Courses.Topics.create(resource, classList[i].id);
      createAssignment(topic,classList[i]);
    }
    catch(e) {
      if(e == "GoogleJsonResponseException: API call to classroom.courses.topics.create failed with error: Requested entity already exists") {
        var topics = Classroom.Courses.Topics.list(classList[i].id);

        for(j = 0; j < topics.topic.length; j++) {
          if(topics.topic[j].name == "Daily Online Attendance") {
            createAssignment(topics.topic[j], classList[i]);
          }
        }
      }
    }
  }
}

/*
creates an assignment in each class, under each topic
each assignment only has one choice that says "here" and is going to be 'graded' each night to track attendance
*/
function createAssignment(topic,course) {
  var resource = {
    title: "Attendance for "+(date.getMonth()+1)+"/"+date.getDate()+"/2020",
    description: "Please fill this assignment out each day for attendance",
    topicId: topic.topicId,
    state: "PUBLISHED",
    workType: "MULTIPLE_CHOICE_QUESTION",
    multipleChoiceQuestion: {
      "choices": [
        "Here"
      ] 
    }
  };
  try {
    var assignment = Classroom.Courses.CourseWork.create(resource, course.id);
    var sheet = ss.getSheetByName("Assignments");
    sheet.appendRow([course.id,assignment.id]);
  }
  catch(e){}
}

/*
creates a new sheet for each day and logs each assignement
*/
function getStudentResponses() {
  var assignmentSheet = ss.getSheetByName("Assignments");
  var sheet2;
  var response;

  assignmentSheet.sort(1, true);
  
  try{
    sheet2 = ss.insertSheet("Attendance for "+(date.getMonth()+1)+"/"+date.getDate()+"/2020",(ss.getSheets().length-(ss.getSheets().length-2)));
    sheet2.appendRow(["Student Last Name","Student First Name","Grade","Class Name","Assignment Answer"]);
  }
  catch(e) {
    sheet2 = ss.getSheetByName("Attendance for "+(date.getMonth()+1)+"/"+date.getDate()+"/2020");
  }
  
  sheet2.setFrozenRows(1);
  
  var range = assignmentSheet.getDataRange();
  var values = range.getValues();
  
  for(var i in values) {
    var row = values[i];
    var courseId = row[0]+"";
    var courseWorkId = row[1]+"";
    
    try {
      response = Classroom.Courses.CourseWork.StudentSubmissions.list(courseId, courseWorkId);
        
      for(var j in response.studentSubmissions) {
        if(response.studentSubmissions[j].state == "TURNED_IN") {
          try {
            var grade;
            var email = Classroom.UserProfiles.get(response.studentSubmissions[j].userId).emailAddress;
            sheet2.appendRow([Classroom.UserProfiles.get(response.studentSubmissions[j].userId).name.familyName,Classroom.UserProfiles.get(response.studentSubmissions[j].userId).name.givenName,grade,Classroom.Courses.get(courseId).name,response.studentSubmissions[j].multipleChoiceSubmission.answer]);
          }
          catch (e) {}
        }
      }
    }
    catch(e) {}
  }
}

/*
deletes all assignemnts that were created
*/
function deleteAssignments() {
  var assignmentSheet = ss.getSheetByName("Assignments");
  assignmentSheet.sort(1, true);
  var range = assignmentSheet.getDataRange();
  var values = range.getValues();
  
  for(var i in values) {
    var row = values[i];
    var courseId = row[0]+"";
    var courseWorkId = row[1]+"";
    
    try {
      Classroom.Courses.CourseWork.remove(courseId, courseWorkId);
    }
    catch(e) {}
  assignmentSheet.clear();
  }
}

function createTriggers() {
  ScriptApp.newTrigger('getCourses')
      .timeBased()
      .everyDays(1)
      .atHour(6)
      .create();
  
  ScriptApp.newTrigger('getStudentResponses')
      .timeBased()
      .everyDays(1)
      .atHour(22)
      .create();
  
  ScriptApp.newTrigger('deleteAssignments')
      .timeBased()
      .everyDays(1)
      .atHour(23)
      .create();
  
  ScriptApp.newTrigger('listCourses')
      .timeBased()
      .everyDays(1)
      .atHour(21)
      .create();
  
  ScriptApp.newTrigger('acceptInvite')
      .timeBased()
      .everyDays(1)
      .atHour(20)
      .create();
}

Antworten

Rubén Nov 19 2020 at 11:41

appendRowist langsam, sollten Sie vermeiden, es innerhalb einer forSchleife zu verwenden. Erstellen Sie stattdessen ein Array und übergeben Sie die Werte mit einem einzigen setValuesAufruf.

Ressourcen

  • Best Practices | Apps-Skript

verbunden

  • Google Script-Leistung verlangsamt sich
  • Erhöhen Sie meine Skriptleistung Google Sheets Script
  • Sehr langsame Ausführung von for ... in Schleife