diff options
Diffstat (limited to 'util/promise.lua')
-rw-r--r-- | util/promise.lua | 72 |
1 files changed, 63 insertions, 9 deletions
diff --git a/util/promise.lua b/util/promise.lua index 75c8697b..ea30898c 100644 --- a/util/promise.lua +++ b/util/promise.lua @@ -2,6 +2,7 @@ local promise_methods = {}; local promise_mt = { __name = "promise", __index = promise_methods }; local xpcall = require "util.xpcall".xpcall; +local unpack = table.unpack or unpack; --luacheck: ignore 113 function promise_mt:__tostring() return "promise (" .. (self._state or "invalid") .. ")"; @@ -49,6 +50,9 @@ local function promise_settle(promise, new_state, new_next, cbs, value) for _, cb in ipairs(cbs) do cb(value); end + -- No need to keep references to callbacks + promise._pending_on_fulfilled = nil; + promise._pending_on_rejected = nil; return true; end @@ -88,16 +92,64 @@ end local function all(promises) return new(function (resolve, reject) - local count, total, results = 0, #promises, {}; - for i = 1, total do - promises[i]:next(function (v) - results[i] = v; - count = count + 1; - if count == total then - resolve(results); - end - end, reject); + local settled, results, loop_finished = 0, {}, false; + local total = 0; + for k, v in pairs(promises) do + if is_promise(v) then + total = total + 1; + v:next(function (value) + results[k] = value; + settled = settled + 1; + if settled == total and loop_finished then + resolve(results); + end + end, reject); + else + results[k] = v; + end end + loop_finished = true; + if settled == total then + resolve(results); + end + end); +end + +local function all_settled(promises) + return new(function (resolve) + local settled, results, loop_finished = 0, {}, false; + local total = 0; + for k, v in pairs(promises) do + if is_promise(v) then + total = total + 1; + v:next(function (value) + results[k] = { status = "fulfilled", value = value }; + settled = settled + 1; + if settled == total and loop_finished then + resolve(results); + end + end, function (e) + results[k] = { status = "rejected", reason = e }; + settled = settled + 1; + if settled == total and loop_finished then + resolve(results); + end + end); + else + results[k] = v; + end + end + loop_finished = true; + if settled == total then + resolve(results); + end + end); +end + +local function join(handler, ...) + local promises, n = { ... }, select("#", ...); + return all(promises):next(function (results) + return handler(unpack(results, 1, n)); end); end @@ -144,8 +196,10 @@ end return { new = new; resolve = resolve; + join = join; reject = reject; all = all; + all_settled = all_settled; race = race; try = try; is_promise = is_promise; |