Software /
code /
prosody
Comparison
util/promise.lua @ 9456:d54a0e129af8
util.promise: ES6-like API for promises
author | Matthew Wild <mwild1@gmail.com> |
---|---|
date | Wed, 10 Oct 2018 17:45:19 +0100 |
child | 9510:8ef46d09386a |
comparison
equal
deleted
inserted
replaced
9455:c62c983b8be3 | 9456:d54a0e129af8 |
---|---|
1 local promise_methods = {}; | |
2 local promise_mt = { __name = "promise", __index = promise_methods }; | |
3 | |
4 local function is_promise(o) | |
5 local mt = getmetatable(o); | |
6 return mt == promise_mt; | |
7 end | |
8 | |
9 local function next_pending(self, on_fulfilled, on_rejected) | |
10 table.insert(self._pending_on_fulfilled, on_fulfilled); | |
11 table.insert(self._pending_on_rejected, on_rejected); | |
12 end | |
13 | |
14 local function next_fulfilled(promise, on_fulfilled, on_rejected) -- luacheck: ignore 212/on_rejected | |
15 on_fulfilled(promise.value); | |
16 end | |
17 | |
18 local function next_rejected(promise, on_fulfilled, on_rejected) -- luacheck: ignore 212/on_fulfilled | |
19 on_rejected(promise.reason); | |
20 end | |
21 | |
22 local function promise_settle(promise, new_state, new_next, cbs, value) | |
23 if promise._state ~= "pending" then | |
24 return; | |
25 end | |
26 promise._state = new_state; | |
27 promise._next = new_next; | |
28 for _, cb in ipairs(cbs) do | |
29 cb(value); | |
30 end | |
31 return true; | |
32 end | |
33 | |
34 local function new_resolve_functions(p) | |
35 local resolved = false; | |
36 local function _resolve(v) | |
37 if resolved then return; end | |
38 resolved = true; | |
39 if is_promise(v) then | |
40 v:next(new_resolve_functions(p)); | |
41 elseif promise_settle(p, "fulfilled", next_fulfilled, p._pending_on_fulfilled, v) then | |
42 p.value = v; | |
43 end | |
44 | |
45 end | |
46 local function _reject(e) | |
47 if resolved then return; end | |
48 resolved = true; | |
49 if promise_settle(p, "rejected", next_rejected, p._pending_on_rejected, e) then | |
50 p.reason = e; | |
51 end | |
52 end | |
53 return _resolve, _reject; | |
54 end | |
55 | |
56 local function new(f) | |
57 local p = setmetatable({ _state = "pending", _next = next_pending, _pending_on_fulfilled = {}, _pending_on_rejected = {} }, promise_mt); | |
58 if f then | |
59 local resolve, reject = new_resolve_functions(p); | |
60 local ok, ret = pcall(f, resolve, reject); | |
61 if not ok and p._state == "pending" then | |
62 reject(ret); | |
63 end | |
64 end | |
65 return p; | |
66 end | |
67 | |
68 local function wrap_handler(f, resolve, reject) | |
69 return function (param) | |
70 local ok, ret = pcall(f, param); | |
71 if ok then | |
72 resolve(ret); | |
73 else | |
74 reject(ret); | |
75 end | |
76 end; | |
77 end | |
78 | |
79 function promise_methods:next(on_fulfilled, on_rejected) | |
80 return new(function (resolve, reject) | |
81 self:_next( | |
82 on_fulfilled and wrap_handler(on_fulfilled, resolve, reject) or nil, | |
83 on_rejected and wrap_handler(on_rejected, resolve, reject) or nil | |
84 ); | |
85 end); | |
86 end | |
87 | |
88 function promise_methods:catch(on_rejected) | |
89 return self:next(nil, on_rejected); | |
90 end | |
91 | |
92 local function all(promises) | |
93 return new(function (resolve, reject) | |
94 local count, total, results = 0, #promises, {}; | |
95 for i = 1, total do | |
96 promises[i]:next(function (v) | |
97 results[i] = v; | |
98 count = count + 1; | |
99 if count == total then | |
100 resolve(results); | |
101 end | |
102 end, reject); | |
103 end | |
104 end); | |
105 end | |
106 | |
107 local function race(promises) | |
108 return new(function (resolve, reject) | |
109 for i = 1, #promises do | |
110 promises[i]:next(resolve, reject); | |
111 end | |
112 end); | |
113 end | |
114 | |
115 local function resolve(v) | |
116 return new(function (_resolve) | |
117 _resolve(v); | |
118 end); | |
119 end | |
120 | |
121 local function reject(v) | |
122 return new(function (_reject) | |
123 _reject(v); | |
124 end); | |
125 end | |
126 | |
127 return { | |
128 new = new; | |
129 resolve = resolve; | |
130 reject = reject; | |
131 all = all; | |
132 race = race; | |
133 } |