Software /
code /
prosody
Comparison
util/promise.lua @ 9549:800c274928bf
util.promise: Ensure chained promises always receive a value/rejection even if an intermediate promise has no handlers
author | Matthew Wild <mwild1@gmail.com> |
---|---|
date | Thu, 25 Oct 2018 14:38:00 +0100 |
parent | 9548:a83afc22e9d7 |
child | 9550:98de4c2e2627 |
comparison
equal
deleted
inserted
replaced
9548:a83afc22e9d7 | 9549:800c274928bf |
---|---|
8 local function is_promise(o) | 8 local function is_promise(o) |
9 local mt = getmetatable(o); | 9 local mt = getmetatable(o); |
10 return mt == promise_mt; | 10 return mt == promise_mt; |
11 end | 11 end |
12 | 12 |
13 local function next_pending(self, on_fulfilled, on_rejected) | 13 local function wrap_handler(f, resolve, reject, default) |
14 table.insert(self._pending_on_fulfilled, on_fulfilled); | 14 if not f then |
15 table.insert(self._pending_on_rejected, on_rejected); | 15 return default; |
16 end | |
17 return function (param) | |
18 local ok, ret = pcall(f, param); | |
19 if ok then | |
20 resolve(ret); | |
21 else | |
22 reject(ret); | |
23 end | |
24 return true; | |
25 end; | |
16 end | 26 end |
17 | 27 |
18 local function next_fulfilled(promise, on_fulfilled, on_rejected) -- luacheck: ignore 212/on_rejected | 28 local function next_pending(self, on_fulfilled, on_rejected, resolve, reject) |
19 on_fulfilled(promise.value); | 29 table.insert(self._pending_on_fulfilled, wrap_handler(on_fulfilled, resolve, reject, resolve)); |
30 table.insert(self._pending_on_rejected, wrap_handler(on_rejected, resolve, reject, reject)); | |
20 end | 31 end |
21 | 32 |
22 local function next_rejected(promise, on_fulfilled, on_rejected) -- luacheck: ignore 212/on_fulfilled | 33 local function next_fulfilled(promise, on_fulfilled, on_rejected, resolve, reject) -- luacheck: ignore 212/on_rejected |
23 on_rejected(promise.reason); | 34 wrap_handler(on_fulfilled, resolve, reject)(promise.value); |
35 end | |
36 | |
37 local function next_rejected(promise, on_fulfilled, on_rejected, resolve, reject) -- luacheck: ignore 212/on_fulfilled | |
38 wrap_handler(on_rejected, resolve, reject)(promise.reason); | |
24 end | 39 end |
25 | 40 |
26 local function promise_settle(promise, new_state, new_next, cbs, value) | 41 local function promise_settle(promise, new_state, new_next, cbs, value) |
27 if promise._state ~= "pending" then | 42 if promise._state ~= "pending" then |
28 return; | 43 return; |
55 elseif promise_settle(p, "rejected", next_rejected, p._pending_on_rejected, e) then | 70 elseif promise_settle(p, "rejected", next_rejected, p._pending_on_rejected, e) then |
56 p.reason = e; | 71 p.reason = e; |
57 end | 72 end |
58 end | 73 end |
59 return _resolve, _reject; | 74 return _resolve, _reject; |
60 end | |
61 | |
62 local function wrap_handler(f, resolve, reject) | |
63 return function (param) | |
64 local ok, ret = pcall(f, param); | |
65 if ok then | |
66 resolve(ret); | |
67 else | |
68 reject(ret); | |
69 end | |
70 end; | |
71 end | 75 end |
72 | 76 |
73 local function new(f) | 77 local function new(f) |
74 local p = setmetatable({ _state = "pending", _next = next_pending, _pending_on_fulfilled = {}, _pending_on_rejected = {} }, promise_mt); | 78 local p = setmetatable({ _state = "pending", _next = next_pending, _pending_on_fulfilled = {}, _pending_on_rejected = {} }, promise_mt); |
75 if f then | 79 if f then |
121 return resolve():next(function () return f(); end); | 125 return resolve():next(function () return f(); end); |
122 end | 126 end |
123 | 127 |
124 function promise_methods:next(on_fulfilled, on_rejected) | 128 function promise_methods:next(on_fulfilled, on_rejected) |
125 return new(function (resolve, reject) --luacheck: ignore 431/resolve 431/reject | 129 return new(function (resolve, reject) --luacheck: ignore 431/resolve 431/reject |
126 self:_next( | 130 self:_next(on_fulfilled, on_rejected, resolve, reject); |
127 on_fulfilled and wrap_handler(on_fulfilled, resolve, reject) or nil, | |
128 on_rejected and wrap_handler(on_rejected, resolve, reject) or nil | |
129 ); | |
130 end); | 131 end); |
131 end | 132 end |
132 | 133 |
133 function promise_methods:catch(on_rejected) | 134 function promise_methods:catch(on_rejected) |
134 return self:next(nil, on_rejected); | 135 return self:next(nil, on_rejected); |