-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.es5.js
159 lines (131 loc) · 4.71 KB
/
index.es5.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.ensureDelay = ensureDelay;
exports.time = time;
exports.timedAsync = timedAsync;
exports.DelayedPromise = exports.sleep = void 0;
const FAST_LOAD_TIME = 500; // miliseconds
const SLOW_LOAD_TIME = 1500; // miliseconds
const clamp = (num, min, max) => Math.min(Math.max(num, min), max);
const promiseOrCall = promiseOrFunc => {
return typeof promiseOrFunc === 'function' ? promiseOrFunc() : promiseOrFunc;
};
const sleep = time => new Promise(resolve => setTimeout(resolve, time));
/**
* A promise that is only resolved after a minimum amount of time has passed.
* Can also attach slow and fast callbacks.
*/
exports.sleep = sleep;
class DelayedPromise extends Promise {
minimumDelay = FAST_LOAD_TIME;
slowCallbackTimeouts = [];
fastCallbacks = [];
resolvedCallbacks = [];
/**
* @param promiseOrFunc a promise to be awaited, or a function returning a promise.
* @param minimumDelay minimum amount of time (in ms) to have passed before promise is returned (default: 500).
*/
constructor(promiseOrFunc, minimumDelay = FAST_LOAD_TIME) {
super((resolve, reject) => {
setTimeout(() => {
// nextTick because `this` isn't available yet
this.execute(promiseOrFunc).then(resolve).catch(reject);
});
});
this.startedLoading = +new Date();
this.minimumDelay = minimumDelay;
}
async execute(promiseOrFunc) {
try {
return await promiseOrCall(promiseOrFunc);
} finally {
const loadDuration = +new Date() - this.startedLoading;
const extraWaitTime = clamp(this.minimumDelay - loadDuration, 0, this.minimumDelay);
if (extraWaitTime > 0) {
this.executeCallbacks(this.fastCallbacks, loadDuration);
}
await sleep(extraWaitTime);
this.clearSlowCallbacks();
}
}
static get [Symbol.species]() {
return Promise;
}
get [Symbol.toStringTag]() {
return 'DelayedPromise';
}
executeCallbacks(callbacks, time) {
for (const callback of callbacks) {
callback(time);
}
}
/**
* Adds callback to be called in case original promise settled faster than the minimum delay.
* Can be chained.
* @param callback
*/
onFast(callback) {
this.fastCallbacks.push(callback);
return this;
}
/**
* Adds callback to be called after time passed.
* Callback gets cleared and is not executed if promise resolves before that.
* This can be used to display text such as "Still loading, please wait a bit more."
* Can be chained.
* @param time time (in ms) after which this callback is executed
* @param callback
*/
after(time, callback) {
const timeout = setTimeout(() => {
callback(time);
}, time);
this.slowCallbackTimeouts.push(timeout);
return this;
}
clearSlowCallbacks() {
for (const timeout of this.slowCallbackTimeouts) {
clearTimeout(timeout);
}
}
}
/**
* Factory to create a DelayedPromise.
* @param promiseOrFunc a promise to be awaited, or a function returning a promise.
* @param minimumDelay minimum amount of time (in ms) to have passed before promise is returned (default: 500).
*/
exports.DelayedPromise = DelayedPromise;
function ensureDelay(promiseOrFunc, minimumDelay = FAST_LOAD_TIME) {
return new DelayedPromise(promiseOrFunc, minimumDelay);
}
/**
* Annotate promise result with duration.
* @param promiseOrFunc a promise to be awaited, or a function returning a promise.
*/
async function time(promiseOrFunc) {
const startedLoading = +new Date();
const result = await promiseOrCall(promiseOrFunc);
const time = +new Date() - startedLoading;
return [result, time];
}
/**
* Decorator to add "slow" and "fast" timing hooks to any async operation.
* This returns the return value of the main function and also lets exceptions go through.
* This is the legacy version of ensureDelay supported for backwards compatability.
*
* @param {function|Promise} promiseOrFunc execution function to be timed, or promise to be awaited
* @param {object} options
* @param {function} options.slow function to be called when operation is slow
* @param {number?} options.slowTime time after which the operation is considered slow. Default: 1500
* @param {function} options.fast function to be called when operation is fast
* @param {number?} options.fastTime time until which the operation is considered fast. Default: 500
* @return {any} return value of main function
*/
function timedAsync(promiseOrFunc, options = {}) {
const promise = new DelayedPromise(promiseOrFunc, options.fastTime || FAST_LOAD_TIME);
if (options.fast) promise.onFast(options.fast);
if (options.slow) promise.after(options.slowTime || SLOW_LOAD_TIME, options.slow);
return promise;
}