@quenty/promise 10.10.1 → 10.10.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/package.json +6 -6
- package/src/Shared/Promise.lua +72 -54
- package/src/Shared/PromiseRetryUtils.lua +21 -2
- package/src/Shared/PromiseUtils.lua +28 -16
- package/src/Shared/Utility/PendingPromiseTracker.lua +17 -9
- package/src/Shared/Utility/PromiseInstanceUtils.lua +2 -1
- package/src/Shared/Utility/promiseChild.lua +7 -2
- package/src/Shared/Utility/promisePropertyValue.lua +1 -1
- package/src/Shared/Utility/promiseWait.lua +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,17 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [10.10.2](https://github.com/Quenty/NevermoreEngine/compare/@quenty/promise@10.10.1...@quenty/promise@10.10.2) (2025-04-05)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
|
|
11
|
+
* Add types to packages ([2374fb2](https://github.com/Quenty/NevermoreEngine/commit/2374fb2b043cfbe0e9b507b3316eec46a4e353a0))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
6
17
|
## [10.10.1](https://github.com/Quenty/NevermoreEngine/compare/@quenty/promise@10.10.0...@quenty/promise@10.10.1) (2025-03-21)
|
|
7
18
|
|
|
8
19
|
**Note:** Version bump only for package @quenty/promise
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quenty/promise",
|
|
3
|
-
"version": "10.10.
|
|
3
|
+
"version": "10.10.2",
|
|
4
4
|
"description": "Promise implementation for Roblox",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Roblox",
|
|
@@ -25,13 +25,13 @@
|
|
|
25
25
|
"Quenty"
|
|
26
26
|
],
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@quenty/deferred": "^2.2.
|
|
29
|
-
"@quenty/loader": "^10.8.
|
|
30
|
-
"@quenty/maid": "^3.4.
|
|
31
|
-
"@quenty/math": "^2.7.
|
|
28
|
+
"@quenty/deferred": "^2.2.1",
|
|
29
|
+
"@quenty/loader": "^10.8.1",
|
|
30
|
+
"@quenty/maid": "^3.4.1",
|
|
31
|
+
"@quenty/math": "^2.7.2"
|
|
32
32
|
},
|
|
33
33
|
"publishConfig": {
|
|
34
34
|
"access": "public"
|
|
35
35
|
},
|
|
36
|
-
"gitHead": "
|
|
36
|
+
"gitHead": "78c3ac0ab08dd18085b6e6e6e4f745e76ed99f68"
|
|
37
37
|
}
|
package/src/Shared/Promise.lua
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
--!nocheck
|
|
1
2
|
--[=[
|
|
2
3
|
Promises, but without error handling as this screws with stack traces, using Roblox signals
|
|
3
4
|
|
|
@@ -12,19 +13,34 @@ local HttpService = game:GetService("HttpService")
|
|
|
12
13
|
local ENABLE_TRACEBACK = false
|
|
13
14
|
local _emptyRejectedPromise = nil
|
|
14
15
|
local _emptyFulfilledPromise = nil
|
|
15
|
-
local EMPTY_PACKED_TUPLE = table.freeze({ n = 0
|
|
16
|
+
local EMPTY_PACKED_TUPLE = table.freeze({ n = 0 })
|
|
16
17
|
|
|
17
18
|
local Promise = {}
|
|
18
19
|
Promise.ClassName = "Promise"
|
|
19
20
|
Promise.__index = Promise
|
|
20
21
|
|
|
22
|
+
export type Resolve<T...> = (T...) -> ()
|
|
23
|
+
export type Reject = (...any) -> ()
|
|
24
|
+
export type ResolveReject<T...> = (Resolve<T...>, Reject) -> ()
|
|
25
|
+
|
|
26
|
+
export type Promise<T...> = typeof(setmetatable(
|
|
27
|
+
{} :: {
|
|
28
|
+
_fulfilled: any?,
|
|
29
|
+
_rejected: any?,
|
|
30
|
+
_unconsumedException: boolean,
|
|
31
|
+
_pendingExecuteList: { any }?,
|
|
32
|
+
_source: string,
|
|
33
|
+
},
|
|
34
|
+
Promise
|
|
35
|
+
))
|
|
36
|
+
|
|
21
37
|
--[=[
|
|
22
38
|
Determines whether a value is a promise or not.
|
|
23
39
|
|
|
24
40
|
@param value any
|
|
25
41
|
@return boolean
|
|
26
42
|
]=]
|
|
27
|
-
function Promise.isPromise(value)
|
|
43
|
+
function Promise.isPromise(value: any): boolean
|
|
28
44
|
return type(value) == "table" and value.ClassName == "Promise"
|
|
29
45
|
end
|
|
30
46
|
|
|
@@ -37,13 +53,13 @@ end
|
|
|
37
53
|
::
|
|
38
54
|
|
|
39
55
|
@param func (resolve: (...) -> (), reject: (...) -> ()) -> ()?
|
|
40
|
-
@return Promise<T
|
|
56
|
+
@return Promise<T...>
|
|
41
57
|
]=]
|
|
42
|
-
function Promise.new(func)
|
|
58
|
+
function Promise.new<T...>(func: ResolveReject<T...>?): Promise<T...>
|
|
43
59
|
local self = setmetatable({
|
|
44
|
-
_pendingExecuteList = {}
|
|
45
|
-
_unconsumedException = true
|
|
46
|
-
_source = ENABLE_TRACEBACK and debug.traceback("Promise.new()", 2) or ""
|
|
60
|
+
_pendingExecuteList = {},
|
|
61
|
+
_unconsumedException = true,
|
|
62
|
+
_source = ENABLE_TRACEBACK and debug.traceback("Promise.new()", 2) or "",
|
|
47
63
|
}, Promise)
|
|
48
64
|
|
|
49
65
|
if type(func) == "function" then
|
|
@@ -57,9 +73,9 @@ end
|
|
|
57
73
|
Initializes a new promise with the given function in a spawn wrapper.
|
|
58
74
|
|
|
59
75
|
@param func (resolve: (...) -> (), reject: (...) -> ()) -> ()?
|
|
60
|
-
@return Promise<T
|
|
76
|
+
@return Promise<T...>
|
|
61
77
|
]=]
|
|
62
|
-
function Promise.spawn(func)
|
|
78
|
+
function Promise.spawn<T...>(func: ResolveReject<T...>): Promise<T...>
|
|
63
79
|
local self = Promise.new()
|
|
64
80
|
|
|
65
81
|
task.spawn(func, self:_getResolveReject())
|
|
@@ -72,9 +88,9 @@ end
|
|
|
72
88
|
|
|
73
89
|
@param seconds number
|
|
74
90
|
@param func (resolve: (...) -> (), reject: (...) -> ()) -> ()?
|
|
75
|
-
@return Promise<T
|
|
91
|
+
@return Promise<T...>
|
|
76
92
|
]=]
|
|
77
|
-
function Promise.delay(seconds, func)
|
|
93
|
+
function Promise.delay<T...>(seconds: number, func: ResolveReject<T...>): Promise<T...>
|
|
78
94
|
assert(type(seconds) == "number", "Bad seconds")
|
|
79
95
|
assert(type(func) == "function", "Bad func")
|
|
80
96
|
|
|
@@ -89,9 +105,9 @@ end
|
|
|
89
105
|
Initializes a new promise with the given function in a deferred wrapper.
|
|
90
106
|
|
|
91
107
|
@param func (resolve: (...) -> (), reject: (...) -> ()) -> ()?
|
|
92
|
-
@return Promise<T
|
|
108
|
+
@return Promise<T...>
|
|
93
109
|
]=]
|
|
94
|
-
function Promise.defer(func)
|
|
110
|
+
function Promise.defer<T...>(func: ResolveReject<T...>): Promise<T...>
|
|
95
111
|
local self = Promise.new()
|
|
96
112
|
|
|
97
113
|
-- Just the function part of the resolve/reject protocol!
|
|
@@ -104,9 +120,9 @@ end
|
|
|
104
120
|
Returns a resolved promise with the following values
|
|
105
121
|
|
|
106
122
|
@param ... Values to resolve to
|
|
107
|
-
@return Promise<T
|
|
123
|
+
@return Promise<T...>
|
|
108
124
|
]=]
|
|
109
|
-
function Promise.resolved(...)
|
|
125
|
+
function Promise.resolved<T...>(...: T...): Promise<T...>
|
|
110
126
|
local n = select("#", ...)
|
|
111
127
|
if n == 0 then
|
|
112
128
|
-- Reuse promise here to save on calls to Promise.resolved()
|
|
@@ -129,9 +145,9 @@ end
|
|
|
129
145
|
Returns a rejected promise with the following values
|
|
130
146
|
|
|
131
147
|
@param ... Values to reject to
|
|
132
|
-
@return Promise<T
|
|
148
|
+
@return Promise<T...>
|
|
133
149
|
]=]
|
|
134
|
-
function Promise.rejected(...)
|
|
150
|
+
function Promise.rejected<T...>(...): Promise<()>
|
|
135
151
|
local n = select("#", ...)
|
|
136
152
|
if n == 0 then
|
|
137
153
|
-- Reuse promise here to save on calls to Promise.rejected()
|
|
@@ -148,7 +164,7 @@ end
|
|
|
148
164
|
|
|
149
165
|
@return bool -- True if pending, false otherwise
|
|
150
166
|
]=]
|
|
151
|
-
function Promise
|
|
167
|
+
function Promise.IsPending<T...>(self: Promise<T...>): boolean
|
|
152
168
|
return self._pendingExecuteList ~= nil
|
|
153
169
|
end
|
|
154
170
|
|
|
@@ -157,7 +173,7 @@ end
|
|
|
157
173
|
|
|
158
174
|
@return bool -- True if fulfilled
|
|
159
175
|
]=]
|
|
160
|
-
function Promise
|
|
176
|
+
function Promise.IsFulfilled<T...>(self: Promise<T...>): boolean
|
|
161
177
|
return self._fulfilled ~= nil
|
|
162
178
|
end
|
|
163
179
|
|
|
@@ -166,7 +182,7 @@ end
|
|
|
166
182
|
|
|
167
183
|
@return bool -- True if rejected
|
|
168
184
|
]=]
|
|
169
|
-
function Promise
|
|
185
|
+
function Promise.IsRejected<T...>(self: Promise<T...>): boolean
|
|
170
186
|
return self._rejected ~= nil
|
|
171
187
|
end
|
|
172
188
|
|
|
@@ -177,11 +193,11 @@ end
|
|
|
177
193
|
@yields
|
|
178
194
|
@return T
|
|
179
195
|
]=]
|
|
180
|
-
function Promise
|
|
196
|
+
function Promise.Wait<T...>(self: Promise<T...>): T...
|
|
181
197
|
if self._fulfilled then
|
|
182
198
|
return table.unpack(self._fulfilled, 1, self._fulfilled.n)
|
|
183
199
|
elseif self._rejected then
|
|
184
|
-
|
|
200
|
+
error(tostring(self._rejected[1]), 2)
|
|
185
201
|
else
|
|
186
202
|
local waitingCoroutine = coroutine.running()
|
|
187
203
|
|
|
@@ -194,14 +210,15 @@ function Promise:Wait()
|
|
|
194
210
|
coroutine.yield()
|
|
195
211
|
|
|
196
212
|
if self._rejected then
|
|
197
|
-
|
|
198
|
-
|
|
213
|
+
error(tostring(self._rejected[1]), 2)
|
|
214
|
+
elseif self._fulfilled then
|
|
199
215
|
return table.unpack(self._fulfilled, 1, self._fulfilled.n)
|
|
216
|
+
else
|
|
217
|
+
error("Bad state")
|
|
200
218
|
end
|
|
201
219
|
end
|
|
202
220
|
end
|
|
203
221
|
|
|
204
|
-
|
|
205
222
|
--[=[
|
|
206
223
|
Yields until the promise is complete, then returns a boolean indicating
|
|
207
224
|
the result, followed by the values from the promise.
|
|
@@ -209,7 +226,7 @@ end
|
|
|
209
226
|
@yields
|
|
210
227
|
@return boolean, T
|
|
211
228
|
]=]
|
|
212
|
-
function Promise
|
|
229
|
+
function Promise.Yield<T...>(self: Promise<T...>): (boolean, T...)
|
|
213
230
|
if self._fulfilled then
|
|
214
231
|
return true, table.unpack(self._fulfilled, 1, self._fulfilled.n)
|
|
215
232
|
elseif self._rejected then
|
|
@@ -235,13 +252,12 @@ function Promise:Yield()
|
|
|
235
252
|
end
|
|
236
253
|
end
|
|
237
254
|
|
|
238
|
-
|
|
239
255
|
--[=[
|
|
240
256
|
Promise resolution procedure, resolves the given values
|
|
241
257
|
|
|
242
258
|
@param ... T
|
|
243
259
|
]=]
|
|
244
|
-
function Promise:Resolve(...)
|
|
260
|
+
function Promise:Resolve<T...>(...: T...)
|
|
245
261
|
if not self._pendingExecuteList then
|
|
246
262
|
return
|
|
247
263
|
end
|
|
@@ -253,7 +269,8 @@ function Promise:Resolve(...)
|
|
|
253
269
|
self:Reject("TypeError: Resolved to self")
|
|
254
270
|
elseif Promise.isPromise(...) then
|
|
255
271
|
if len > 1 then
|
|
256
|
-
local message =
|
|
272
|
+
local message =
|
|
273
|
+
string.format("When resolving a promise, extra arguments are discarded! See:\n\n%s", self._source)
|
|
257
274
|
warn(message)
|
|
258
275
|
end
|
|
259
276
|
|
|
@@ -270,7 +287,6 @@ function Promise:Resolve(...)
|
|
|
270
287
|
self:_reject(table.pack(...))
|
|
271
288
|
end
|
|
272
289
|
end,
|
|
273
|
-
nil
|
|
274
290
|
}
|
|
275
291
|
elseif promise2._rejected then -- rejected
|
|
276
292
|
promise2._unconsumedException = false
|
|
@@ -282,7 +298,8 @@ function Promise:Resolve(...)
|
|
|
282
298
|
end
|
|
283
299
|
elseif type(...) == "function" then
|
|
284
300
|
if len > 1 then
|
|
285
|
-
local message =
|
|
301
|
+
local message =
|
|
302
|
+
string.format("When resolving a function, extra arguments are discarded! See:\n\n%s", self._source)
|
|
286
303
|
warn(message)
|
|
287
304
|
end
|
|
288
305
|
|
|
@@ -301,7 +318,7 @@ end
|
|
|
301
318
|
@param values { T } -- Params to fulfil with
|
|
302
319
|
@private
|
|
303
320
|
]]
|
|
304
|
-
function Promise
|
|
321
|
+
function Promise._fulfill<T...>(self: Promise<T...>, values)
|
|
305
322
|
if not self._pendingExecuteList then
|
|
306
323
|
return
|
|
307
324
|
end
|
|
@@ -310,7 +327,7 @@ function Promise:_fulfill(values)
|
|
|
310
327
|
|
|
311
328
|
local list = self._pendingExecuteList
|
|
312
329
|
self._pendingExecuteList = nil
|
|
313
|
-
for _, data in
|
|
330
|
+
for _, data in list do
|
|
314
331
|
self:_executeThen(unpack(data))
|
|
315
332
|
end
|
|
316
333
|
end
|
|
@@ -319,11 +336,11 @@ end
|
|
|
319
336
|
Rejects the promise with the values given
|
|
320
337
|
@param ... T -- Params to reject with
|
|
321
338
|
]=]
|
|
322
|
-
function Promise
|
|
339
|
+
function Promise.Reject<T...>(self: Promise<T...>, ...)
|
|
323
340
|
self:_reject(table.pack(...))
|
|
324
341
|
end
|
|
325
342
|
|
|
326
|
-
function Promise
|
|
343
|
+
function Promise._reject<T...>(self: Promise<T...>, values)
|
|
327
344
|
if not self._pendingExecuteList then
|
|
328
345
|
return
|
|
329
346
|
end
|
|
@@ -332,7 +349,7 @@ function Promise:_reject(values)
|
|
|
332
349
|
|
|
333
350
|
local list = self._pendingExecuteList
|
|
334
351
|
self._pendingExecuteList = nil
|
|
335
|
-
for _, data in
|
|
352
|
+
for _, data in list do
|
|
336
353
|
self:_executeThen(unpack(data))
|
|
337
354
|
end
|
|
338
355
|
|
|
@@ -342,10 +359,12 @@ function Promise:_reject(values)
|
|
|
342
359
|
-- Yield to end of frame, giving control back to Roblox.
|
|
343
360
|
-- This is the equivalent of giving something back to a task manager.
|
|
344
361
|
if self._unconsumedException then
|
|
345
|
-
local errOutput = self:_toHumanReadable(
|
|
362
|
+
local errOutput = self:_toHumanReadable(values[1])
|
|
346
363
|
|
|
347
364
|
if ENABLE_TRACEBACK then
|
|
348
|
-
warn(
|
|
365
|
+
warn(
|
|
366
|
+
string.format("[Promise] - Uncaught exception in promise\n\n%q\n\n%s", errOutput, self._source)
|
|
367
|
+
)
|
|
349
368
|
else
|
|
350
369
|
warn(string.format("[Promise] - Uncaught exception in promise: %q", errOutput))
|
|
351
370
|
end
|
|
@@ -354,7 +373,7 @@ function Promise:_reject(values)
|
|
|
354
373
|
end
|
|
355
374
|
end
|
|
356
375
|
|
|
357
|
-
function Promise
|
|
376
|
+
function Promise._toHumanReadable<T...>(_self: Promise<T...>, data: any): string
|
|
358
377
|
if type(data) == "table" then
|
|
359
378
|
local errOutput
|
|
360
379
|
local ok = pcall(function()
|
|
@@ -387,9 +406,9 @@ end
|
|
|
387
406
|
|
|
388
407
|
@param onFulfilled function -- Called if/when fulfilled with parameters
|
|
389
408
|
@param onRejected function -- Called if/when rejected with parameters
|
|
390
|
-
@return Promise<T
|
|
409
|
+
@return Promise<T...>
|
|
391
410
|
]=]
|
|
392
|
-
function Promise
|
|
411
|
+
function Promise.Then<T...>(self: Promise<T...>, onFulfilled, onRejected)
|
|
393
412
|
if type(onRejected) == "function" then
|
|
394
413
|
self._unconsumedException = false
|
|
395
414
|
end
|
|
@@ -411,9 +430,9 @@ end
|
|
|
411
430
|
|
|
412
431
|
@param onFulfilled function
|
|
413
432
|
@param onRejected function
|
|
414
|
-
@return Promise<T
|
|
433
|
+
@return Promise<T...> -- Returns self
|
|
415
434
|
]=]
|
|
416
|
-
function Promise
|
|
435
|
+
function Promise.Tap<T...>(self: Promise<T...>, onFulfilled, onRejected)
|
|
417
436
|
-- Run immediately like then, but we return something safer!
|
|
418
437
|
local result = self:Then(onFulfilled, onRejected)
|
|
419
438
|
if result == self then
|
|
@@ -443,9 +462,9 @@ end
|
|
|
443
462
|
Executes upon pending stop
|
|
444
463
|
|
|
445
464
|
@param func function
|
|
446
|
-
@return Promise<T
|
|
465
|
+
@return Promise<T...>
|
|
447
466
|
]=]
|
|
448
|
-
function Promise
|
|
467
|
+
function Promise.Finally<T...>(self: Promise<T...>, func)
|
|
449
468
|
return self:Then(func, func)
|
|
450
469
|
end
|
|
451
470
|
|
|
@@ -453,17 +472,16 @@ end
|
|
|
453
472
|
Catch errors from the promise
|
|
454
473
|
|
|
455
474
|
@param onRejected function
|
|
456
|
-
@return Promise<T
|
|
475
|
+
@return Promise<T...>
|
|
457
476
|
]=]
|
|
458
|
-
function Promise
|
|
477
|
+
function Promise.Catch<T...>(self: Promise<T...>, onRejected)
|
|
459
478
|
return self:Then(nil, onRejected)
|
|
460
479
|
end
|
|
461
480
|
|
|
462
|
-
|
|
463
481
|
--[=[
|
|
464
482
|
Rejects the current promise. Utility left for Maid task
|
|
465
483
|
]=]
|
|
466
|
-
function Promise
|
|
484
|
+
function Promise.Destroy<T...>(self: Promise<T...>)
|
|
467
485
|
self:_reject(EMPTY_PACKED_TUPLE)
|
|
468
486
|
end
|
|
469
487
|
|
|
@@ -477,7 +495,7 @@ end
|
|
|
477
495
|
@return boolean -- true if resolved, false otherwise.
|
|
478
496
|
@return any
|
|
479
497
|
]=]
|
|
480
|
-
function Promise
|
|
498
|
+
function Promise.GetResults<T...>(self: Promise<T...>): (boolean, T...)
|
|
481
499
|
if self._rejected then
|
|
482
500
|
return false, table.unpack(self._rejected, 1, self._rejected.n)
|
|
483
501
|
elseif self._fulfilled then
|
|
@@ -487,7 +505,7 @@ function Promise:GetResults()
|
|
|
487
505
|
end
|
|
488
506
|
end
|
|
489
507
|
|
|
490
|
-
function Promise
|
|
508
|
+
function Promise._getResolveReject<T...>(self: Promise<T...>): (Resolve<T...>, Reject)
|
|
491
509
|
return function(...)
|
|
492
510
|
self:Resolve(...)
|
|
493
511
|
end, function(...)
|
|
@@ -500,10 +518,10 @@ end
|
|
|
500
518
|
|
|
501
519
|
@param onFulfilled function?
|
|
502
520
|
@param onRejected function?
|
|
503
|
-
@param promise2 Promise<T
|
|
521
|
+
@param promise2 Promise<T...>? -- May be nil. If it is, then we have the option to return self
|
|
504
522
|
@return Promise
|
|
505
523
|
]=]
|
|
506
|
-
function Promise
|
|
524
|
+
function Promise._executeThen<T...>(self: Promise<T...>, onFulfilled, onRejected, promise2)
|
|
507
525
|
if self._fulfilled then
|
|
508
526
|
if type(onFulfilled) == "function" then
|
|
509
527
|
-- If either onFulfilled or onRejected returns a value x, run
|
|
@@ -579,4 +597,4 @@ _emptyFulfilledPromise:_fulfill(EMPTY_PACKED_TUPLE)
|
|
|
579
597
|
_emptyRejectedPromise = Promise.new()
|
|
580
598
|
_emptyRejectedPromise:_reject(EMPTY_PACKED_TUPLE)
|
|
581
599
|
|
|
582
|
-
return Promise
|
|
600
|
+
return Promise
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
--!strict
|
|
1
2
|
--[=[
|
|
2
3
|
@class PromiseRetryUtils
|
|
3
4
|
]=]
|
|
@@ -9,7 +10,21 @@ local Math = require("Math")
|
|
|
9
10
|
|
|
10
11
|
local PromiseRetryUtils = {}
|
|
11
12
|
|
|
12
|
-
|
|
13
|
+
export type RetryOptions = {
|
|
14
|
+
initialWaitTime: number,
|
|
15
|
+
maxAttempts: number,
|
|
16
|
+
printWarning: boolean,
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
--[=[
|
|
20
|
+
Returns a promise that will retry the given callback until it succeeds or the max attempts
|
|
21
|
+
is reached.
|
|
22
|
+
|
|
23
|
+
@param callback function -- Callback that returns a promise
|
|
24
|
+
@param options RetryOptions -- Options for retrying
|
|
25
|
+
@return Promise<T>
|
|
26
|
+
]=]
|
|
27
|
+
function PromiseRetryUtils.retry<T...>(callback: () -> Promise.Promise<T...>, options: RetryOptions): Promise.Promise<T...>
|
|
13
28
|
assert(type(options.initialWaitTime) == "number", "Bad initialWaitTime")
|
|
14
29
|
assert(type(options.maxAttempts) == "number", "Bad maxAttempts")
|
|
15
30
|
assert(type(options.printWarning) == "boolean", "Bad printWarning")
|
|
@@ -39,7 +54,11 @@ function PromiseRetryUtils.retry(callback, options)
|
|
|
39
54
|
end
|
|
40
55
|
|
|
41
56
|
isLoopResolved = true
|
|
42
|
-
local errorMessage = string.format(
|
|
57
|
+
local errorMessage = string.format(
|
|
58
|
+
"Attempted request %d times before failing with error %s",
|
|
59
|
+
options.maxAttempts,
|
|
60
|
+
tostring(lastResults[2])
|
|
61
|
+
)
|
|
43
62
|
promise:Reject(errorMessage, table.unpack(lastResults, 3, lastResults.n))
|
|
44
63
|
end)
|
|
45
64
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
--!strict
|
|
1
2
|
--[=[
|
|
2
3
|
Utility methods for promise
|
|
3
4
|
@class PromiseUtils
|
|
@@ -6,6 +7,7 @@
|
|
|
6
7
|
local require = require(script.Parent.loader).load(script)
|
|
7
8
|
|
|
8
9
|
local Promise = require("Promise")
|
|
10
|
+
local _Signal = require("Signal")
|
|
9
11
|
|
|
10
12
|
local PromiseUtils = {}
|
|
11
13
|
|
|
@@ -14,7 +16,7 @@ local PromiseUtils = {}
|
|
|
14
16
|
@param promises { Promise<T> }
|
|
15
17
|
@return Promise<T> -- Promise that resolves with first result
|
|
16
18
|
]=]
|
|
17
|
-
function PromiseUtils.any(promises)
|
|
19
|
+
function PromiseUtils.any<T...>(promises: { Promise.Promise<T...> }): Promise.Promise<T...>
|
|
18
20
|
local returnPromise = Promise.new()
|
|
19
21
|
|
|
20
22
|
local function resolve(...)
|
|
@@ -25,7 +27,7 @@ function PromiseUtils.any(promises)
|
|
|
25
27
|
returnPromise:Reject(...)
|
|
26
28
|
end
|
|
27
29
|
|
|
28
|
-
for _, promise in
|
|
30
|
+
for _, promise in promises do
|
|
29
31
|
promise:Then(resolve, reject)
|
|
30
32
|
end
|
|
31
33
|
|
|
@@ -38,7 +40,7 @@ end
|
|
|
38
40
|
@param seconds number
|
|
39
41
|
@return Promise
|
|
40
42
|
]=]
|
|
41
|
-
function PromiseUtils.delayed(seconds)
|
|
43
|
+
function PromiseUtils.delayed(seconds: number): Promise.Promise<()>
|
|
42
44
|
assert(type(seconds) == "number", "Bad seconds")
|
|
43
45
|
|
|
44
46
|
return Promise.delay(seconds, function(resolve, _reject)
|
|
@@ -57,7 +59,7 @@ end
|
|
|
57
59
|
@param promises { Promise<T> }
|
|
58
60
|
@return Promise<T>
|
|
59
61
|
]=]
|
|
60
|
-
function PromiseUtils.all(promises)
|
|
62
|
+
function PromiseUtils.all<T>(promises: { Promise.Promise<T> }): Promise.Promise<T>
|
|
61
63
|
if #promises == 0 then
|
|
62
64
|
return Promise.resolved()
|
|
63
65
|
elseif #promises == 1 then
|
|
@@ -81,14 +83,20 @@ function PromiseUtils.all(promises)
|
|
|
81
83
|
end
|
|
82
84
|
end
|
|
83
85
|
|
|
84
|
-
for index, promise in
|
|
86
|
+
for index, promise in promises do
|
|
85
87
|
promise:Then(syncronize(index, true), syncronize(index, false))
|
|
86
88
|
end
|
|
87
89
|
|
|
88
90
|
return returnPromise
|
|
89
91
|
end
|
|
90
92
|
|
|
91
|
-
|
|
93
|
+
--[=[
|
|
94
|
+
Keeps on trying promises until one of them succeeds, or reports
|
|
95
|
+
the last failure.
|
|
96
|
+
|
|
97
|
+
@param promises { Promise<T> }
|
|
98
|
+
]=]
|
|
99
|
+
function PromiseUtils.firstSuccessOrLastFailure<T...>(promises: { Promise.Promise<T...> }): Promise.Promise<T...>
|
|
92
100
|
if #promises == 0 then
|
|
93
101
|
return Promise.resolved()
|
|
94
102
|
elseif #promises == 1 then
|
|
@@ -109,10 +117,12 @@ function PromiseUtils.firstSuccessOrLastFailure(promises)
|
|
|
109
117
|
if remainingCount == 0 then
|
|
110
118
|
return returnPromise:Reject(...)
|
|
111
119
|
end
|
|
120
|
+
|
|
121
|
+
return
|
|
112
122
|
end
|
|
113
123
|
end
|
|
114
124
|
|
|
115
|
-
for _, promise in
|
|
125
|
+
for _, promise in promises do
|
|
116
126
|
promise:Then(syncronize(true), syncronize(false))
|
|
117
127
|
end
|
|
118
128
|
|
|
@@ -125,13 +135,13 @@ end
|
|
|
125
135
|
@param stateTable any
|
|
126
136
|
@return Promise<any>
|
|
127
137
|
]=]
|
|
128
|
-
function PromiseUtils.combine(stateTable)
|
|
138
|
+
function PromiseUtils.combine(stateTable: any): Promise.Promise<any>
|
|
129
139
|
assert(type(stateTable) == "table", "Bad stateTable")
|
|
130
140
|
|
|
131
141
|
local remainingCount = 0
|
|
132
142
|
local results = {}
|
|
133
143
|
|
|
134
|
-
for key, value in
|
|
144
|
+
for key, value in stateTable do
|
|
135
145
|
if Promise.isPromise(value) then
|
|
136
146
|
remainingCount = remainingCount + 1
|
|
137
147
|
else
|
|
@@ -159,7 +169,7 @@ function PromiseUtils.combine(stateTable)
|
|
|
159
169
|
end
|
|
160
170
|
end
|
|
161
171
|
|
|
162
|
-
for key, value in
|
|
172
|
+
for key, value in stateTable do
|
|
163
173
|
if Promise.isPromise(value) then
|
|
164
174
|
value:Then(syncronize(key, true), syncronize(key, false))
|
|
165
175
|
end
|
|
@@ -175,7 +185,7 @@ end
|
|
|
175
185
|
@param promise Promise<T>
|
|
176
186
|
@return Promise<T>
|
|
177
187
|
]=]
|
|
178
|
-
function PromiseUtils.invert(promise)
|
|
188
|
+
function PromiseUtils.invert<T...>(promise: Promise.Promise<T...>): Promise.Promise<T...>
|
|
179
189
|
if promise:IsPending() then
|
|
180
190
|
return promise:Then(function(...)
|
|
181
191
|
return Promise.rejected(...)
|
|
@@ -183,7 +193,7 @@ function PromiseUtils.invert(promise)
|
|
|
183
193
|
return Promise.resolved(...)
|
|
184
194
|
end)
|
|
185
195
|
else
|
|
186
|
-
local results = {promise:GetResults()}
|
|
196
|
+
local results = { promise:GetResults() }
|
|
187
197
|
if results[1] then
|
|
188
198
|
return Promise.rejected(unpack(results, 2))
|
|
189
199
|
else
|
|
@@ -198,12 +208,14 @@ end
|
|
|
198
208
|
@param signal Signal<T>
|
|
199
209
|
@return Promise<T>
|
|
200
210
|
]=]
|
|
201
|
-
function PromiseUtils.fromSignal(signal)
|
|
211
|
+
function PromiseUtils.fromSignal<T...>(signal: _Signal.Signal<T...>): Promise.Promise<T...>
|
|
202
212
|
local promise = Promise.new()
|
|
203
|
-
local conn
|
|
213
|
+
local conn: _Signal.Connection<T...>?
|
|
204
214
|
|
|
205
215
|
promise:Finally(function()
|
|
206
|
-
conn
|
|
216
|
+
if conn then
|
|
217
|
+
conn:Disconnect()
|
|
218
|
+
end
|
|
207
219
|
conn = nil
|
|
208
220
|
end)
|
|
209
221
|
|
|
@@ -222,7 +234,7 @@ end
|
|
|
222
234
|
@param fromPromise Promise<T>
|
|
223
235
|
@return Promise<T>
|
|
224
236
|
]=]
|
|
225
|
-
function PromiseUtils.timeout(timeoutTime, fromPromise)
|
|
237
|
+
function PromiseUtils.timeout<T...>(timeoutTime: number, fromPromise: Promise.Promise<T...>): Promise.Promise<T...>
|
|
226
238
|
assert(type(timeoutTime) == "number", "Bad timeoutTime")
|
|
227
239
|
assert(fromPromise, "Bad fromPromise")
|
|
228
240
|
|
|
@@ -1,18 +1,30 @@
|
|
|
1
|
+
--!strict
|
|
1
2
|
--[=[
|
|
2
3
|
Tracks pending promises
|
|
3
4
|
@class PendingPromiseTracker
|
|
4
5
|
]=]
|
|
5
6
|
|
|
7
|
+
local require = require(script.Parent.loader).load(script)
|
|
8
|
+
|
|
9
|
+
local _Promise = require("Promise")
|
|
10
|
+
|
|
6
11
|
local PendingPromiseTracker = {}
|
|
7
12
|
PendingPromiseTracker.ClassName = "PendingPromiseTracker"
|
|
8
13
|
PendingPromiseTracker.__index = PendingPromiseTracker
|
|
9
14
|
|
|
15
|
+
export type PendingPromiseTracker<T...> = typeof(setmetatable(
|
|
16
|
+
{} :: {
|
|
17
|
+
_pendingPromises: { [_Promise.Promise<T...>]: true },
|
|
18
|
+
},
|
|
19
|
+
PendingPromiseTracker
|
|
20
|
+
))
|
|
21
|
+
|
|
10
22
|
--[=[
|
|
11
23
|
Returns a new pending promise tracker
|
|
12
24
|
|
|
13
25
|
@return PendingPromiseTracker<T>
|
|
14
26
|
]=]
|
|
15
|
-
function PendingPromiseTracker.new()
|
|
27
|
+
function PendingPromiseTracker.new<T...>(): PendingPromiseTracker<T...>
|
|
16
28
|
local self = setmetatable({}, PendingPromiseTracker)
|
|
17
29
|
|
|
18
30
|
self._pendingPromises = {}
|
|
@@ -22,10 +34,8 @@ end
|
|
|
22
34
|
|
|
23
35
|
--[=[
|
|
24
36
|
Adds a new promise to the tracker. If it's not pending it will not add.
|
|
25
|
-
|
|
26
|
-
@param promise Promise<T>
|
|
27
37
|
]=]
|
|
28
|
-
function PendingPromiseTracker
|
|
38
|
+
function PendingPromiseTracker.Add<T...>(self: PendingPromiseTracker<T...>, promise: _Promise.Promise<T...>)
|
|
29
39
|
if promise:IsPending() then
|
|
30
40
|
self._pendingPromises[promise] = true
|
|
31
41
|
promise:Finally(function()
|
|
@@ -36,12 +46,10 @@ end
|
|
|
36
46
|
|
|
37
47
|
--[=[
|
|
38
48
|
Gets all of the promises that are pending
|
|
39
|
-
|
|
40
|
-
@return { Promise<T> }
|
|
41
49
|
]=]
|
|
42
|
-
function PendingPromiseTracker
|
|
43
|
-
local promises = {}
|
|
44
|
-
for promise, _ in
|
|
50
|
+
function PendingPromiseTracker.GetAll<T...>(self: PendingPromiseTracker<T...>): { _Promise.Promise<T...> }
|
|
51
|
+
local promises: { _Promise.Promise<T...> } = {}
|
|
52
|
+
for promise: any, _ in self._pendingPromises do
|
|
45
53
|
table.insert(promises, promise)
|
|
46
54
|
end
|
|
47
55
|
return promises
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
--!strict
|
|
1
2
|
--[=[
|
|
2
3
|
@class PromiseInstanceUtils
|
|
3
4
|
]=]
|
|
@@ -15,7 +16,7 @@ local PromiseInstanceUtils = {}
|
|
|
15
16
|
@param instance Instance
|
|
16
17
|
@return Promise
|
|
17
18
|
]=]
|
|
18
|
-
function PromiseInstanceUtils.promiseRemoved(instance)
|
|
19
|
+
function PromiseInstanceUtils.promiseRemoved(instance: Instance): Promise.Promise<()>
|
|
19
20
|
assert(instance:IsDescendantOf(game))
|
|
20
21
|
|
|
21
22
|
local maid = Maid.new()
|
|
@@ -17,14 +17,19 @@ local Promise = require("Promise")
|
|
|
17
17
|
@return Promise<Instance>
|
|
18
18
|
@within promiseChild
|
|
19
19
|
]=]
|
|
20
|
-
return function(parent, name, timeOut)
|
|
20
|
+
return function(parent: Instance, name: string, timeOut: number?): Promise.Promise<Instance>
|
|
21
21
|
local result = parent:FindFirstChild(name)
|
|
22
22
|
if result then
|
|
23
23
|
return Promise.resolved(result)
|
|
24
24
|
end
|
|
25
25
|
|
|
26
26
|
return Promise.spawn(function(resolve, reject)
|
|
27
|
-
local child
|
|
27
|
+
local child: Instance?
|
|
28
|
+
if timeOut then
|
|
29
|
+
child = parent:WaitForChild(name, timeOut)
|
|
30
|
+
else
|
|
31
|
+
child = parent:WaitForChild(name)
|
|
32
|
+
end
|
|
28
33
|
|
|
29
34
|
if child then
|
|
30
35
|
resolve(child)
|
|
@@ -20,7 +20,7 @@ local Promise = require("Promise")
|
|
|
20
20
|
@return Promise<Instance>
|
|
21
21
|
@within promisePropertyValue
|
|
22
22
|
]=]
|
|
23
|
-
return function(instance, propertyName)
|
|
23
|
+
return function(instance: Instance, propertyName: string)
|
|
24
24
|
assert(typeof(instance) == "Instance", "Bad instance")
|
|
25
25
|
assert(type(propertyName) == "string", "Bad propertyName")
|
|
26
26
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
--!strict
|
|
1
2
|
--[=[
|
|
2
3
|
Wraps the task.delay() API in a promise
|
|
3
4
|
|
|
@@ -8,7 +9,7 @@ local require = require(script.Parent.loader).load(script)
|
|
|
8
9
|
|
|
9
10
|
local Promise = require("Promise")
|
|
10
11
|
|
|
11
|
-
return function(time)
|
|
12
|
+
return function(time: number): Promise.Promise<()>
|
|
12
13
|
return Promise.new(function(resolve, _)
|
|
13
14
|
task.delay(time, function()
|
|
14
15
|
resolve()
|