2016-08-30 3 views
0

현재 불행히도 너무 느리게 실행되는 Google 스크립트를 작성하고 있습니다. (6 분 초과). 스크립트는 문서를 열고 두 개의 문자열 (Google 시트에 설정 됨)을 대체하여 PDF로 저장합니다. 멋진 일은 없어.Google 스크립트가 너무 느리게 실행 중입니다.

이 스크립트를 실행하는 데 약 200 개의 문서가 있지만 6 분 내에 6 개로 만 관리됩니다. Google 스크립트가이 속도가 느리거나, 실수로 가장 비효율적 인 Google 스크립트를 만든 적이 있습니까?

function createAllPDF() { 
    var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet(); 
    var range = SpreadsheetApp.getActiveSheet().getActiveRange() 
    var numRows = SpreadsheetApp.getActiveSpreadsheet().getLastRow() - 1; 
    for(var i = 9; i <= numRows; i++) { 
    var thisRange = sheet.getRange("A" + n + ":C" + n); 
    var fond = thisRange.getCell(1, 1).getValue(); 
    var adresse = thisRange.getCell(1, 3).getValue(); 
    thisRange.setBackground('#cfe2f3'); 
    genDoc(fond, adresse); 
    } 
} 
//// CREATE PDF ////////////////// FUNCTION FOR GENERATING THE PDF ///////////////////////////////// 
function genDoc(fond, adresse) { 
    // Finds the template and duplicate it into a new file. 
    var template = ("xxxxxxxxxxxx"); 
    var docId = DriveApp.getFileById(template).makeCopy().getId(); 
    // Opens the newly created Document for editing 
    var doc = DocumentApp.openById(docId); 
    var body = doc.getActiveSection(); 
    // Renames the newly generated document 
    var newName = doc.setName(fond); 
    // Replaces each with the parsed variables. 
    body.replaceText("%FOND%", fond); 
    body.replaceText("%ADRESSE%", adresse); 
    doc.saveAndClose(); 
    //Adds the PDF ID to the invoice_input sheet 
    var conv = DriveApp.getFileById(docId); 
    var pdf = conv.getAs("application/pdf"); 
    var fileId = DriveApp.createFile(pdf).getId(); 
    // Gets the PDF file by ID 
    var thisPDF = DriveApp.getFileById(fileId); 
    // The ID of the folder I'd like to put the PDF into. 
    var folderId = "xxxxxxxxxxx"; 
    // Gets the folder by ID 
    var targetFolder = DriveApp.getFolderById(folderId); 
    // Adds the PDF to the Folder 
    targetFolder.addFile(thisPDF); 
    // Removes the PDF from the root. 
    var root = DriveApp.getRootFolder().removeFile(thisPDF); 
    // Deletes the duplicated document 
    DriveApp.getFileById(docId).setTrashed(true) 
    return fileId; 
} 

최적화 방법에 대한 모든 정보가 크게 도움이 될 것입니다. 나는 아주 일반적으로 구글 스크립트와 프로그래밍에 익숙하지 않기 때문에 큰 단어는 없다. 이 보드를 잘못 사용하면 사과드립니다. 알려 주시면 수정하겠습니다.

+2

