Réduire le temps d'exécution des scripts dans Google Apps Script?

Nov 19 2020

J'ai créé un script qui suit la participation à l'apprentissage à distance. Après un certain temps, je pense que j'ai des problèmes avec trop d'appels à l'API Google Classroom, mais je ne vois pas de moyen de le changer pour sortir ces appels d'une boucle.

Le script prend toutes les classes Google Classroom sur lesquelles mon compte de script d'applications est co-enseignant et l'utilisation de déclencheurs chronométrés crée une affectation de présence quotidienne avec une question qui dit «ici». Les étudiants sont alors censés répondre à la question, puis un autre déclencheur la nuit exécute la fonction pour `` noter '' chaque devoir et remplir ma feuille de calcul afin que les secrétaires d'école puissent la consulter le matin et enregistrer la fréquentation des jours précédents.

La partie qui semble avoir le goulot d'étranglement est ma fonction getStudentResponses (). J'ai essayé de réduire le temps en filtrant les étudiants qui n'avaient pas soumis le devoir, mais ce n'était pas suffisant. Quelqu'un voit-il un moyen que je puisse faire plus rapidement? J'étais en train de lire sur l'utilisation du service de cache, mais je ne savais pas comment faire fonctionner cela. Toute aide serait appréciée.

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();
}

Réponses

Rubén Nov 19 2020 at 11:41

appendRowest lent, vous devez éviter de l'utiliser dans une forboucle. Au lieu de cela, créez un tableau, puis transmettez les valeurs en un seul setValuesappel.

Ressources

  • Meilleures pratiques | Script d'applications

En rapport

  • Ralentissement des performances des scripts Google
  • Augmenter les performances de mon script Script Google Sheets
  • Exécution très lente de for ... in loop