From 9e0186b0ed9b0005807b5d383faf8626fdf36168 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Mon, 8 Jun 2020 14:01:02 +0100 Subject: util.promise: Add all_settled, which follows semantics of allSettled from ES2020 --- spec/util_promise_spec.lua | 54 ++++++++++++++++++++++++++++++++++++++++++++++ util/promise.lua | 22 +++++++++++++++++++ 2 files changed, 76 insertions(+) diff --git a/spec/util_promise_spec.lua b/spec/util_promise_spec.lua index 0008c6a2..6fb5d6bd 100644 --- a/spec/util_promise_spec.lua +++ b/spec/util_promise_spec.lua @@ -353,6 +353,60 @@ describe("util.promise", function () assert.equal("fail", result); end); end); + describe("all_settled()", function () + it("works with fulfilled promises", function () + local p1, p2 = promise.resolve("yep"), promise.resolve("nope"); + local p = promise.all_settled({ p1, p2 }); + local result; + p:next(function (v) + result = v; + end); + assert.same({ + { status = "fulfilled", value = "yep" }; + { status = "fulfilled", value = "nope" }; + }, result); + end); + it("works with pending promises", function () + local r1, r2; + local p1, p2 = promise.new(function (resolve) r1 = resolve end), promise.new(function (resolve) r2 = resolve end); + local p = promise.all_settled({ p1, p2 }); + + local result; + local cb = spy.new(function (v) + result = v; + end); + p:next(cb); + assert.spy(cb).was_called(0); + r2("yep"); + assert.spy(cb).was_called(0); + r1("nope"); + assert.spy(cb).was_called(1); + assert.same({ + { status = "fulfilled", value = "nope" }; + { status = "fulfilled", value = "yep" }; + }, result); + end); + it("works when some promises reject", function () + local r1, r2; + local p1, p2 = promise.new(function (resolve) r1 = resolve end), promise.new(function (_, reject) r2 = reject end); + local p = promise.all_settled({ p1, p2 }); + + local result; + local cb = spy.new(function (v) + result = v; + end); + p:next(cb); + assert.spy(cb).was_called(0); + r2("this fails"); + assert.spy(cb).was_called(0); + r1("this succeeds"); + assert.spy(cb).was_called(1); + assert.same({ + { status = "fulfilled", value = "this succeeds" }; + { status = "rejected", reason = "this fails" }; + }, result); + end); + end); describe("catch()", function () it("works", function () local result; diff --git a/util/promise.lua b/util/promise.lua index 0b182b54..6ebb0dd6 100644 --- a/util/promise.lua +++ b/util/promise.lua @@ -104,6 +104,27 @@ local function all(promises) end); end +local function all_settled(promises) + return new(function (resolve) + local count, total, results = 0, #promises, {}; + for i = 1, total do + promises[i]:next(function (v) + results[i] = { status = "fulfilled", value = v }; + count = count + 1; + if count == total then + resolve(results); + end + end, function (e) + results[i] = { status = "rejected", reason = e }; + count = count + 1; + if count == total then + resolve(results); + end + end); + end + end); +end + local function race(promises) return new(function (resolve, reject) for i = 1, #promises do @@ -149,6 +170,7 @@ return { resolve = resolve; reject = reject; all = all; + all_settled = all_settled; race = race; try = try; is_promise = is_promise; -- cgit v1.2.3