본문으로 건너뛰기

백그라운드 스크립트

백그라운드 스크립트는 계속 실행해야 하는 스크립트에 적합합니다. 백그라운드 스크립트는 ScriptCat 전용 스크립트 유형입니다. 샌드박스에서 실행되며 DOM에 접근할 수 없습니다. Tampermonkey와 동일한 GM API를 사용하여 개발할 수 있으며 호환성 참고 사항은 문서에 명시되어 있습니다.

백그라운드 스크립트 (@background)

백그라운드 스크립트는 @background 속성으로 선언됩니다. 스크립트가 활성화되거나 브라우저가 시작된 후에도 백그라운드에서 계속 실행되도록 합니다.

예약 스크립트 (@crontab)

예약 스크립트는 시간 주기로 반복적으로 실행해야 하는 작업에 적합한 백그라운드 스크립트의 한 종류입니다.

예약 스크립트는 @crontab 속성으로 선언됩니다. 분 단위와 초 단위 예약을 지원하며, 동일한 시간 주기 내에서 두 번 이상 실행되는 것을 방지하는 ScriptCat의 확장 구문 once / once(...)을 제공합니다.

⚠️ 참고:

  • 단일 스크립트에서 첫 번째 @crontab만 적용됩니다
  • 스크립트의 단일 실행 시간 + 재시도 시간이 cron 간격을 초과하지 않는 것이 좋습니다. 그렇지 않으면 실행이 겹칠 수 있습니다

Cron 표현식 참고 사항

ScriptCat의 cron 구현은 표준 cron 구문에 작은 확장을 더한 node-cron을 기반으로 합니다.

표현식 형식

표준 5필드 형식 (권장)

minute hour day month weekday

확장 6필드 형식 (비권장)

second minute hour day month weekday

⚠️ 6필드 형식은 권장되지 않습니다 브라우저 환경은 초 단위 정밀도를 보장할 수 없으며 성능 오버헤드가 증가합니다 — 백그라운드 페이지의 예약이 지연될 수 있습니다.

필드별 사용 가능한 구문

구문의미
*모든 값* (매분/매시간)
숫자특정 값5 (5분)
a,b,c여러 개별 값1,15,30
a-b연속 범위10-23
*/nn 단위마다*/5
a-b/n단계가 있는 범위10-50/10

요일 규칙

  • 1–6: 월요일부터 토요일까지
  • 0 또는 7: 일요일

once 확장 구문

once의 의미

cron 표현식에서 once를 사용하면 다음을 의미합니다:

현재 시간 주기 내에서 한 번의 성공적인 실행만 허용

같은 주기 내의 이후 시간 지점이 여전히 cron 규칙과 일치하더라도 스크립트는 다시 실행되지 않습니다.

once vs. once(...)

구문이 필드의 기본 cron 값설명
once* (모든 값)특정 시간 없이 주기 내 첫 일치에서 실행
once(expr)expr주기 내에서 expr과 일치하는 시간에만, 그리고 한 번만 실행

once(expr)을 사용하면 "주기당 한 번만 실행"을 유지하면서 후보 시간 지점을 정확하게 지정할 수 있습니다. 괄호 안에는 모든 표준 cron 구문(숫자, 범위, 단계, 목록)이 지원됩니다.

예시 비교:

* once * * * // 매시간 임의의 분; 첫 일치에서 실행, 그 시간에는 더 이상 실행되지 않음
* once(9-17) * * * // 매일 9:00~17:59 사이, 시간당 한 번 실행
0,30 once * * * // 매시간 0분 또는 30분 중 먼저 일치하는 것이 실행됨; 그 시간에는 더 이상 실행되지 않음

once의 위치 = 제한하는 시간 주기

once / once(...)이 어디에 배치되든 "해당 시간 단위 내에서 한 번만 실행"을 의미합니다.

once 위치동작
분 필드분당 한 번만 실행
시간 필드시간당 한 번만 실행
일 필드하루에 한 번만 실행
월 필드한 달에 한 번만 실행
요일 필드일주일에 한 번만 실행

예시:

* once * * * // 시간당 한 번만 실행
* * once * * // 하루에 한 번만 실행
* 9-18 once * * // 매일 9:00~18:59 사이에 한 번만 실행

once와 범위 / 목록 / 단계 결합

once / once(...)은 모든 cron 구문과 결합할 수 있지만 규칙은 하나뿐입니다:

같은 주기 내에서 한 번 실행에 성공하면 이후의 모든 일치 시간 지점은 무시됩니다

예시 1: 범위

* 10 once * *

의미:

  • 매일 10:00~10:59가 후보 시간입니다
  • 하루의 첫 일치 후
  • 10:05~10:59는 더 이상 실행되지 않습니다

예시 2: 목록

* 1,3,5 once * *

의미:

  • 매일 1:00, 3:00, 5:00가 후보 시간입니다
  • 1:00에 이미 실행된 경우
  • 3:00과 5:00은 건너뜁니다

예시 3: 단계

* */4 once * *

의미:

  • 매일 0:00, 4:00, 8:00, 12:00, 16:00, 20:00이 후보 시간입니다
  • 하루의 첫 실행 후
  • 더 이상 시간 지점이 실행되지 않습니다

예시 4: once(...)으로 후보 시간 지점 지정

* once(9-17) * * *

의미:

  • 매일 9:00~17:00이 후보 시간입니다
  • 주기는 매시간 재설정됩니다. 한 시간 내에서 첫 일치가 이후 실행을 중지합니다
  • 효과: 매일 9:00~17:00 사이에 시간당 한 번, 총 9회 실행
* 9-18 once * *

의미:

  • 매일 9:00~18:59가 후보 시간입니다
  • 일 필드의 once는 주기를 하루에 한 번으로 고정합니다
  • 하루의 첫 일치 후 18:59까지 아무것도 실행되지 않습니다

@crontab 예시

일반

//@crontab * * * * * // 분당 한 번 실행
//@crontab * * * * * * // 초당 한 번 실행 (권장하지 않음)
//@crontab 0 */6 * * * // 6시간마다 정시에 실행
//@crontab 15 */6 * * * // 6시간마다 15분에 실행
//@crontab * once * * * // 시간당 최대 한 번 실행
//@crontab * * once * * // 하루 최대 한 번 실행
//@crontab * 10 once * * // 매일 10:00 시간 내에 한 번만 실행 (예: 10:04에 실행되면 10:05-10:59에 다시 실행되지 않음)
//@crontab * */4 once * * // 매일 4시간마다 최대 한 번 확인 (예: 4:00에 실행되면 8, 12, 16, 20, 24 등에 다시 실행되지 않음)

고급

//@crontab * 1,3,5 once * * // 매일 1:00, 3:00 또는 5:00에 한 번 실행 (예: 1:00에 실행되면 3:00 또는 5:00에 다시 실행되지 않음)
//@crontab * 10-23 once * * // 매일 10:00~23:59 사이에 한 번 실행 (예: 10:04에 실행되면 10:05-23:59에 다시 실행되지 않음)
//@crontab * once 13 * * // 매월 13일에 시간당 한 번 실행
//@crontab * once(9-17) * * * // 매일 9:00~17:00 사이에 시간당 한 번 실행
//@crontab 0,30 once * * * // 매시간 0분 또는 30분 중 먼저 일치하는 것이 실행됨; 그 시간에는 반복되지 않음
//@crontab * 9-18 once * * // 매일 9:00~18:00 사이에 한 번만 실행

사용 권장 사항

once에 적합한 경우

  • 하루/시간당 한 번만 실행하면 되는 작업

  • 상태 확인, 동기화 및 보고 스크립트

  • 다음 문제 방지:

    • 브라우저가 오랫동안 열리지 않은 경우
    • 백그라운드 페이지 예약 지연
    • 브라우저 다시 시작으로 인한 중복 실행

