aboutsummaryrefslogtreecommitdiffstats
path: root/util/promise.lua
diff options
context:
space:
mode:
Diffstat (limited to 'util/promise.lua')
-rw-r--r--util/promise.lua72
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;