@rn-org/react-native-thread 0.5.0 → 0.6.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.
- package/README.md +143 -22
- package/lib/module/babel-plugin.js +328 -2
- package/lib/module/babel-plugin.js.map +1 -1
- package/lib/module/index.js +59 -8
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/src/index.d.ts +5 -0
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/babel-plugin.js +411 -2
- package/src/index.tsx +83 -12
package/src/index.tsx
CHANGED
|
@@ -8,12 +8,18 @@ export type ThreadInfo = {
|
|
|
8
8
|
readonly name: string;
|
|
9
9
|
};
|
|
10
10
|
|
|
11
|
+
export type ThreadError = {
|
|
12
|
+
message: string;
|
|
13
|
+
stack: string;
|
|
14
|
+
};
|
|
15
|
+
|
|
11
16
|
export type ThreadHandle = {
|
|
12
17
|
readonly id: number;
|
|
13
18
|
readonly name: string;
|
|
14
19
|
run(task: ThreadTask, params?: unknown): void;
|
|
15
20
|
onMessage(handler: (data: unknown) => void): () => void;
|
|
16
21
|
onMessage(): Promise<unknown>;
|
|
22
|
+
onError(handler: (error: ThreadError) => void): () => void;
|
|
17
23
|
destroy(): void;
|
|
18
24
|
};
|
|
19
25
|
|
|
@@ -37,18 +43,60 @@ function _unregister(id: number): void {
|
|
|
37
43
|
_registry.delete(id);
|
|
38
44
|
}
|
|
39
45
|
|
|
46
|
+
function _isBytecode(src: string): boolean {
|
|
47
|
+
return (
|
|
48
|
+
src.includes('[bytecode]') ||
|
|
49
|
+
/^\s*function\s*\(\)\s*\{\s*bytecode\s*\}/.test(src)
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function _serializeValue(value: unknown): string {
|
|
54
|
+
if (value === undefined) return 'undefined';
|
|
55
|
+
if (value === null) return 'null';
|
|
56
|
+
if (typeof value === 'function') {
|
|
57
|
+
const src = value.toString();
|
|
58
|
+
if (_isBytecode(src)) {
|
|
59
|
+
if (__DEV__) {
|
|
60
|
+
console.warn(
|
|
61
|
+
'[react-native-thread] A function param returned a Hermes bytecode placeholder. ' +
|
|
62
|
+
"Add the Babel plugin: plugins: ['@rn-org/react-native-thread/babel-plugin']"
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
return 'undefined';
|
|
66
|
+
}
|
|
67
|
+
return src;
|
|
68
|
+
}
|
|
69
|
+
if (typeof value === 'string') return JSON.stringify(value);
|
|
70
|
+
if (typeof value === 'number' || typeof value === 'boolean')
|
|
71
|
+
return String(value);
|
|
72
|
+
if (Array.isArray(value))
|
|
73
|
+
return '[' + value.map(_serializeValue).join(',') + ']';
|
|
74
|
+
if (typeof value === 'object') {
|
|
75
|
+
const rec = value as Record<string, unknown>;
|
|
76
|
+
if (typeof rec.__rnThreadFn === 'string') {
|
|
77
|
+
return rec.__rnThreadFn;
|
|
78
|
+
}
|
|
79
|
+
const entries = Object.entries(rec)
|
|
80
|
+
.map(([k, v]) => `${JSON.stringify(k)}:${_serializeValue(v)}`)
|
|
81
|
+
.join(',');
|
|
82
|
+
return '{' + entries + '}';
|
|
83
|
+
}
|
|
84
|
+
return String(value);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function _wrapWithErrorHandler(code: string): string {
|
|
88
|
+
return `try { ${code} } catch(__e__) { resolveThreadMessage(JSON.stringify({ __rnThreadError: true, message: __e__.message || String(__e__), stack: __e__.stack || '' })); }`;
|
|
89
|
+
}
|
|
90
|
+
|
|
40
91
|
function toCode(task: ThreadTask, params?: unknown): string {
|
|
41
92
|
if (typeof task === 'string') {
|
|
42
|
-
const
|
|
43
|
-
params !== undefined ?
|
|
44
|
-
return `var __params__ = ${
|
|
93
|
+
const paramsCode =
|
|
94
|
+
params !== undefined ? _serializeValue(params) : 'undefined';
|
|
95
|
+
return _wrapWithErrorHandler(`var __params__ = ${paramsCode};\n${task}`);
|
|
45
96
|
}
|
|
46
97
|
|
|
47
98
|
const src = task.toString();
|
|
48
|
-
if (
|
|
49
|
-
src.includes('[bytecode]') ||
|
|
50
|
-
/^\s*function\s*\(\)\s*\{\s*bytecode\s*\}/.test(src)
|
|
51
|
-
) {
|
|
99
|
+
if (_isBytecode(src)) {
|
|
52
100
|
if (__DEV__) {
|
|
53
101
|
console.warn(
|
|
54
102
|
'[react-native-thread] fn.toString() returned a Hermes bytecode placeholder. ' +
|
|
@@ -58,8 +106,8 @@ function toCode(task: ThreadTask, params?: unknown): string {
|
|
|
58
106
|
return '/* bytecode: no-op */';
|
|
59
107
|
}
|
|
60
108
|
|
|
61
|
-
const argsStr = params !== undefined ?
|
|
62
|
-
return `(${src})(${argsStr})
|
|
109
|
+
const argsStr = params !== undefined ? _serializeValue(params) : '';
|
|
110
|
+
return _wrapWithErrorHandler(`(${src})(${argsStr})`);
|
|
63
111
|
}
|
|
64
112
|
|
|
65
113
|
const SHARED_THREAD_NAME = 'RNOrgThread';
|
|
@@ -170,6 +218,16 @@ export function onMessage(
|
|
|
170
218
|
});
|
|
171
219
|
}
|
|
172
220
|
|
|
221
|
+
function _isThreadError(
|
|
222
|
+
data: unknown
|
|
223
|
+
): data is { __rnThreadError: true; message: string; stack: string } {
|
|
224
|
+
return (
|
|
225
|
+
typeof data === 'object' &&
|
|
226
|
+
data !== null &&
|
|
227
|
+
(data as any).__rnThreadError === true
|
|
228
|
+
);
|
|
229
|
+
}
|
|
230
|
+
|
|
173
231
|
function createThreadHandle(id: number, name: string): ThreadHandle {
|
|
174
232
|
return {
|
|
175
233
|
id,
|
|
@@ -180,18 +238,31 @@ function createThreadHandle(id: number, name: string): ThreadHandle {
|
|
|
180
238
|
onMessage: function (handler?: (data: unknown) => void) {
|
|
181
239
|
if (handler) {
|
|
182
240
|
return onMessage((data, threadId) => {
|
|
183
|
-
if (threadId === id) handler(data);
|
|
241
|
+
if (threadId === id && !_isThreadError(data)) handler(data);
|
|
184
242
|
});
|
|
185
243
|
}
|
|
186
|
-
return new Promise<unknown>((resolve) => {
|
|
244
|
+
return new Promise<unknown>((resolve, reject) => {
|
|
187
245
|
const unsub = onMessage((data, threadId) => {
|
|
188
246
|
if (threadId === id) {
|
|
189
247
|
unsub();
|
|
190
|
-
|
|
248
|
+
if (_isThreadError(data)) {
|
|
249
|
+
const err = new Error(data.message);
|
|
250
|
+
err.stack = data.stack;
|
|
251
|
+
reject(err);
|
|
252
|
+
} else {
|
|
253
|
+
resolve(data);
|
|
254
|
+
}
|
|
191
255
|
}
|
|
192
256
|
});
|
|
193
257
|
});
|
|
194
258
|
} as ThreadHandle['onMessage'],
|
|
259
|
+
onError(handler: (error: ThreadError) => void) {
|
|
260
|
+
return onMessage((data, threadId) => {
|
|
261
|
+
if (threadId === id && _isThreadError(data)) {
|
|
262
|
+
handler({ message: data.message, stack: data.stack });
|
|
263
|
+
}
|
|
264
|
+
});
|
|
265
|
+
},
|
|
195
266
|
destroy() {
|
|
196
267
|
destroyThread(id);
|
|
197
268
|
},
|