- Auto-await
- Async functions
- Top-level await
- Promise API
- Promise instance methods
- delay()
- Error handling
- Patterns
- Next steps
Part of the Scripting Language reference.
The engine supports async operations with auto-await - all function calls that return a Promise are automatically resolved. The await and async keywords are supported but optional.
Auto-await
Function calls that return a native Promise (e.g. requestJira(), Issues.get()) are automatically awaited. You do not need to write await or mark functions as async:
// Both forms are equivalent:
const issue = Issues.get("TEST-1")
const issue = await Issues.get("TEST-1")
// Chaining works:
const summary = Issues.get("TEST-1").summary
// Works inside regular functions (no async keyword needed):
function getIssueSummary(key) {
const issue = Issues.get(key)
return issue.summary
}
log(getIssueSummary("TEST-1"))
Important limitations:
Promise.all()works, but does not provide parallelism - all calls inside are resolved sequentially beforePromise.allreceives them. UseawaitwithPromise.all().- For async operations inside
.map()/.filter()callbacks, usefor...ofloop instead (array callbacks run in sync context).
// For async in loops, use for...of instead of .map():
const keys = ["TEST-1", "TEST-2"]
const issues = []
for (const key of keys) {
issues.push(Issues.get(key))
}
Async functions
The async keyword is supported but optional. Both forms work identically:
// async keyword is optional - both forms work identically:
function fetchCount() {
return Issues.count("project = TEST")
}
async function fetchCount() {
return await Issues.count("project = TEST")
}
const val = fetchCount()
log(val) // => number of issues
Async arrow functions
const getTitle = (key) => Issues.get(key).summary
const val = getTitle("TEST-1")
log(val) // => issue summary
Top-level await
await can be used at the top level of a script. It is optional for native Promise values but required for boxed promises (Promise.resolve, Promise.reject, Promise.all, etc.):
const x = await Promise.resolve(42)
log(x) // => 42
Await with non-promise values
await on a non-promise value returns that value as-is:
const x = await 42
log(x) // => 42
const y = await null
log(y) // => null
Promise API
| Method | Description |
|---|---|
Promise.resolve(value) |
Creates a resolved promise |
Promise.reject(reason) |
Creates a rejected promise |
Promise.create(executor) |
Creates a promise with executor (replaces new Promise()) |
Promise.all(array) |
Resolves when all promises resolve, rejects on first rejection |
Promise.race(array) |
Resolves/rejects with the first settled promise |
Promise.allSettled(array) |
Resolves when all promises settle (fulfilled or rejected) |
Promise.any(array) |
Resolves with the first fulfilled promise |
Promise.withResolvers() |
Returns { promise, resolve, reject } for deferred resolution |
Promise.resolve / Promise.reject
const val = await Promise.resolve("hello")
log(val) // => hello
try {
await Promise.reject("oops")
} catch (e) {
log(e) // => oops
}
Promise.create
Replaces new Promise():
const p = Promise.create((resolve, reject) => {
resolve(99)
})
const val = await p
log(val) // => 99
Promise.all
const results = await Promise.all([
Promise.resolve(1),
Promise.resolve(2),
Promise.resolve(3),
])
log(results) // => [1, 2, 3]
Rejects immediately when any promise rejects:
try {
await Promise.all([
Promise.resolve(1),
Promise.reject("error"),
Promise.resolve(3),
])
} catch (e) {
log(e) // => error
}
Promise.race
const result = await Promise.race([
Promise.resolve("first"),
Promise.resolve("second"),
])
log(result) // => first
Promise.allSettled
const results = await Promise.allSettled([
Promise.resolve(1),
Promise.reject("fail"),
Promise.resolve(3),
])
log(results[0].status) // => fulfilled
log(results[0].value) // => 1
log(results[1].status) // => rejected
log(results[1].reason) // => fail
Promise.any
const val = await Promise.any([
Promise.reject("err1"),
Promise.resolve("success"),
Promise.reject("err2"),
])
log(val) // => success
When all promises reject:
try {
await Promise.any([Promise.reject("a"), Promise.reject("b")])
} catch (e) {
log(e) // => All promises were rejected
}
Promise.withResolvers
const { promise, resolve } = Promise.withResolvers()
resolve(42)
const val = await promise
log(val) // => 42
Promise instance methods
Promises support .then(), .catch(), and .finally() for chaining:
const result = await Promise.resolve(1)
.then(v => v + 1)
.then(v => v * 3)
log(result) // => 6
const fallback = await Promise.reject("error")
.catch(e => "caught: " + e)
log(fallback) // => caught: error
await Promise.resolve(42).finally(() => log("done"))
// => done
delay()
Pauses execution for the specified number of milliseconds.
await delay(100)
log("100ms later")
Rules:
msmust be a finite non-negative number- If
msexceeds the remaining execution time (depends on trigger type - see Limits), a timeout error is thrown immediately - Each
delay()call counts towardmaxPendingPromises
Sequential delays:
await delay(50)
log("first")
await delay(50)
log("second")
// Total: ~100ms
Parallel delays with Promise.all:
await Promise.all([delay(50), delay(50), delay(50)])
log("done")
// Total: ~50ms (parallel, not 150ms)
Error handling:
// Validation errors are catchable:
try {
await delay(-1)
} catch (e) {
log(e) // => delay(ms) requires a finite non-negative number
}
// Timeout errors are NOT catchable (same as other resource limits)
Error handling
Errors from async functions are caught with try/catch:
async function failing() {
throw "boom"
}
try {
await failing()
} catch (e) {
log(e) // => boom
}
The finally block works as expected:
let x = 0
try {
await Promise.reject("fail")
} catch (e) {
x = 1
} finally {
x = x + 10
}
log(x) // => 11
Patterns
Parallel execution
Use Promise.all with array methods:
async function processItem(item) {
return await Promise.resolve(item * 2 + 1)
}
const processed = await Promise.all([
processItem(10),
processItem(20),
processItem(30),
])
log(processed) // => [21, 41, 61]
Async map with Promise.all
const asyncDouble = async (x) => x * 2
const results = [1, 2, 3].map(asyncDouble)
const resolved = await Promise.all(results)
log(resolved) // => [2, 4, 6]
Sequential async loop
const keys = ["TEST-1", "TEST-2", "TEST-3"]
for (const key of keys) {
const issue = Issues.get(key)
log(issue.summary)
}
Next steps
- JS: Language Basics - Core language features
- JS: Functions & Classes - Function syntax and classes
- Scripting API: Issues - Async API methods
- Limits -
maxPendingPromisesand timeout limits
