Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- local Promise = {}
- Promise.__index = Promise
- Promise.State = {
- Pending = 'Pending',
- Resolved = 'Resolved',
- Rejected = 'Rejected',
- }
- function Promise.new(func)
- local self = {
- state = Promise.State.Pending,
- value = nil,
- reason = nil,
- onResolved = {},
- onRejected = {},
- }
- setmetatable(self, Promise)
- local function resolve(value)
- if self.state ~= Promise.State.Pending then
- error("Cannot resolve non-pending promise", 1)
- end
- self.value = value
- self.state = Promise.State.Resolved
- for callback in pairs(self.onResolved) do
- callback(value)
- end
- end
- local function reject(reason)
- if self.state ~= Promise.State.Pending then
- error("Cannot reject non-pending promise", 1)
- end
- self.reason = reason
- self.state = Promise.State.Rejected
- for callback in pairs(self.onRejected) do
- callback(reason)
- end
- end
- func(resolve, reject)
- return self
- end
- function Promise:andThen(onResolve, onReject)
- return Promise.new(function(resolveChild, rejectChild)
- local function resolveCallback(value)
- local newValue = value
- if onResolve then
- newValue = onResolve(newValue)
- end
- if type(newValue) == 'table' and newValue.andThen then
- newValue:andThen(resolveChild, rejectChild)
- else
- resolveChild(newValue)
- end
- end
- local function rejectCallback(reason)
- local newReason = reason
- if onReject then
- newReason = onReject(newReason)
- end
- if type(newReason) == 'table' and newReason.andThen then
- newReason:andThen(resolveChild, rejectChild)
- else
- rejectChild(newReason)
- end
- rejectChild(newReason)
- end
- if self.state == Promise.State.Resolved then
- resolveCallback(self.value)
- elseif self.state == Promise.State.Rejected then
- rejectCallback(self.reason)
- else
- self.onResolved[resolveCallback] = true
- self.onRejected[rejectCallback] = true
- end
- end)
- end
- -- Doesn't work on the main task in Roblox until Brad's changes go live
- function Promise:wait()
- local thread = coroutine.running()
- if self.state == Promise.State.Resolved then
- return true, self.value
- elseif self.state == Promise.State.Rejected then
- return false, self.reason
- else
- self:andThen(
- function(value)
- return coroutine.resume(thread, true, value)
- end,
- function(reason)
- return coroutine.resume(thread, false, reason)
- end
- )
- return coroutine.yield()
- end
- end
- local tests = {}
- function tests.worksAtAll()
- local promise = Promise.new(function(resolve, _) resolve(4) end)
- local result = promise
- :andThen(function(value) return value + 1 end)
- :andThen(function(value) assert(value == 5) return value end)
- return result
- end
- function tests.nonImmediateResolve()
- local resolveFunc
- local promise = Promise.new(function(resolve, _) resolveFunc = resolve end)
- local result = promise
- :andThen(function(value) return value + 1 end)
- :andThen(function(value) assert(value == 5) return value end)
- assert(result.state == Promise.State.Pending)
- resolveFunc(4)
- assert(result.state == Promise.State.Resolved)
- return result
- end
- function tests.promiseReturningPromise()
- local promise =
- Promise.new(function(resolve, _) resolve(4) end)
- :andThen(function(value)
- return Promise.new(function(resolve, _) resolve(value + 1) end)
- end)
- :andThen(function(value) assert(value == 5) return value end)
- return promise
- end
- function tests.promiseReturningPromiseNonImmediate()
- local resolveFunc
- local promise =
- Promise.new(function(resolve, _) resolveFunc = resolve end)
- :andThen(function(value)
- return Promise.new(function(resolve, _) resolve(value + 1) end)
- end)
- :andThen(function(value) assert(value == 5) return value end)
- resolveFunc(4)
- return promise
- end
- local function printStatus(ok, name, value)
- local status = ok and "PASSED" or "FAILED"
- print(string.format("[%s] %s", status, name))
- print(value)
- end
- for name, func in pairs(tests) do
- local promise = func()
- promise:andThen(
- function(value)
- printStatus(true, name, value)
- end,
- function(reason)
- printStatus(false, name, reason)
- end
- )
- end
- return Promise
Add Comment
Please, Sign In to add comment