[코드 검토] (http://codereview.stackexchange.com/help/on-topic) – pnuts

답변

0

(참고 :이 테스트를하지 않은,하지만 당신이 시작 얻어야한다)

몇 가지 아이디어를 :

  1. 가 for 루프 밖으로 "getRange"명령을 이동합니다.
  2. for 루프 외부의 targetFolder 및 rootFolder 템플릿을 읽고이를 genDoc에 인수로 전달합니다.
  3. 가능한 경우 "시트"와 "전환"을 다시 사용하십시오.
  4. 모든 bgColors를 개별적으로 한번에 쓰십시오.
  5. 아무 것도 반환하지 마십시오.

그래서 이런 식으로 뭔가 :


function createAllPDF() { 
    var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet(); 
    var numRows = sheet.getLastRow() - 1; 
    var range = sheet.getActiveRange(); 
    var values = range.getValues(); 
    var templateId = ("xxxxxxxxxxxx"); 
    var template = DriveApp.getFileById(templateId); 
    // The ID of the folder I'd like to put the PDF into. 
    var folderId = "xxxxxxxxxxx"; 
    // Gets the folder by ID 
    var targetFolder = DriveApp.getFolderById(folderId); 
    var rootFolder = DriveApp.getRootFolder(); 
    for(var i = 9; i <= numRows; i++) { 
    var fond = values[i][1]; // TODO: check syntax. 
    var adresse = values[i][3]; 
    genDoc(fond, adresse, template, targetFolder, rootFolder); 
    } 
    range.setBackground('#cfe2f3'); // TODO: only first 3 columns 
} 
//// CREATE PDF ////////////////// FUNCTION FOR GENERATING THE PDF ///////////////////////////////// 
function genDoc(fond, adresse, template, targetFolder, rootFolder) { 
    // Finds the template and duplicate it into a new file. 
    var conv = template.makeCopy(); 
    var docId = conv.getId(); 
    // Opens the newly created Document for editing 
    var doc = DocumentApp.openById(docId); 
    var body = doc.getActiveSection(); 
    // Renames the newly generated document 
    var newName = doc.setName(fond); 
    // Replaces each with the parsed variables. 
    body.replaceText("%FOND%", fond); 
    body.replaceText("%ADRESSE%", adresse); 
    doc.saveAndClose(); 
    //Adds the PDF ID to the invoice_input sheet 
    var pdf = conv.getAs("application/pdf"); 
    var fileId = DriveApp.createFile(pdf).getId(); 
    // Gets the PDF file by ID 
    var thisPDF = DriveApp.getFileById(fileId); 
    // Adds the PDF to the Folder 
    targetFolder.addFile(thisPDF); 
    // Removes the PDF from the root. 
    rootFolder.removeFile(thisPDF); 
    // Deletes the duplicated document 
    conv.setTrashed(true); 
} 
+0

안녕하세요, 답변 해 주셔서 감사합니다. 이제는 두 배 빠른 속도로 실행됩니다. 불행히도 6 분 안에 내 문서를 완성 할만큼 충분히 빠르지는 않습니다. 그것은 하루의 50 분 제한 시간 내에 끝내기에는 너무 빠르지 않습니다. 어쩌면 이것이 정확히 Google 스크립트가 사용되기로되어있는 것은 아닙니다. 모든 도움을 주셔서 다시 한 번 감사드립니다. – Jake

+0

설치 가능한 트리거 https://developers.google.com/apps-script/guides/triggers/installable 및 일반 최적화 기술을 살펴보십시오. http://stackoverflow.com/questions/14450819/google-app-script- 제한 시간 - 5 분 – opowell

0

나는 즉시 당신이 정의되지 않은 변수 n을 알 수 있습니다. 그것은 라인에이 코드가 완전히 unuseable 했어야

var thisRange = sheet.getRange("A" + n + ":C" + n);

. 이 변수를 i으로 변경하면 전체 6 분 동안 코드를 성공적으로 실행할 수있었습니다. 그 시간 동안, 그것은 약 41.5 회 반복 할 수있었습니다. 그것은 행 9-53에 대한 파일을 만들었지 만 올바른 폴더에 마지막 파일을 추가 할 수 있기 전에 중단되었습니다.

실행 기록을 보면 가장 긴 작업은 파일을 만들고 이동하고 삭제하는 몇 가지 호출입니다.

또한 range을 정의한 다음이 변수를 사용하지 마십시오. 불필요합니다.

나는 여러 번 나 자신을 위해 사용한 구조와 방법으로 코드를 다시 작성했다. 9-59 행을 완전히 처리 할 수있었습니다. 이 메소드는 6 행만큼 확장 할 수있었습니다. 5 분 55 초 간격으로 기능을 중지하고 5 초 후에 다시 시작하도록 제한 시간 트리거를 추가하는 것이 좋습니다. javascript 시간에 대한 안내는 here입니다. 다른 일치 방법도 사용합니다. RegEx를 사용합니다. RegEx에 대한 광범위한 안내서와 처리 시간을 최소화하는 방법이 있습니다. 나는이 지역에 능숙하지 않다.

function PDFCreator() { 
    var ss = SpreadsheetApp.getActiveSpreadsheet(); 
    var sheet = ss.getSheetByName("Test Sheet"); 
    var lastRow = sheet.getLastRow(); 
    var checkRange = sheet.getRange(9, 1, (lastRow - 8), 3); 
    var check = checkRange.getBackgrounds(); 
    var lightBlue = "#cfe2f3"; 
    var template = DriveApp.getFileById("1RslWGntAwfLTSytOv_IoOv2_iBhSmsK0ZtEVWaq3ezM"); 
    var folder = DriveApp.getFolderById("0BwZ6LWJudkOHaTFiQjd5cFA5OG8"); 
    for (i = 0; i < check.length; i++) { 
    if (check[i] == lightBlue) { 
     continue; 
    } else { 
     var dataRow = sheet.getRange((i + 9), 1, 1, 3); 
     var fond = sheet.getRange((i + 9), 1, 1, 1).getValue(); 
     var adresse = sheet.getRange((i + 9), 3, 1, 1).getValue(); 
     var docName = fond + ".pdf"; 
     var docCopy = template.makeCopy(docName, folder); 
     var docId = docCopy.getId(); 
     var docToEdit = DocumentApp.openById(docId); 
     var docBody = docToEdit.getBody(); 
     docBody.replaceText(/\%{1}[F][O][N][D]\%{1}/g, fond); 
     docBody.replaceText(/\%{1}[A][D][R][E][S][S][E]\%{1}/g, adresse); 
     docToEdit.saveAndClose(); 
     var fileToPDF = DriveApp.getFileById(docId); 
     var pdfBlob = fileToPDF.getAs(MimeType.PDF); 
     var pdfRoot = DriveApp.createFile(pdfBlob).setName(docName); 
     var pdf = pdfRoot.makeCopy(folder); 
     pdfRoot.setTrashed(true); 
     fileToPDF.setTrashed(true); 
     dataRow.setBackground(lightBlue); 
    } 
    } 
} 

당신은 내가 메인 함수 내부의 for()if()을 중첩 된 것을 알 수 있습니다.그런 식으로, 당신은 함수간에 정보를 계속해서 전달하지 않습니다. 일반적으로 외부에을 정의 할 수 있으면 더 많은 호출을 할 수 있습니다. for 루프 외부에서 설정할 수있는 변수가 더 많아서 실행을 연장 할 수 있습니다.

기본적으로 긴 프로세스이므로 6 분 안에 200 번 실행하지 못할 것입니다. 이것을 합리적인 효율로 55/60 전체 행으로 확장 할 수는 있지만 그 시점에서 다시 실행해야합니다.

관련 문제