mirror of
https://github.com/AmberGraceRblx/luau-promise.git
synced 2025-04-24 23:50:03 +00:00
parent
e7033308ec
commit
4e04458816
2 changed files with 169 additions and 141 deletions
57
lib/init.lua
57
lib/init.lua
|
@ -7,6 +7,21 @@ local ERROR_NON_LIST = "Please pass a list of promises to %s"
|
||||||
local ERROR_NON_FUNCTION = "Please pass a handler function to %s!"
|
local ERROR_NON_FUNCTION = "Please pass a handler function to %s!"
|
||||||
local MODE_KEY_METATABLE = { __mode = "k" }
|
local MODE_KEY_METATABLE = { __mode = "k" }
|
||||||
|
|
||||||
|
local function isCallable(value)
|
||||||
|
if type(value) == "function" then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
if type(value) == "table" then
|
||||||
|
local metatable = getmetatable(value)
|
||||||
|
if metatable and type(rawget(metatable, "__call")) == "function" then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
--[[
|
--[[
|
||||||
Creates an enum dictionary with some metamethods to prevent common mistakes.
|
Creates an enum dictionary with some metamethods to prevent common mistakes.
|
||||||
]]
|
]]
|
||||||
|
@ -131,7 +146,7 @@ local function packResult(success, ...)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function makeErrorHandler(traceback)
|
local function makeErrorHandler(traceback)
|
||||||
assert(traceback ~= nil)
|
assert(traceback ~= nil, "traceback is nil")
|
||||||
|
|
||||||
return function(err)
|
return function(err)
|
||||||
-- If the error object is already a table, forward it directly.
|
-- If the error object is already a table, forward it directly.
|
||||||
|
@ -592,7 +607,7 @@ end
|
||||||
]=]
|
]=]
|
||||||
function Promise.fold(list, reducer, initialValue)
|
function Promise.fold(list, reducer, initialValue)
|
||||||
assert(type(list) == "table", "Bad argument #1 to Promise.fold: must be a table")
|
assert(type(list) == "table", "Bad argument #1 to Promise.fold: must be a table")
|
||||||
assert(type(reducer) == "function", "Bad argument #2 to Promise.fold: must be a function")
|
assert(isCallable(reducer), "Bad argument #2 to Promise.fold: must be a function")
|
||||||
|
|
||||||
local accumulator = Promise.resolve(initialValue)
|
local accumulator = Promise.resolve(initialValue)
|
||||||
return Promise.each(list, function(resolvedElement, i)
|
return Promise.each(list, function(resolvedElement, i)
|
||||||
|
@ -842,7 +857,7 @@ end
|
||||||
]=]
|
]=]
|
||||||
function Promise.each(list, predicate)
|
function Promise.each(list, predicate)
|
||||||
assert(type(list) == "table", string.format(ERROR_NON_LIST, "Promise.each"))
|
assert(type(list) == "table", string.format(ERROR_NON_LIST, "Promise.each"))
|
||||||
assert(type(predicate) == "function", string.format(ERROR_NON_FUNCTION, "Promise.each"))
|
assert(isCallable(predicate), string.format(ERROR_NON_FUNCTION, "Promise.each"))
|
||||||
|
|
||||||
return Promise._new(debug.traceback(nil, 2), function(resolve, reject, onCancel)
|
return Promise._new(debug.traceback(nil, 2), function(resolve, reject, onCancel)
|
||||||
local results = {}
|
local results = {}
|
||||||
|
@ -951,11 +966,11 @@ function Promise.is(object)
|
||||||
return true
|
return true
|
||||||
elseif objectMetatable == nil then
|
elseif objectMetatable == nil then
|
||||||
-- No metatable, but we should still chain onto tables with andThen methods
|
-- No metatable, but we should still chain onto tables with andThen methods
|
||||||
return type(object.andThen) == "function"
|
return isCallable(object.andThen)
|
||||||
elseif
|
elseif
|
||||||
type(objectMetatable) == "table"
|
type(objectMetatable) == "table"
|
||||||
and type(rawget(objectMetatable, "__index")) == "table"
|
and type(rawget(objectMetatable, "__index")) == "table"
|
||||||
and type(rawget(rawget(objectMetatable, "__index"), "andThen")) == "function"
|
and isCallable(rawget(rawget(objectMetatable, "__index"), "andThen"))
|
||||||
then
|
then
|
||||||
-- Maybe this came from a different or older Promise library.
|
-- Maybe this came from a different or older Promise library.
|
||||||
return true
|
return true
|
||||||
|
@ -1235,14 +1250,8 @@ end
|
||||||
@return Promise<...any>
|
@return Promise<...any>
|
||||||
]=]
|
]=]
|
||||||
function Promise.prototype:andThen(successHandler, failureHandler)
|
function Promise.prototype:andThen(successHandler, failureHandler)
|
||||||
assert(
|
assert(successHandler == nil or isCallable(successHandler), string.format(ERROR_NON_FUNCTION, "Promise:andThen"))
|
||||||
successHandler == nil or type(successHandler) == "function",
|
assert(failureHandler == nil or isCallable(failureHandler), string.format(ERROR_NON_FUNCTION, "Promise:andThen"))
|
||||||
string.format(ERROR_NON_FUNCTION, "Promise:andThen")
|
|
||||||
)
|
|
||||||
assert(
|
|
||||||
failureHandler == nil or type(failureHandler) == "function",
|
|
||||||
string.format(ERROR_NON_FUNCTION, "Promise:andThen")
|
|
||||||
)
|
|
||||||
|
|
||||||
return self:_andThen(debug.traceback(nil, 2), successHandler, failureHandler)
|
return self:_andThen(debug.traceback(nil, 2), successHandler, failureHandler)
|
||||||
end
|
end
|
||||||
|
@ -1261,10 +1270,7 @@ end
|
||||||
@return Promise<...any>
|
@return Promise<...any>
|
||||||
]=]
|
]=]
|
||||||
function Promise.prototype:catch(failureHandler)
|
function Promise.prototype:catch(failureHandler)
|
||||||
assert(
|
assert(failureHandler == nil or isCallable(failureHandler), string.format(ERROR_NON_FUNCTION, "Promise:catch"))
|
||||||
failureHandler == nil or type(failureHandler) == "function",
|
|
||||||
string.format(ERROR_NON_FUNCTION, "Promise:catch")
|
|
||||||
)
|
|
||||||
return self:_andThen(debug.traceback(nil, 2), nil, failureHandler)
|
return self:_andThen(debug.traceback(nil, 2), nil, failureHandler)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1285,7 +1291,7 @@ end
|
||||||
@return Promise<...any>
|
@return Promise<...any>
|
||||||
]=]
|
]=]
|
||||||
function Promise.prototype:tap(tapHandler)
|
function Promise.prototype:tap(tapHandler)
|
||||||
assert(type(tapHandler) == "function", string.format(ERROR_NON_FUNCTION, "Promise:tap"))
|
assert(isCallable(tapHandler), string.format(ERROR_NON_FUNCTION, "Promise:tap"))
|
||||||
return self:_andThen(debug.traceback(nil, 2), function(...)
|
return self:_andThen(debug.traceback(nil, 2), function(...)
|
||||||
local callbackReturn = tapHandler(...)
|
local callbackReturn = tapHandler(...)
|
||||||
|
|
||||||
|
@ -1320,7 +1326,7 @@ end
|
||||||
@return Promise
|
@return Promise
|
||||||
]=]
|
]=]
|
||||||
function Promise.prototype:andThenCall(callback, ...)
|
function Promise.prototype:andThenCall(callback, ...)
|
||||||
assert(type(callback) == "function", string.format(ERROR_NON_FUNCTION, "Promise:andThenCall"))
|
assert(isCallable(callback), string.format(ERROR_NON_FUNCTION, "Promise:andThenCall"))
|
||||||
local length, values = pack(...)
|
local length, values = pack(...)
|
||||||
return self:_andThen(debug.traceback(nil, 2), function()
|
return self:_andThen(debug.traceback(nil, 2), function()
|
||||||
return callback(unpack(values, 1, length))
|
return callback(unpack(values, 1, length))
|
||||||
|
@ -1474,10 +1480,7 @@ end
|
||||||
@return Promise<...any>
|
@return Promise<...any>
|
||||||
]=]
|
]=]
|
||||||
function Promise.prototype:finally(finallyHandler)
|
function Promise.prototype:finally(finallyHandler)
|
||||||
assert(
|
assert(finallyHandler == nil or isCallable(finallyHandler), string.format(ERROR_NON_FUNCTION, "Promise:finally"))
|
||||||
finallyHandler == nil or type(finallyHandler) == "function",
|
|
||||||
string.format(ERROR_NON_FUNCTION, "Promise:finally")
|
|
||||||
)
|
|
||||||
return self:_finally(debug.traceback(nil, 2), finallyHandler)
|
return self:_finally(debug.traceback(nil, 2), finallyHandler)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1491,7 +1494,7 @@ end
|
||||||
@return Promise
|
@return Promise
|
||||||
]=]
|
]=]
|
||||||
function Promise.prototype:finallyCall(callback, ...)
|
function Promise.prototype:finallyCall(callback, ...)
|
||||||
assert(type(callback) == "function", string.format(ERROR_NON_FUNCTION, "Promise:finallyCall"))
|
assert(isCallable(callback), string.format(ERROR_NON_FUNCTION, "Promise:finallyCall"))
|
||||||
local length, values = pack(...)
|
local length, values = pack(...)
|
||||||
return self:_finally(debug.traceback(nil, 2), function()
|
return self:_finally(debug.traceback(nil, 2), function()
|
||||||
return callback(unpack(values, 1, length))
|
return callback(unpack(values, 1, length))
|
||||||
|
@ -1540,7 +1543,7 @@ end
|
||||||
@return Promise<...any>
|
@return Promise<...any>
|
||||||
]=]
|
]=]
|
||||||
function Promise.prototype:done(doneHandler)
|
function Promise.prototype:done(doneHandler)
|
||||||
assert(doneHandler == nil or type(doneHandler) == "function", string.format(ERROR_NON_FUNCTION, "Promise:done"))
|
assert(doneHandler == nil or isCallable(doneHandler), string.format(ERROR_NON_FUNCTION, "Promise:done"))
|
||||||
return self:_finally(debug.traceback(nil, 2), doneHandler, true)
|
return self:_finally(debug.traceback(nil, 2), doneHandler, true)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1554,7 +1557,7 @@ end
|
||||||
@return Promise
|
@return Promise
|
||||||
]=]
|
]=]
|
||||||
function Promise.prototype:doneCall(callback, ...)
|
function Promise.prototype:doneCall(callback, ...)
|
||||||
assert(type(callback) == "function", string.format(ERROR_NON_FUNCTION, "Promise:doneCall"))
|
assert(isCallable(callback), string.format(ERROR_NON_FUNCTION, "Promise:doneCall"))
|
||||||
local length, values = pack(...)
|
local length, values = pack(...)
|
||||||
return self:_finally(debug.traceback(nil, 2), function()
|
return self:_finally(debug.traceback(nil, 2), function()
|
||||||
return callback(unpack(values, 1, length))
|
return callback(unpack(values, 1, length))
|
||||||
|
@ -1903,7 +1906,7 @@ end
|
||||||
@param ...? P
|
@param ...? P
|
||||||
]=]
|
]=]
|
||||||
function Promise.retry(callback, times, ...)
|
function Promise.retry(callback, times, ...)
|
||||||
assert(type(callback) == "function", "Parameter #1 to Promise.retry must be a function")
|
assert(isCallable(callback), "Parameter #1 to Promise.retry must be a function")
|
||||||
assert(type(times) == "number", "Parameter #2 to Promise.retry must be a number")
|
assert(type(times) == "number", "Parameter #2 to Promise.retry must be a number")
|
||||||
|
|
||||||
local args, length = { ... }, select("#", ...)
|
local args, length = { ... }, select("#", ...)
|
||||||
|
|
|
@ -5,7 +5,8 @@ return function()
|
||||||
local timeEvent = Instance.new("BindableEvent")
|
local timeEvent = Instance.new("BindableEvent")
|
||||||
Promise._timeEvent = timeEvent.Event
|
Promise._timeEvent = timeEvent.Event
|
||||||
|
|
||||||
local advanceTime do
|
local advanceTime
|
||||||
|
do
|
||||||
local injectedPromiseTime = 0
|
local injectedPromiseTime = 0
|
||||||
|
|
||||||
Promise._getTime = function()
|
Promise._getTime = function()
|
||||||
|
@ -13,7 +14,7 @@ return function()
|
||||||
end
|
end
|
||||||
|
|
||||||
function advanceTime(delta)
|
function advanceTime(delta)
|
||||||
delta = delta or (1/60)
|
delta = delta or (1 / 60)
|
||||||
|
|
||||||
injectedPromiseTime = injectedPromiseTime + delta
|
injectedPromiseTime = injectedPromiseTime + delta
|
||||||
timeEvent:Fire(delta)
|
timeEvent:Fire(delta)
|
||||||
|
@ -145,7 +146,9 @@ return function()
|
||||||
expect(trace:find("nestedCall")).to.be.ok()
|
expect(trace:find("nestedCall")).to.be.ok()
|
||||||
expect(trace:find("runExecutor")).to.be.ok()
|
expect(trace:find("runExecutor")).to.be.ok()
|
||||||
expect(trace:find("runPlanNode")).to.be.ok()
|
expect(trace:find("runPlanNode")).to.be.ok()
|
||||||
expect(trace:find("...Rejected because it was chained to the following Promise, which encountered an error:")).to.be.ok()
|
expect(
|
||||||
|
trace:find("...Rejected because it was chained to the following Promise, which encountered an error:")
|
||||||
|
).to.be.ok()
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it("should report errors from Promises with _error (< v2)", function()
|
it("should report errors from Promises with _error (< v2)", function()
|
||||||
|
@ -158,9 +161,29 @@ return function()
|
||||||
|
|
||||||
local trace = tostring(newPromise._values[1])
|
local trace = tostring(newPromise._values[1])
|
||||||
expect(trace:find("Sample error")).to.be.ok()
|
expect(trace:find("Sample error")).to.be.ok()
|
||||||
expect(trace:find("...Rejected because it was chained to the following Promise, which encountered an error:")).to.be.ok()
|
expect(
|
||||||
|
trace:find("...Rejected because it was chained to the following Promise, which encountered an error:")
|
||||||
|
).to.be.ok()
|
||||||
expect(trace:find("%[No stack trace available")).to.be.ok()
|
expect(trace:find("%[No stack trace available")).to.be.ok()
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
it("should allow callable tables", function()
|
||||||
|
local promise = Promise.new(setmetatable({}, {
|
||||||
|
__call = function(_, resolve)
|
||||||
|
resolve(1)
|
||||||
|
end,
|
||||||
|
}))
|
||||||
|
|
||||||
|
local called = false
|
||||||
|
promise:andThen(setmetatable({}, {
|
||||||
|
__call = function(_, var)
|
||||||
|
expect(var).to.equal(1)
|
||||||
|
called = true
|
||||||
|
end,
|
||||||
|
}))
|
||||||
|
|
||||||
|
expect(called).to.equal(true)
|
||||||
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
describe("Promise.defer", function()
|
describe("Promise.defer", function()
|
||||||
|
@ -206,7 +229,7 @@ return function()
|
||||||
local promise = Promise.delay(2)
|
local promise = Promise.delay(2)
|
||||||
|
|
||||||
Promise.delay(1):andThen(function()
|
Promise.delay(1):andThen(function()
|
||||||
promise:cancel()
|
promise:cancel()
|
||||||
end)
|
end)
|
||||||
|
|
||||||
expect(promise:getStatus()).to.equal(Promise.Status.Started)
|
expect(promise:getStatus()).to.equal(Promise.Status.Started)
|
||||||
|
@ -308,15 +331,12 @@ return function()
|
||||||
|
|
||||||
local promise = Promise.resolve(5)
|
local promise = Promise.resolve(5)
|
||||||
|
|
||||||
local chained = promise:andThen(
|
local chained = promise:andThen(function(...)
|
||||||
function(...)
|
argsLength, args = pack(...)
|
||||||
argsLength, args = pack(...)
|
callCount = callCount + 1
|
||||||
callCount = callCount + 1
|
end, function()
|
||||||
end,
|
badCallCount = badCallCount + 1
|
||||||
function()
|
end)
|
||||||
badCallCount = badCallCount + 1
|
|
||||||
end
|
|
||||||
)
|
|
||||||
|
|
||||||
expect(badCallCount).to.equal(0)
|
expect(badCallCount).to.equal(0)
|
||||||
|
|
||||||
|
@ -342,15 +362,12 @@ return function()
|
||||||
|
|
||||||
local promise = Promise.reject(5)
|
local promise = Promise.reject(5)
|
||||||
|
|
||||||
local chained = promise:andThen(
|
local chained = promise:andThen(function(...)
|
||||||
function(...)
|
badCallCount = badCallCount + 1
|
||||||
badCallCount = badCallCount + 1
|
end, function(...)
|
||||||
end,
|
argsLength, args = pack(...)
|
||||||
function(...)
|
callCount = callCount + 1
|
||||||
argsLength, args = pack(...)
|
end)
|
||||||
callCount = callCount + 1
|
|
||||||
end
|
|
||||||
)
|
|
||||||
|
|
||||||
expect(badCallCount).to.equal(0)
|
expect(badCallCount).to.equal(0)
|
||||||
|
|
||||||
|
@ -397,16 +414,13 @@ return function()
|
||||||
startResolution = resolve
|
startResolution = resolve
|
||||||
end)
|
end)
|
||||||
|
|
||||||
local chained = promise:andThen(
|
local chained = promise:andThen(function(...)
|
||||||
function(...)
|
args = { ... }
|
||||||
args = {...}
|
argsLength = select("#", ...)
|
||||||
argsLength = select("#", ...)
|
callCount = callCount + 1
|
||||||
callCount = callCount + 1
|
end, function()
|
||||||
end,
|
badCallCount = badCallCount + 1
|
||||||
function()
|
end)
|
||||||
badCallCount = badCallCount + 1
|
|
||||||
end
|
|
||||||
)
|
|
||||||
|
|
||||||
expect(callCount).to.equal(0)
|
expect(callCount).to.equal(0)
|
||||||
expect(badCallCount).to.equal(0)
|
expect(badCallCount).to.equal(0)
|
||||||
|
@ -440,16 +454,13 @@ return function()
|
||||||
startResolution = reject
|
startResolution = reject
|
||||||
end)
|
end)
|
||||||
|
|
||||||
local chained = promise:andThen(
|
local chained = promise:andThen(function()
|
||||||
function()
|
badCallCount = badCallCount + 1
|
||||||
badCallCount = badCallCount + 1
|
end, function(...)
|
||||||
end,
|
args = { ... }
|
||||||
function(...)
|
argsLength = select("#", ...)
|
||||||
args = {...}
|
callCount = callCount + 1
|
||||||
argsLength = select("#", ...)
|
end)
|
||||||
callCount = callCount + 1
|
|
||||||
end
|
|
||||||
)
|
|
||||||
|
|
||||||
expect(callCount).to.equal(0)
|
expect(callCount).to.equal(0)
|
||||||
expect(badCallCount).to.equal(0)
|
expect(badCallCount).to.equal(0)
|
||||||
|
@ -476,9 +487,7 @@ return function()
|
||||||
local x, y, z
|
local x, y, z
|
||||||
Promise.new(function(resolve, reject)
|
Promise.new(function(resolve, reject)
|
||||||
reject(1, 2, 3)
|
reject(1, 2, 3)
|
||||||
end)
|
end):andThen(function() end):catch(function(a, b, c)
|
||||||
:andThen(function() end)
|
|
||||||
:catch(function(a, b, c)
|
|
||||||
x, y, z = a, b, c
|
x, y, z = a, b, c
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
@ -492,11 +501,13 @@ return function()
|
||||||
it("should mark promises as cancelled and not resolve or reject them", function()
|
it("should mark promises as cancelled and not resolve or reject them", function()
|
||||||
local callCount = 0
|
local callCount = 0
|
||||||
local finallyCallCount = 0
|
local finallyCallCount = 0
|
||||||
local promise = Promise.new(function() end):andThen(function()
|
local promise = Promise.new(function() end)
|
||||||
callCount = callCount + 1
|
:andThen(function()
|
||||||
end):finally(function()
|
callCount = callCount + 1
|
||||||
finallyCallCount = finallyCallCount + 1
|
end)
|
||||||
end)
|
:finally(function()
|
||||||
|
finallyCallCount = finallyCallCount + 1
|
||||||
|
end)
|
||||||
|
|
||||||
promise:cancel()
|
promise:cancel()
|
||||||
promise:cancel() -- Twice to check call counts
|
promise:cancel() -- Twice to check call counts
|
||||||
|
@ -556,7 +567,9 @@ return function()
|
||||||
it("should track consumers", function()
|
it("should track consumers", function()
|
||||||
local pending = Promise.new(function() end)
|
local pending = Promise.new(function() end)
|
||||||
local p0 = Promise.resolve()
|
local p0 = Promise.resolve()
|
||||||
local p1 = p0:finally(function() return pending end)
|
local p1 = p0:finally(function()
|
||||||
|
return pending
|
||||||
|
end)
|
||||||
local p2 = Promise.new(function(resolve)
|
local p2 = Promise.new(function(resolve)
|
||||||
resolve(p1)
|
resolve(p1)
|
||||||
end)
|
end)
|
||||||
|
@ -596,9 +609,7 @@ return function()
|
||||||
end):finally(finally)
|
end):finally(finally)
|
||||||
|
|
||||||
-- Chained promise
|
-- Chained promise
|
||||||
Promise.resolve():andThen(function()
|
Promise.resolve():andThen(function() end):finally(finally):finally(finally)
|
||||||
|
|
||||||
end):finally(finally):finally(finally)
|
|
||||||
|
|
||||||
-- Rejected promise
|
-- Rejected promise
|
||||||
Promise.reject():finally(finally)
|
Promise.reject():finally(finally)
|
||||||
|
@ -620,11 +631,13 @@ return function()
|
||||||
it("should forward return values", function()
|
it("should forward return values", function()
|
||||||
local value
|
local value
|
||||||
|
|
||||||
Promise.resolve():finally(function()
|
Promise.resolve()
|
||||||
return 1
|
:finally(function()
|
||||||
end):andThen(function(v)
|
return 1
|
||||||
value = v
|
end)
|
||||||
end)
|
:andThen(function(v)
|
||||||
|
value = v
|
||||||
|
end)
|
||||||
|
|
||||||
expect(value).to.equal(1)
|
expect(value).to.equal(1)
|
||||||
end)
|
end)
|
||||||
|
@ -649,7 +662,7 @@ return function()
|
||||||
|
|
||||||
it("should error if given non-promise values", function()
|
it("should error if given non-promise values", function()
|
||||||
expect(function()
|
expect(function()
|
||||||
Promise.all({{}, {}, {}})
|
Promise.all({ {}, {}, {} })
|
||||||
end).to.throw()
|
end).to.throw()
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
@ -662,7 +675,7 @@ return function()
|
||||||
|
|
||||||
for i = 1, testValuesLength do
|
for i = 1, testValuesLength do
|
||||||
promises[i] = Promise.new(function(resolve)
|
promises[i] = Promise.new(function(resolve)
|
||||||
resolveFunctions[i] = {resolve, testValues[i]}
|
resolveFunctions[i] = { resolve, testValues[i] }
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -698,7 +711,7 @@ return function()
|
||||||
resolveB = resolve
|
resolveB = resolve
|
||||||
end)
|
end)
|
||||||
|
|
||||||
local combinedPromise = Promise.all({a, b})
|
local combinedPromise = Promise.all({ a, b })
|
||||||
|
|
||||||
expect(combinedPromise:getStatus()).to.equal(Promise.Status.Started)
|
expect(combinedPromise:getStatus()).to.equal(Promise.Status.Started)
|
||||||
|
|
||||||
|
@ -727,7 +740,7 @@ return function()
|
||||||
resolveB = resolve
|
resolveB = resolve
|
||||||
end)
|
end)
|
||||||
|
|
||||||
local combinedPromise = Promise.all({a, b})
|
local combinedPromise = Promise.all({ a, b })
|
||||||
|
|
||||||
expect(combinedPromise:getStatus()).to.equal(Promise.Status.Started)
|
expect(combinedPromise:getStatus()).to.equal(Promise.Status.Started)
|
||||||
|
|
||||||
|
@ -755,7 +768,7 @@ return function()
|
||||||
rejectB = reject
|
rejectB = reject
|
||||||
end)
|
end)
|
||||||
|
|
||||||
local combinedPromise = Promise.all({a, b})
|
local combinedPromise = Promise.all({ a, b })
|
||||||
|
|
||||||
expect(combinedPromise:getStatus()).to.equal(Promise.Status.Started)
|
expect(combinedPromise:getStatus()).to.equal(Promise.Status.Started)
|
||||||
|
|
||||||
|
@ -788,7 +801,7 @@ return function()
|
||||||
expect(Promise.all({
|
expect(Promise.all({
|
||||||
Promise.resolve(),
|
Promise.resolve(),
|
||||||
Promise.reject(),
|
Promise.reject(),
|
||||||
p
|
p,
|
||||||
}):getStatus()).to.equal(Promise.Status.Rejected)
|
}):getStatus()).to.equal(Promise.Status.Rejected)
|
||||||
expect(p:getStatus()).to.equal(Promise.Status.Cancelled)
|
expect(p:getStatus()).to.equal(Promise.Status.Cancelled)
|
||||||
end)
|
end)
|
||||||
|
@ -800,7 +813,7 @@ return function()
|
||||||
local promises = {
|
local promises = {
|
||||||
Promise.new(function() end),
|
Promise.new(function() end),
|
||||||
Promise.new(function() end),
|
Promise.new(function() end),
|
||||||
p
|
p,
|
||||||
}
|
}
|
||||||
|
|
||||||
Promise.all(promises):cancel()
|
Promise.all(promises):cancel()
|
||||||
|
@ -824,7 +837,7 @@ return function()
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it("should accept promises in the list", function()
|
it("should accept promises in the list", function()
|
||||||
local sum = Promise.fold({Promise.resolve(1), 2, 3}, function(sum, element)
|
local sum = Promise.fold({ Promise.resolve(1), 2, 3 }, function(sum, element)
|
||||||
return sum + element
|
return sum + element
|
||||||
end, 0)
|
end, 0)
|
||||||
expect(Promise.is(sum)).to.equal(true)
|
expect(Promise.is(sum)).to.equal(true)
|
||||||
|
@ -833,7 +846,7 @@ return function()
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it("should always return a promise even if the list or reducer don't use them", function()
|
it("should always return a promise even if the list or reducer don't use them", function()
|
||||||
local sum = Promise.fold({1, 2, 3}, function(sum, element, index)
|
local sum = Promise.fold({ 1, 2, 3 }, function(sum, element, index)
|
||||||
if index == 2 then
|
if index == 2 then
|
||||||
return Promise.delay(1):andThenReturn(sum + element)
|
return Promise.delay(1):andThenReturn(sum + element)
|
||||||
else
|
else
|
||||||
|
@ -849,7 +862,7 @@ return function()
|
||||||
|
|
||||||
it("should return the first rejected promise", function()
|
it("should return the first rejected promise", function()
|
||||||
local errorMessage = "foo"
|
local errorMessage = "foo"
|
||||||
local sum = Promise.fold({1, 2, 3}, function(sum, element, index)
|
local sum = Promise.fold({ 1, 2, 3 }, function(sum, element, index)
|
||||||
if index == 2 then
|
if index == 2 then
|
||||||
return Promise.reject(errorMessage)
|
return Promise.reject(errorMessage)
|
||||||
else
|
else
|
||||||
|
@ -864,14 +877,14 @@ return function()
|
||||||
|
|
||||||
it("should return the first canceled promise", function()
|
it("should return the first canceled promise", function()
|
||||||
local secondPromise
|
local secondPromise
|
||||||
local sum = Promise.fold({1, 2, 3}, function(sum, element, index)
|
local sum = Promise.fold({ 1, 2, 3 }, function(sum, element, index)
|
||||||
if index == 1 then
|
if index == 1 then
|
||||||
return sum + element
|
return sum + element
|
||||||
elseif index == 2 then
|
elseif index == 2 then
|
||||||
secondPromise = Promise.delay(1):andThenReturn(sum + element)
|
secondPromise = Promise.delay(1):andThenReturn(sum + element)
|
||||||
return secondPromise
|
return secondPromise
|
||||||
else
|
else
|
||||||
error('this should not run if the promise is cancelled')
|
error("this should not run if the promise is cancelled")
|
||||||
end
|
end
|
||||||
end, 0)
|
end, 0)
|
||||||
expect(Promise.is(sum)).to.equal(true)
|
expect(Promise.is(sum)).to.equal(true)
|
||||||
|
@ -885,7 +898,7 @@ return function()
|
||||||
it("should resolve with the first settled value", function()
|
it("should resolve with the first settled value", function()
|
||||||
local promise = Promise.race({
|
local promise = Promise.race({
|
||||||
Promise.resolve(1),
|
Promise.resolve(1),
|
||||||
Promise.resolve(2)
|
Promise.resolve(2),
|
||||||
}):andThen(function(value)
|
}):andThen(function(value)
|
||||||
expect(value).to.equal(1)
|
expect(value).to.equal(1)
|
||||||
end)
|
end)
|
||||||
|
@ -901,7 +914,7 @@ return function()
|
||||||
Promise.new(function() end),
|
Promise.new(function() end),
|
||||||
Promise.new(function(resolve)
|
Promise.new(function(resolve)
|
||||||
resolve(2)
|
resolve(2)
|
||||||
end)
|
end),
|
||||||
}
|
}
|
||||||
|
|
||||||
local promise = Promise.race(promises)
|
local promise = Promise.race(promises)
|
||||||
|
@ -916,7 +929,7 @@ return function()
|
||||||
expect(Promise.race({
|
expect(Promise.race({
|
||||||
Promise.reject(),
|
Promise.reject(),
|
||||||
Promise.resolve(),
|
Promise.resolve(),
|
||||||
p
|
p,
|
||||||
}):getStatus()).to.equal(Promise.Status.Rejected)
|
}):getStatus()).to.equal(Promise.Status.Rejected)
|
||||||
expect(p:getStatus()).to.equal(Promise.Status.Cancelled)
|
expect(p:getStatus()).to.equal(Promise.Status.Cancelled)
|
||||||
end)
|
end)
|
||||||
|
@ -937,7 +950,7 @@ return function()
|
||||||
local promises = {
|
local promises = {
|
||||||
Promise.new(function() end),
|
Promise.new(function() end),
|
||||||
Promise.new(function() end),
|
Promise.new(function() end),
|
||||||
p
|
p,
|
||||||
}
|
}
|
||||||
|
|
||||||
Promise.race(promises):cancel()
|
Promise.race(promises):cancel()
|
||||||
|
@ -965,9 +978,9 @@ return function()
|
||||||
|
|
||||||
it("should catch errors after a yield", function()
|
it("should catch errors after a yield", function()
|
||||||
local bindable = Instance.new("BindableEvent")
|
local bindable = Instance.new("BindableEvent")
|
||||||
local test = Promise.promisify(function ()
|
local test = Promise.promisify(function()
|
||||||
bindable.Event:Wait()
|
bindable.Event:Wait()
|
||||||
error('errortext')
|
error("errortext")
|
||||||
end)
|
end)
|
||||||
|
|
||||||
local promise = test()
|
local promise = test()
|
||||||
|
@ -1026,7 +1039,7 @@ return function()
|
||||||
it("should catch synchronous errors", function()
|
it("should catch synchronous errors", function()
|
||||||
local errorText
|
local errorText
|
||||||
Promise.try(function()
|
Promise.try(function()
|
||||||
error('errortext')
|
error("errortext")
|
||||||
end):catch(function(e)
|
end):catch(function(e)
|
||||||
errorText = tostring(e)
|
errorText = tostring(e)
|
||||||
end)
|
end)
|
||||||
|
@ -1048,7 +1061,7 @@ return function()
|
||||||
local bindable = Instance.new("BindableEvent")
|
local bindable = Instance.new("BindableEvent")
|
||||||
local promise = Promise.try(function()
|
local promise = Promise.try(function()
|
||||||
bindable.Event:Wait()
|
bindable.Event:Wait()
|
||||||
error('errortext')
|
error("errortext")
|
||||||
end)
|
end)
|
||||||
|
|
||||||
expect(promise:getStatus()).to.equal(Promise.Status.Started)
|
expect(promise:getStatus()).to.equal(Promise.Status.Started)
|
||||||
|
@ -1127,11 +1140,13 @@ return function()
|
||||||
expect(value).to.equal(true)
|
expect(value).to.equal(true)
|
||||||
|
|
||||||
local never, always
|
local never, always
|
||||||
Promise.reject():done(function()
|
Promise.reject()
|
||||||
never = true
|
:done(function()
|
||||||
end):finally(function()
|
never = true
|
||||||
always = true
|
end)
|
||||||
end)
|
:finally(function()
|
||||||
|
always = true
|
||||||
|
end)
|
||||||
|
|
||||||
expect(never).to.never.be.ok()
|
expect(never).to.never.be.ok()
|
||||||
expect(always).to.be.ok()
|
expect(always).to.be.ok()
|
||||||
|
@ -1143,7 +1158,7 @@ return function()
|
||||||
local p = Promise.some({
|
local p = Promise.some({
|
||||||
Promise.resolve(1),
|
Promise.resolve(1),
|
||||||
Promise.reject(),
|
Promise.reject(),
|
||||||
Promise.resolve(2)
|
Promise.resolve(2),
|
||||||
}, 2)
|
}, 2)
|
||||||
expect(p:getStatus()).to.equal(Promise.Status.Resolved)
|
expect(p:getStatus()).to.equal(Promise.Status.Resolved)
|
||||||
expect(p._values[1][1]).to.equal(1)
|
expect(p._values[1][1]).to.equal(1)
|
||||||
|
@ -1153,13 +1168,15 @@ return function()
|
||||||
it("should error if the goal can't be reached", function()
|
it("should error if the goal can't be reached", function()
|
||||||
expect(Promise.some({
|
expect(Promise.some({
|
||||||
Promise.resolve(),
|
Promise.resolve(),
|
||||||
Promise.reject()
|
Promise.reject(),
|
||||||
}, 2):getStatus()).to.equal(Promise.Status.Rejected)
|
}, 2):getStatus()).to.equal(Promise.Status.Rejected)
|
||||||
|
|
||||||
local reject
|
local reject
|
||||||
local p = Promise.some({
|
local p = Promise.some({
|
||||||
Promise.resolve(),
|
Promise.resolve(),
|
||||||
Promise.new(function(_, r) reject = r end)
|
Promise.new(function(_, r)
|
||||||
|
reject = r
|
||||||
|
end),
|
||||||
}, 2)
|
}, 2)
|
||||||
|
|
||||||
expect(p:getStatus()).to.equal(Promise.Status.Started)
|
expect(p:getStatus()).to.equal(Promise.Status.Started)
|
||||||
|
@ -1171,12 +1188,14 @@ return function()
|
||||||
it("should cancel pending Promises once the goal is reached", function()
|
it("should cancel pending Promises once the goal is reached", function()
|
||||||
local resolve
|
local resolve
|
||||||
local pending1 = Promise.new(function() end)
|
local pending1 = Promise.new(function() end)
|
||||||
local pending2 = Promise.new(function(r) resolve = r end)
|
local pending2 = Promise.new(function(r)
|
||||||
|
resolve = r
|
||||||
|
end)
|
||||||
|
|
||||||
local some = Promise.some({
|
local some = Promise.some({
|
||||||
pending1,
|
pending1,
|
||||||
pending2,
|
pending2,
|
||||||
Promise.resolve()
|
Promise.resolve(),
|
||||||
}, 2)
|
}, 2)
|
||||||
|
|
||||||
expect(some:getStatus()).to.equal(Promise.Status.Started)
|
expect(some:getStatus()).to.equal(Promise.Status.Started)
|
||||||
|
@ -1198,7 +1217,7 @@ return function()
|
||||||
|
|
||||||
it("should return an empty array if amount is 0", function()
|
it("should return an empty array if amount is 0", function()
|
||||||
local p = Promise.some({
|
local p = Promise.some({
|
||||||
Promise.resolve(2)
|
Promise.resolve(2),
|
||||||
}, 0)
|
}, 0)
|
||||||
|
|
||||||
expect(p:getStatus()).to.equal(Promise.Status.Resolved)
|
expect(p:getStatus()).to.equal(Promise.Status.Resolved)
|
||||||
|
@ -1226,7 +1245,7 @@ return function()
|
||||||
local promises = {
|
local promises = {
|
||||||
Promise.new(function() end),
|
Promise.new(function() end),
|
||||||
Promise.new(function() end),
|
Promise.new(function() end),
|
||||||
p
|
p,
|
||||||
}
|
}
|
||||||
|
|
||||||
Promise.some(promises, 3):cancel()
|
Promise.some(promises, 3):cancel()
|
||||||
|
@ -1241,7 +1260,7 @@ return function()
|
||||||
local p = Promise.any({
|
local p = Promise.any({
|
||||||
Promise.reject(),
|
Promise.reject(),
|
||||||
Promise.reject(),
|
Promise.reject(),
|
||||||
Promise.resolve(1)
|
Promise.resolve(1),
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(p:getStatus()).to.equal(Promise.Status.Resolved)
|
expect(p:getStatus()).to.equal(Promise.Status.Resolved)
|
||||||
|
@ -1265,7 +1284,9 @@ return function()
|
||||||
Promise.resolve(),
|
Promise.resolve(),
|
||||||
Promise.reject(),
|
Promise.reject(),
|
||||||
Promise.resolve(),
|
Promise.resolve(),
|
||||||
Promise.new(function(_, r) reject = r end)
|
Promise.new(function(_, r)
|
||||||
|
reject = r
|
||||||
|
end),
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(p:getStatus()).to.equal(Promise.Status.Started)
|
expect(p:getStatus()).to.equal(Promise.Status.Started)
|
||||||
|
@ -1284,7 +1305,7 @@ return function()
|
||||||
local promises = {
|
local promises = {
|
||||||
Promise.new(function() end),
|
Promise.new(function() end),
|
||||||
Promise.new(function() end),
|
Promise.new(function() end),
|
||||||
p
|
p,
|
||||||
}
|
}
|
||||||
|
|
||||||
Promise.allSettled(promises):cancel()
|
Promise.allSettled(promises):cancel()
|
||||||
|
@ -1349,9 +1370,12 @@ return function()
|
||||||
describe("Promise.each", function()
|
describe("Promise.each", function()
|
||||||
it("should iterate", function()
|
it("should iterate", function()
|
||||||
local ok, result = Promise.each({
|
local ok, result = Promise.each({
|
||||||
"foo", "bar", "baz", "qux"
|
"foo",
|
||||||
|
"bar",
|
||||||
|
"baz",
|
||||||
|
"qux",
|
||||||
}, function(...)
|
}, function(...)
|
||||||
return {...}
|
return { ... }
|
||||||
end):_unwrap()
|
end):_unwrap()
|
||||||
|
|
||||||
expect(ok).to.equal(true)
|
expect(ok).to.equal(true)
|
||||||
|
@ -1370,7 +1394,9 @@ return function()
|
||||||
local callCounts = {}
|
local callCounts = {}
|
||||||
|
|
||||||
local promise = Promise.each({
|
local promise = Promise.each({
|
||||||
"foo", "bar", "baz"
|
"foo",
|
||||||
|
"bar",
|
||||||
|
"baz",
|
||||||
}, function(value, index)
|
}, function(value, index)
|
||||||
callCounts[index] = (callCounts[index] or 0) + 1
|
callCounts[index] = (callCounts[index] or 0) + 1
|
||||||
|
|
||||||
|
@ -1415,7 +1441,7 @@ return function()
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it("should reject with the value if the predicate promise rejects", function()
|
it("should reject with the value if the predicate promise rejects", function()
|
||||||
local promise = Promise.each({1, 2, 3}, function()
|
local promise = Promise.each({ 1, 2, 3 }, function()
|
||||||
return Promise.reject("foobar")
|
return Promise.reject("foobar")
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
@ -1430,7 +1456,7 @@ return function()
|
||||||
end)
|
end)
|
||||||
|
|
||||||
local promise = Promise.each({
|
local promise = Promise.each({
|
||||||
innerPromise
|
innerPromise,
|
||||||
}, function(value)
|
}, function(value)
|
||||||
return value * 2
|
return value * 2
|
||||||
end)
|
end)
|
||||||
|
@ -1445,7 +1471,7 @@ return function()
|
||||||
|
|
||||||
it("should reject with the value if a Promise from the list rejects", function()
|
it("should reject with the value if a Promise from the list rejects", function()
|
||||||
local called = false
|
local called = false
|
||||||
local promise = Promise.each({1, 2, Promise.reject("foobar")}, function(value)
|
local promise = Promise.each({ 1, 2, Promise.reject("foobar") }, function(value)
|
||||||
called = true
|
called = true
|
||||||
return "never"
|
return "never"
|
||||||
end)
|
end)
|
||||||
|
@ -1460,7 +1486,7 @@ return function()
|
||||||
cancelled:cancel()
|
cancelled:cancel()
|
||||||
|
|
||||||
local called = false
|
local called = false
|
||||||
local promise = Promise.each({1, 2, cancelled}, function()
|
local promise = Promise.each({ 1, 2, cancelled }, function()
|
||||||
called = true
|
called = true
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
@ -1473,13 +1499,13 @@ return function()
|
||||||
local callCounts = {}
|
local callCounts = {}
|
||||||
|
|
||||||
local promise = Promise.each({
|
local promise = Promise.each({
|
||||||
"foo", "bar", "baz"
|
"foo",
|
||||||
|
"bar",
|
||||||
|
"baz",
|
||||||
}, function(value, index)
|
}, function(value, index)
|
||||||
callCounts[index] = (callCounts[index] or 0) + 1
|
callCounts[index] = (callCounts[index] or 0) + 1
|
||||||
|
|
||||||
return Promise.new(function()
|
return Promise.new(function() end)
|
||||||
|
|
||||||
end)
|
|
||||||
end)
|
end)
|
||||||
|
|
||||||
expect(promise:getStatus()).to.equal(Promise.Status.Started)
|
expect(promise:getStatus()).to.equal(Promise.Status.Started)
|
||||||
|
@ -1497,10 +1523,11 @@ return function()
|
||||||
local innerPromise
|
local innerPromise
|
||||||
|
|
||||||
local promise = Promise.each({
|
local promise = Promise.each({
|
||||||
"foo", "bar", "baz"
|
"foo",
|
||||||
|
"bar",
|
||||||
|
"baz",
|
||||||
}, function(value, index)
|
}, function(value, index)
|
||||||
innerPromise = Promise.new(function()
|
innerPromise = Promise.new(function() end)
|
||||||
end)
|
|
||||||
return innerPromise
|
return innerPromise
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
@ -1512,7 +1539,7 @@ return function()
|
||||||
it("should cancel Promises in the list if Promise.each is cancelled", function()
|
it("should cancel Promises in the list if Promise.each is cancelled", function()
|
||||||
local innerPromise = Promise.new(function() end)
|
local innerPromise = Promise.new(function() end)
|
||||||
|
|
||||||
local promise = Promise.each({innerPromise}, function() end)
|
local promise = Promise.each({ innerPromise }, function() end)
|
||||||
|
|
||||||
promise:cancel()
|
promise:cancel()
|
||||||
|
|
||||||
|
@ -1595,7 +1622,7 @@ return function()
|
||||||
local obj = {
|
local obj = {
|
||||||
andThen = function()
|
andThen = function()
|
||||||
return 1
|
return 1
|
||||||
end
|
end,
|
||||||
}
|
}
|
||||||
|
|
||||||
expect(Promise.is(obj)).to.equal(true)
|
expect(Promise.is(obj)).to.equal(true)
|
||||||
|
@ -1606,9 +1633,7 @@ return function()
|
||||||
OldPromise.prototype = {}
|
OldPromise.prototype = {}
|
||||||
OldPromise.__index = OldPromise.prototype
|
OldPromise.__index = OldPromise.prototype
|
||||||
|
|
||||||
function OldPromise.prototype:andThen()
|
function OldPromise.prototype:andThen() end
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
local oldPromise = setmetatable({}, OldPromise)
|
local oldPromise = setmetatable({}, OldPromise)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue