happy-dom 12.8.1 → 12.9.0
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.
Potentially problematic release.
This version of happy-dom might be problematic. Click here for more details.
- package/cjs/async-task-manager/AsyncTaskManager.cjs +75 -69
- package/cjs/async-task-manager/AsyncTaskManager.cjs.map +1 -1
- package/cjs/async-task-manager/AsyncTaskManager.d.ts +20 -11
- package/cjs/async-task-manager/AsyncTaskManager.d.ts.map +1 -1
- package/cjs/fetch/Fetch.cjs +2 -2
- package/cjs/fetch/Fetch.cjs.map +1 -1
- package/cjs/nodes/document/DocumentReadyStateManager.cjs +9 -9
- package/cjs/nodes/document/DocumentReadyStateManager.cjs.map +1 -1
- package/cjs/nodes/document/DocumentReadyStateManager.d.ts +1 -1
- package/cjs/nodes/document/DocumentReadyStateManager.d.ts.map +1 -1
- package/cjs/version.cjs +1 -1
- package/cjs/window/IWindow.d.ts +4 -4
- package/cjs/window/IWindow.d.ts.map +1 -1
- package/cjs/window/Window.cjs +17 -6
- package/cjs/window/Window.cjs.map +1 -1
- package/cjs/window/Window.d.ts +4 -4
- package/cjs/window/Window.d.ts.map +1 -1
- package/lib/async-task-manager/AsyncTaskManager.d.ts +20 -11
- package/lib/async-task-manager/AsyncTaskManager.d.ts.map +1 -1
- package/lib/async-task-manager/AsyncTaskManager.js +75 -69
- package/lib/async-task-manager/AsyncTaskManager.js.map +1 -1
- package/lib/fetch/Fetch.js +2 -2
- package/lib/fetch/Fetch.js.map +1 -1
- package/lib/nodes/document/DocumentReadyStateManager.d.ts +1 -1
- package/lib/nodes/document/DocumentReadyStateManager.d.ts.map +1 -1
- package/lib/nodes/document/DocumentReadyStateManager.js +9 -9
- package/lib/nodes/document/DocumentReadyStateManager.js.map +1 -1
- package/lib/version.js +1 -1
- package/lib/window/IWindow.d.ts +4 -4
- package/lib/window/IWindow.d.ts.map +1 -1
- package/lib/window/Window.d.ts +4 -4
- package/lib/window/Window.d.ts.map +1 -1
- package/lib/window/Window.js +17 -6
- package/lib/window/Window.js.map +1 -1
- package/package.json +1 -1
- package/src/async-task-manager/AsyncTaskManager.ts +85 -72
- package/src/fetch/Fetch.ts +2 -2
- package/src/nodes/document/DocumentReadyStateManager.ts +9 -9
- package/src/window/IWindow.ts +4 -4
- package/src/window/Window.ts +18 -9
@@ -4,30 +4,55 @@
|
|
4
4
|
export default class AsyncTaskManager {
|
5
5
|
private static taskID = 0;
|
6
6
|
private runningTasks: { [k: string]: () => void } = {};
|
7
|
+
private runningTaskCount = 0;
|
7
8
|
private runningTimers: NodeJS.Timeout[] = [];
|
8
|
-
private
|
9
|
-
private
|
9
|
+
private runningImmediates: NodeJS.Immediate[] = [];
|
10
|
+
private whenCompleteImmediate: NodeJS.Immediate | null = null;
|
11
|
+
private whenCompleteResolvers: Array<() => void> = [];
|
10
12
|
|
11
13
|
/**
|
12
|
-
* Returns a promise that is
|
13
|
-
* This method is not part of the HTML standard.
|
14
|
+
* Returns a promise that is resolved when async tasks are complete.
|
14
15
|
*
|
15
16
|
* @returns Promise.
|
16
17
|
*/
|
17
18
|
public whenComplete(): Promise<void> {
|
18
19
|
return new Promise((resolve) => {
|
19
|
-
this.
|
20
|
-
this.endTask(
|
20
|
+
this.whenCompleteResolvers.push(resolve);
|
21
|
+
this.endTask(this.startTask());
|
21
22
|
});
|
22
23
|
}
|
23
24
|
|
24
25
|
/**
|
25
|
-
*
|
26
|
-
*
|
27
|
-
* @param [error] Error.
|
26
|
+
* Cancels all tasks.
|
28
27
|
*/
|
29
28
|
public cancelAll(): void {
|
30
|
-
this.
|
29
|
+
const runningTimers = this.runningTimers;
|
30
|
+
const runningImmediates = this.runningImmediates;
|
31
|
+
const runningTasks = this.runningTasks;
|
32
|
+
|
33
|
+
this.runningTasks = {};
|
34
|
+
this.runningTaskCount = 0;
|
35
|
+
this.runningImmediates = [];
|
36
|
+
this.runningTimers = [];
|
37
|
+
|
38
|
+
if (this.whenCompleteImmediate) {
|
39
|
+
global.clearImmediate(this.whenCompleteImmediate);
|
40
|
+
this.whenCompleteImmediate = null;
|
41
|
+
}
|
42
|
+
|
43
|
+
for (const immediate of runningImmediates) {
|
44
|
+
global.clearImmediate(immediate);
|
45
|
+
}
|
46
|
+
|
47
|
+
for (const timer of runningTimers) {
|
48
|
+
global.clearTimeout(timer);
|
49
|
+
}
|
50
|
+
|
51
|
+
for (const key of Object.keys(runningTasks)) {
|
52
|
+
runningTasks[key]();
|
53
|
+
}
|
54
|
+
|
55
|
+
this.resolveWhenComplete();
|
31
56
|
}
|
32
57
|
|
33
58
|
/**
|
@@ -37,10 +62,6 @@ export default class AsyncTaskManager {
|
|
37
62
|
*/
|
38
63
|
public startTimer(timerID: NodeJS.Timeout): void {
|
39
64
|
this.runningTimers.push(timerID);
|
40
|
-
if (this.callbackTimeout) {
|
41
|
-
global.clearTimeout(this.callbackTimeout);
|
42
|
-
this.callbackTimeout = null;
|
43
|
-
}
|
44
65
|
}
|
45
66
|
|
46
67
|
/**
|
@@ -52,13 +73,33 @@ export default class AsyncTaskManager {
|
|
52
73
|
const index = this.runningTimers.indexOf(timerID);
|
53
74
|
if (index !== -1) {
|
54
75
|
this.runningTimers.splice(index, 1);
|
76
|
+
if (!this.runningTaskCount && !this.runningTimers.length && !this.runningImmediates.length) {
|
77
|
+
this.resolveWhenComplete();
|
78
|
+
}
|
55
79
|
}
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
80
|
+
}
|
81
|
+
|
82
|
+
/**
|
83
|
+
* Starts an immediate.
|
84
|
+
*
|
85
|
+
* @param immediateID Immediate ID.
|
86
|
+
*/
|
87
|
+
public startImmediate(immediateID: NodeJS.Immediate): void {
|
88
|
+
this.runningImmediates.push(immediateID);
|
89
|
+
}
|
90
|
+
|
91
|
+
/**
|
92
|
+
* Ends an immediate.
|
93
|
+
*
|
94
|
+
* @param immediateID Immediate ID.
|
95
|
+
*/
|
96
|
+
public endImmediate(immediateID: NodeJS.Immediate): void {
|
97
|
+
const index = this.runningImmediates.indexOf(immediateID);
|
98
|
+
if (index !== -1) {
|
99
|
+
this.runningImmediates.splice(index, 1);
|
100
|
+
if (!this.runningTaskCount && !this.runningTimers.length && !this.runningImmediates.length) {
|
101
|
+
this.resolveWhenComplete();
|
102
|
+
}
|
62
103
|
}
|
63
104
|
}
|
64
105
|
|
@@ -71,10 +112,7 @@ export default class AsyncTaskManager {
|
|
71
112
|
public startTask(abortHandler?: () => void): number {
|
72
113
|
const taskID = this.newTaskID();
|
73
114
|
this.runningTasks[taskID] = abortHandler ? abortHandler : () => {};
|
74
|
-
|
75
|
-
global.clearTimeout(this.callbackTimeout);
|
76
|
-
this.callbackTimeout = null;
|
77
|
-
}
|
115
|
+
this.runningTaskCount++;
|
78
116
|
return taskID;
|
79
117
|
}
|
80
118
|
|
@@ -86,13 +124,22 @@ export default class AsyncTaskManager {
|
|
86
124
|
public endTask(taskID: number): void {
|
87
125
|
if (this.runningTasks[taskID]) {
|
88
126
|
delete this.runningTasks[taskID];
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
127
|
+
this.runningTaskCount--;
|
128
|
+
if (this.whenCompleteImmediate) {
|
129
|
+
global.clearImmediate(this.whenCompleteImmediate);
|
130
|
+
}
|
131
|
+
if (!this.runningTaskCount && !this.runningTimers.length && !this.runningImmediates.length) {
|
132
|
+
this.whenCompleteImmediate = global.setImmediate(() => {
|
133
|
+
this.whenCompleteImmediate = null;
|
134
|
+
if (
|
135
|
+
!this.runningTaskCount &&
|
136
|
+
!this.runningTimers.length &&
|
137
|
+
!this.runningImmediates.length
|
138
|
+
) {
|
139
|
+
this.resolveWhenComplete();
|
140
|
+
}
|
141
|
+
});
|
142
|
+
}
|
96
143
|
}
|
97
144
|
}
|
98
145
|
|
@@ -102,7 +149,7 @@ export default class AsyncTaskManager {
|
|
102
149
|
* @returns Count.
|
103
150
|
*/
|
104
151
|
public getTaskCount(): number {
|
105
|
-
return
|
152
|
+
return this.runningTaskCount;
|
106
153
|
}
|
107
154
|
|
108
155
|
/**
|
@@ -116,47 +163,13 @@ export default class AsyncTaskManager {
|
|
116
163
|
}
|
117
164
|
|
118
165
|
/**
|
119
|
-
*
|
120
|
-
*
|
121
|
-
* @param [canceled] Canceled.
|
166
|
+
* Resolves when complete.
|
122
167
|
*/
|
123
|
-
private
|
124
|
-
const
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
this.runningTimers = [];
|
129
|
-
|
130
|
-
for (const timer of runningTimers) {
|
131
|
-
global.clearTimeout(timer);
|
132
|
-
}
|
133
|
-
|
134
|
-
for (const key of Object.keys(runningTasks)) {
|
135
|
-
runningTasks[key]();
|
136
|
-
}
|
137
|
-
|
138
|
-
if (this.callbackTimeout) {
|
139
|
-
global.clearTimeout(this.callbackTimeout);
|
140
|
-
this.callbackTimeout = null;
|
141
|
-
}
|
142
|
-
if (this.callbacks.length) {
|
143
|
-
if (canceled) {
|
144
|
-
const callbacks = this.callbacks;
|
145
|
-
this.callbacks = [];
|
146
|
-
for (const callback of callbacks) {
|
147
|
-
callback();
|
148
|
-
}
|
149
|
-
} else {
|
150
|
-
this.callbackTimeout = global.setTimeout(() => {
|
151
|
-
const callbacks = this.callbacks;
|
152
|
-
this.callbackTimeout = null;
|
153
|
-
this.callbacks = [];
|
154
|
-
this.runningTimers = [];
|
155
|
-
for (const callback of callbacks) {
|
156
|
-
callback();
|
157
|
-
}
|
158
|
-
}, 10);
|
159
|
-
}
|
168
|
+
private resolveWhenComplete(): void {
|
169
|
+
const resolvers = this.whenCompleteResolvers;
|
170
|
+
this.whenCompleteResolvers = [];
|
171
|
+
for (const resolver of resolvers) {
|
172
|
+
resolver();
|
160
173
|
}
|
161
174
|
}
|
162
175
|
}
|
package/src/fetch/Fetch.ts
CHANGED
@@ -92,12 +92,12 @@ export default class Fetch {
|
|
92
92
|
}
|
93
93
|
|
94
94
|
this.resolve = (response: IResponse | Promise<IResponse>): void => {
|
95
|
-
resolve(response);
|
96
95
|
taskManager.endTask(taskID);
|
96
|
+
resolve(response);
|
97
97
|
};
|
98
98
|
this.reject = (error: Error): void => {
|
99
|
-
reject(error);
|
100
99
|
taskManager.endTask(taskID);
|
100
|
+
reject(error);
|
101
101
|
};
|
102
102
|
|
103
103
|
this.prepareRequest();
|
@@ -7,7 +7,7 @@ export default class DocumentReadyStateManager {
|
|
7
7
|
private totalTasks = 0;
|
8
8
|
private readyStateCallbacks: (() => void)[] = [];
|
9
9
|
private window: IWindow = null;
|
10
|
-
private
|
10
|
+
private immediate: NodeJS.Immediate | null = null;
|
11
11
|
private isComplete = false;
|
12
12
|
|
13
13
|
/**
|
@@ -30,8 +30,8 @@ export default class DocumentReadyStateManager {
|
|
30
30
|
resolve();
|
31
31
|
} else {
|
32
32
|
this.readyStateCallbacks.push(resolve);
|
33
|
-
if (this.totalTasks === 0 && !this.
|
34
|
-
this.
|
33
|
+
if (this.totalTasks === 0 && !this.immediate) {
|
34
|
+
this.immediate = this.window.requestAnimationFrame(this.endTask.bind(this));
|
35
35
|
}
|
36
36
|
}
|
37
37
|
});
|
@@ -45,9 +45,9 @@ export default class DocumentReadyStateManager {
|
|
45
45
|
return;
|
46
46
|
}
|
47
47
|
|
48
|
-
if (this.
|
49
|
-
this.window.
|
50
|
-
this.
|
48
|
+
if (this.immediate) {
|
49
|
+
this.window.cancelAnimationFrame(this.immediate);
|
50
|
+
this.immediate = null;
|
51
51
|
}
|
52
52
|
|
53
53
|
this.totalTasks++;
|
@@ -61,9 +61,9 @@ export default class DocumentReadyStateManager {
|
|
61
61
|
return;
|
62
62
|
}
|
63
63
|
|
64
|
-
if (this.
|
65
|
-
this.window.
|
66
|
-
this.
|
64
|
+
if (this.immediate) {
|
65
|
+
this.window.cancelAnimationFrame(this.immediate);
|
66
|
+
this.immediate = null;
|
67
67
|
}
|
68
68
|
|
69
69
|
this.totalTasks--;
|
package/src/window/IWindow.ts
CHANGED
@@ -492,16 +492,16 @@ export default interface IWindow extends IEventTarget, INodeJSGlobal {
|
|
492
492
|
* Mock animation frames with timeouts.
|
493
493
|
*
|
494
494
|
* @param {Function} callback Callback.
|
495
|
-
* @returns {NodeJS.Timeout}
|
495
|
+
* @returns {NodeJS.Timeout} ID.
|
496
496
|
*/
|
497
|
-
requestAnimationFrame(callback: (timestamp: number) => void): NodeJS.
|
497
|
+
requestAnimationFrame(callback: (timestamp: number) => void): NodeJS.Immediate;
|
498
498
|
|
499
499
|
/**
|
500
500
|
* Mock animation frames with timeouts.
|
501
501
|
*
|
502
|
-
* @param {NodeJS.Timeout} id
|
502
|
+
* @param {NodeJS.Timeout} id ID.
|
503
503
|
*/
|
504
|
-
cancelAnimationFrame(id: NodeJS.
|
504
|
+
cancelAnimationFrame(id: NodeJS.Immediate): void;
|
505
505
|
|
506
506
|
/**
|
507
507
|
* This method provides an easy, logical way to fetch resources asynchronously across the network.
|
package/src/window/Window.ts
CHANGED
@@ -837,12 +837,12 @@ export default class Window extends EventTarget implements IWindow {
|
|
837
837
|
*/
|
838
838
|
public setTimeout(callback: Function, delay = 0, ...args: unknown[]): NodeJS.Timeout {
|
839
839
|
const id = this._setTimeout(() => {
|
840
|
-
this.happyDOM.asyncTaskManager.endTimer(id);
|
841
840
|
if (this.happyDOM.settings.disableErrorCapturing) {
|
842
841
|
callback(...args);
|
843
842
|
} else {
|
844
843
|
WindowErrorUtility.captureError(this, () => callback(...args));
|
845
844
|
}
|
845
|
+
this.happyDOM.asyncTaskManager.endTimer(id);
|
846
846
|
}, delay);
|
847
847
|
this.happyDOM.asyncTaskManager.startTimer(id);
|
848
848
|
return id;
|
@@ -896,19 +896,29 @@ export default class Window extends EventTarget implements IWindow {
|
|
896
896
|
* Mock animation frames with timeouts.
|
897
897
|
*
|
898
898
|
* @param callback Callback.
|
899
|
-
* @returns
|
899
|
+
* @returns ID.
|
900
900
|
*/
|
901
|
-
public requestAnimationFrame(callback: (timestamp: number) => void): NodeJS.
|
902
|
-
|
901
|
+
public requestAnimationFrame(callback: (timestamp: number) => void): NodeJS.Immediate {
|
902
|
+
const id = global.setImmediate(() => {
|
903
|
+
if (this.happyDOM.settings.disableErrorCapturing) {
|
904
|
+
callback(this.performance.now());
|
905
|
+
} else {
|
906
|
+
WindowErrorUtility.captureError(this, () => callback(this.performance.now()));
|
907
|
+
}
|
908
|
+
this.happyDOM.asyncTaskManager.endImmediate(id);
|
909
|
+
});
|
910
|
+
this.happyDOM.asyncTaskManager.startImmediate(id);
|
911
|
+
return id;
|
903
912
|
}
|
904
913
|
|
905
914
|
/**
|
906
915
|
* Mock animation frames with timeouts.
|
907
916
|
*
|
908
|
-
* @param id
|
917
|
+
* @param id ID.
|
909
918
|
*/
|
910
|
-
public cancelAnimationFrame(id: NodeJS.
|
911
|
-
|
919
|
+
public cancelAnimationFrame(id: NodeJS.Immediate): void {
|
920
|
+
global.clearImmediate(id);
|
921
|
+
this.happyDOM.asyncTaskManager.endImmediate(id);
|
912
922
|
}
|
913
923
|
|
914
924
|
/**
|
@@ -921,13 +931,12 @@ export default class Window extends EventTarget implements IWindow {
|
|
921
931
|
const taskId = this.happyDOM.asyncTaskManager.startTask(() => (isAborted = true));
|
922
932
|
this._queueMicrotask(() => {
|
923
933
|
if (!isAborted) {
|
924
|
-
this.happyDOM.asyncTaskManager.endTask(taskId);
|
925
|
-
|
926
934
|
if (this.happyDOM.settings.disableErrorCapturing) {
|
927
935
|
callback();
|
928
936
|
} else {
|
929
937
|
WindowErrorUtility.captureError(this, <() => unknown>callback);
|
930
938
|
}
|
939
|
+
this.happyDOM.asyncTaskManager.endTask(taskId);
|
931
940
|
}
|
932
941
|
});
|
933
942
|
}
|