Last active
December 1, 2023 21:58
-
-
Save freehuntx/a57cb62c1252814c76bccd1da0b7cf41 to your computer and use it in GitHub Desktop.
Godot Promise
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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