Google Apps Script에서 스크립트 실행 시간을 줄이시겠습니까?

Nov 19 2020

원격 학습을 위해 출석을 추적하는 스크립트를 만들었습니다. 잠시 후 시간이 초과되어 Google Classroom API를 너무 많이 호출하는 데 문제가있는 것 같지만 이러한 호출을 루프에서 제거하도록 변경할 수있는 방법이 없습니다.

스크립트는 내 앱 스크립트 계정이 공동 교사 인 모든 Google 클래스 룸 수업을 받고 시간 제한 트리거를 사용하여 '여기'라는 질문 하나가 포함 된 일일 출석 과제를 만듭니다. 그런 다음 학생들은 질문에 답하고 밤에 또 다른 트리거가 각 과제를 '채점'하고 내 스프레드 시트를 채우는 기능을 실행하여 학교 비서가 아침에이를보고 전날 출석을 기록 할 수 있도록합니다.

병목 현상이있는 것처럼 보이는 부분은 getStudentResponses () 함수입니다. 과제를 제출하지 않은 학생들을 걸러내어 시간을 줄이려고했지만 충분하지 않았습니다. 내가 이것을 더 빨리 만들 수있는 방법을 아는 사람이 있습니까? 캐시 서비스 사용에 대해 읽고 있었지만 어떻게 작동하는지 알 수 없었습니다. 어떤 도움을 주시면 감사하겠습니다.

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

답변

Rubén Nov 19 2020 at 11:41

appendRow느리기 때문에 for루프 내에서 사용하지 않아야 합니다. 대신 배열을 만든 다음 단일 setValues호출을 사용하여 값을 전달하십시오 .

자원

  • 모범 사례 | Apps Script

관련

  • Google Script 성능 저하
  • 내 스크립트 성능 향상 Google Sheets Script
  • for ... in 루프 실행이 매우 느림