once에 권장되지 않는 경우

  • 정확한 시점에 실행해야 하는 작업
  • 실행 시간이 cron 간격을 크게 초과할 수 있는 스크립트
  • 실행 횟수에 대한 엄격한 일관성 요구 사항이 있는 작업

Cron 표현식 테스트

cron 표현식을 테스트할 때는 once / once(...)일시적으로 기본 값으로 대체하세요:

  • once*
  • once(expr)expr

테스트 도구가 확장 6필드 형식을 지원하지 않을 수 있습니다.

권장 도구:

스크립트 목록 페이지에서 실행 상태 열 위에 마우스를 올리면 스크립트의 다음 예약 실행 시간을 볼 수 있습니다.

로그

스크립트 목록 페이지에서 실행 상태 열 위에 마우스를 올리면 스크립트의 실행 상태가 있는 툴팁이 표시됩니다. 클릭하면 GM_log로 출력된 로그 내용이 팝업으로 표시됩니다.

스크립트 디버깅

백그라운드 스크립트는 스크립트 편집기 페이지에서 직접 디버깅할 수 있지만 다음과 같은 제한 사항이 있습니다:

  • value가 제대로 동기화되지 않습니다
  • registerMenu 메뉴가 제대로 트리거되지 않습니다

실제 런타임 환경을 디버깅하려면 확장 프로그램 설정에서 개발자 모드를 활성화한 다음 확장 프로그램의 background.html 페이지를 열어 디버깅하세요.

런타임에서 발생한 오류는 실행 로그에서도 볼 수 있습니다.

image-20210903144155450

Promise

다음 패턴을 적극 권장합니다. 스크립트 관리자가 스크립트 실행을 모니터링할 수도 있습니다. 스크립트가 비동기 작업을 수행하는 경우 Promise를 반환해야 합니다.

// ==UserScript==
// @name Background Script
// @namespace wyz
// @version 1.0.0
// @author wyz
// @background
// ==/UserScript==
return new Promise((resolve, reject) => {
if (Math.round((Math.random() * 10) % 2)) {
resolve("ok"); // 성공
} else {
reject("error"); // 실패, 오류 이유 포함
}
});
// ==UserScript==
// @name Scheduled script that runs once a day
// @namespace wyz
// @version 1.0.0
// @author wyz
// @crontab * * once * *
// ==/UserScript==
return new Promise((resolve, reject) => {
if (Math.round((Math.random() * 10) % 2)) {
resolve("ok"); // 성공
} else {
reject("error"); // 실패, 오류 이유 포함
}
});
// ==UserScript==
// @name Call an API
// @namespace wyz
// @version 1.0.0
// @author wyz
// @crontab * * once * *
// ==/UserScript==
return new Promise((resolve, reject) => {
GM_xmlhttpRequest({
url: "https://bbs.tampermonkey.net.cn/",
onload() {
resolve("ok"); // 성공
},
onerror() {
reject("error"); // 실패, 오류 이유 포함
},
});
});

resolve / reject를 스크립트 로직이 실제로 완료된 후에만 호출하세요. 호출 후 관리자는 스크립트 실행이 완료된 것으로 간주하며 이후의 GM 작업은 더 이상 적용되지 않습니다.

오류 재시도

ScriptCat 백그라운드 스크립트는 오류 재시도를 지원합니다. 스크립트가 실패하면 CATRetryErrorreject하여 재시도를 트리거할 수 있습니다.

  • 최소 재시도 간격: 5초
  • 스크립트 자체의 실행 시간과 충돌하지 않도록 하세요. 그렇지 않으면 중복 실행이 발생할 수 있습니다
// ==UserScript==
// @name Retry example
// @namespace https://bbs.tampermonkey.net.cn/
// @version 0.1.0
// @description try to take over the world!
// @author You
// @crontab * * once * *
// @grant GM_notification
// ==/UserScript==

return new Promise((resolve, reject) => {
GM_notification({
title: "retry",
text: "Retrying in 10 seconds",
});
reject(new CATRetryError("xxx error", 10));
});