Skip to content

Instantly share code, notes, and snippets.

@freehuntx
Last active December 1, 2023 21:58
Show Gist options
  • Save freehuntx/a57cb62c1252814c76bccd1da0b7cf41 to your computer and use it in GitHub Desktop.
Save freehuntx/a57cb62c1252814c76bccd1da0b7cf41 to your computer and use it in GitHub Desktop.
Godot Promise
class_name Promise extends RefCounted
# Constants
const State = {
PENDING = "pending",
FULFILLED = "fulfilled",
REJECTED = "rejected"
}
# Signals
signal on_resolved
signal on_rejected
signal on_completed
# Private members
var _state = State.PENDING
var _value: Variant = null
var _reason: Variant = null
var _fulfilled_cbs: Array[Callable] = []
var _rejected_cbs: Array[Callable] = []
# Getters
var resolved:
get:
if _state != State.FULFILLED:
return await on_resolved
if _value is Promise:
return await _value.resolved
return _value
var rejected:
get:
if _state != State.REJECTED:
return await on_rejected
if _reason is Promise:
return await _reason.rejected
return _reason
var completed:
get:
if _state == State.PENDING:
return await on_completed
if _state == State.FULFILLED:
return { state=_state, value=await resolved }
return { state=_state, reason=await rejected }
# Constructor
func _init(executor = null):
if executor != null:
executor.callv(self._resolve, self._reject)
# Public methods
func then(fulfilled_cb=null, rejected_cb=null) -> Promise:
if fulfilled_cb:
_fulfilled_cbs.append(fulfilled_cb)
if _state == State.FULFILLED:
fulfilled_cb.callv([])
fulfilled_cb.callv([ _value ])
if rejected_cb:
_rejected_cbs.append(rejected_cb)
if _state == State.REJECTED:
rejected_cb.callv([])
rejected_cb.callv([ _reason ])
return self
func catch(rejected_cb) -> Promise:
return then(null, rejected_cb)
func finally(cb) -> Promise:
return then(
func(value):
cb.callv([])
cb.callv([[ value, null ]]),
func(reason):
cb.callv([])
cb.callv([[ null, reason ]]),
)
# Private methods
func _resolve(value=null) -> void:
if _state == State.PENDING:
_state = State.FULFILLED
_value = value
on_resolved.emit(value)
on_completed.emit({ state=_state, value=value })
for callback in _fulfilled_cbs:
callback.callv([])
callback.callv([ _value ])
func _reject(reason=null) -> void:
if _state == State.PENDING:
_state = State.REJECTED
_reason = reason
on_rejected.emit(reason)
on_completed.emit({ state=_state, reason=reason })
for callback in _rejected_cbs:
callback.callv([])
callback.callv([ _reason ])
# Static methods
static func resolve(value=null) -> Promise:
var promise := Promise.new()
promise._resolve(value)
return promise
static func reject(reason=null) -> Promise:
var promise := Promise.new()
promise._reject(reason)
return promise
static func all(promise_array: Array[Promise]) -> Promise:
var promise := Promise.new()
var promise_array_size = promise_array.size()
var values = []
values.resize(promise_array_size)
var count_state = {
resolved = 0,
rejected = 0
}
for i in range(0, promise_array_size):
promise_array[i].then(
func(val):
count_state.resolved += 1
values[i] = val
if count_state.resolved == promise_array_size:
promise._resolve(values),
func(reason):
count_state.rejected += 1
if count_state.rejected == 1:
promise._reject(reason)
)
return promise
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment