resource-preloader 2.0.2 → 2.0.4

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.
Files changed (38) hide show
  1. package/README.md +4 -3
  2. package/dist/resource-loader.amd.js +335 -0
  3. package/dist/resource-loader.amd.js.map +1 -0
  4. package/dist/resource-loader.amd.min.js +2 -0
  5. package/dist/resource-loader.amd.min.js.map +1 -0
  6. package/dist/resource-loader.cjs.js +333 -0
  7. package/dist/resource-loader.cjs.js.map +1 -0
  8. package/dist/resource-loader.cjs.min.js +2 -0
  9. package/dist/resource-loader.cjs.min.js.map +1 -0
  10. package/dist/resource-loader.esm.js +328 -0
  11. package/dist/resource-loader.esm.js.map +1 -0
  12. package/dist/resource-loader.esm.min.js +2 -0
  13. package/dist/resource-loader.esm.min.js.map +1 -0
  14. package/dist/resource-loader.umd.js +339 -0
  15. package/dist/resource-loader.umd.js.map +1 -0
  16. package/dist/resource-loader.umd.min.js +2 -0
  17. package/dist/resource-loader.umd.min.js.map +1 -0
  18. package/dist/resource-preloader.amd.js +394 -0
  19. package/dist/resource-preloader.amd.js.map +1 -0
  20. package/dist/resource-preloader.amd.min.js +2 -0
  21. package/dist/resource-preloader.amd.min.js.map +1 -0
  22. package/dist/resource-preloader.cjs.js +392 -0
  23. package/dist/resource-preloader.cjs.js.map +1 -0
  24. package/dist/resource-preloader.cjs.min.js +2 -0
  25. package/dist/resource-preloader.cjs.min.js.map +1 -0
  26. package/dist/resource-preloader.esm.js +387 -0
  27. package/dist/resource-preloader.esm.js.map +1 -0
  28. package/dist/resource-preloader.esm.min.js +2 -0
  29. package/dist/resource-preloader.esm.min.js.map +1 -0
  30. package/dist/resource-preloader.umd.js +398 -0
  31. package/dist/resource-preloader.umd.js.map +1 -0
  32. package/dist/resource-preloader.umd.min.js +2 -0
  33. package/dist/resource-preloader.umd.min.js.map +1 -0
  34. package/package.json +1 -7
  35. package/src/config.js +4 -3
  36. package/src/loader.js +109 -51
  37. package/src/scheduler.js +18 -21
  38. package/types/index.d.ts +2 -2
package/src/loader.js CHANGED
@@ -4,20 +4,22 @@ const loaderMap = new Map();
4
4
  /**
5
5
  * 通用资源加载Promise封装
6
6
  * @param {string} url - 资源地址
7
- * @param {Function} loadHandler - 具体的资源加载处理函数
7
+ * @param {string} type - 具体的资源加载处理函数
8
8
  * @param {number} timeout - 超时时间
9
- * @returns {Promise<Object>} 加载结果Promise
9
+ * @returns {Promise<LoadResult>} 加载结果Promise
10
10
  */
11
- function wrapLoadPromise(url, loadHandler, timeout) {
12
- return new Promise((resolve, reject) => {
11
+ export function wrapLoadPromise(url, type, timeout) {
12
+ return new Promise(function (resolve, reject) {
13
+ // 获取加载器处理函数
14
+ const handler = getLoader(type);
13
15
  // 超时处理
14
16
  const timeoutTimer = setTimeout(() => {
15
17
  reject(new Error(`Resource ${url} load timeout (${timeout}ms)`));
16
18
  }, timeout);
17
19
 
18
20
  // 执行具体加载逻辑
19
- loadHandler(url)
20
- .then((result) => {
21
+ handler(url)
22
+ .then(function (result) {
21
23
  clearTimeout(timeoutTimer);
22
24
  resolve({
23
25
  url,
@@ -26,7 +28,7 @@ function wrapLoadPromise(url, loadHandler, timeout) {
26
28
  error: null,
27
29
  });
28
30
  })
29
- .catch((error) => {
31
+ .catch(function (error) {
30
32
  clearTimeout(timeoutTimer);
31
33
  reject({
32
34
  url,
@@ -38,62 +40,120 @@ function wrapLoadPromise(url, loadHandler, timeout) {
38
40
  });
39
41
  }
40
42
 
43
+ /** 初始化内置加载器 **/
41
44
  // --------------- 内置JS加载器 ---------------
42
- function jsLoaderHandler(url) {
43
- return new Promise((resolve, reject) => {
45
+ loaderMap.set(
46
+ 'js',
47
+ /**
48
+ * JS加载器
49
+ * @param {string} url
50
+ * @returns {Promise<HTMLScriptElement|void>}
51
+ */
52
+ function (url) {
44
53
  const script = document.createElement('script');
45
- script.type = 'text/javascript';
46
- script.src = url;
47
- script.async = false; // 保持加载顺序(不开启异步)
54
+ return new Promise(function (resolve, reject) {
55
+ script.type = 'text/javascript';
56
+ script.src = url;
57
+ script.async = false; // 保持加载顺序(不开启异步)
58
+ script.dataset.flag = 'resource-preloader';
48
59
 
49
- script.onload = () => {
50
- resolve(script);
51
- document.head.removeChild(script); // 可选:加载完成后移除标签,避免污染DOM
52
- };
60
+ script.addEventListener('load', function (e) {
61
+ resolve(script);
62
+ });
63
+ script.addEventListener('error', function () {
64
+ reject(new Error(`JS resource ${url} load failed`));
65
+ });
53
66
 
54
- script.onerror = () => {
55
- reject(new Error(`JS resource ${url} load failed`));
67
+ document.head.appendChild(script);
68
+ }).finally(function () {
69
+ // 加载完成后移除标签,避免污染DOM
56
70
  document.head.removeChild(script);
57
- };
58
-
59
- document.head.appendChild(script);
60
- });
61
- }
62
-
71
+ });
72
+ }
73
+ );
63
74
  // --------------- 内置CSS加载器 ---------------
64
- function cssLoaderHandler(url) {
65
- return new Promise((resolve, reject) => {
66
- const link = document.createElement('link');
67
- link.rel = 'stylesheet';
68
- link.href = url;
69
-
70
- link.onload = () => {
71
- resolve(link);
72
- };
73
-
74
- link.onerror = () => {
75
- reject(new Error(`CSS resource ${url} load failed`));
76
- };
77
-
78
- document.head.appendChild(link);
79
- });
80
- }
75
+ loaderMap.set(
76
+ 'css',
77
+ /**
78
+ * CSS加载器
79
+ * @param {string} url
80
+ * @returns {Promise<HTMLLinkElement>}
81
+ */
82
+ function (url) {
83
+ return new Promise(function (resolve, reject) {
84
+ const link = document.createElement('link');
85
+ link.rel = 'stylesheet';
86
+ link.href = url;
87
+ link.dataset.flag = 'resource-preloader';
81
88
 
82
- // 初始化内置加载器
83
- loaderMap.set('js', jsLoaderHandler);
84
- loaderMap.set('css', cssLoaderHandler);
89
+ link.addEventListener('load', function () {
90
+ resolve(link);
91
+ });
92
+ link.addEventListener('error', function () {
93
+ reject(new Error(`CSS resource ${url} load failed`));
94
+ document.head.removeChild(link);
95
+ });
96
+ document.head.appendChild(link);
97
+ });
98
+ }
99
+ );
100
+ // --------------- 内置IMG加载器 ---------------
101
+ loaderMap.set(
102
+ 'img',
103
+ /**
104
+ * 图片加载器
105
+ * @param url
106
+ * @returns {Promise<HTMLImageElement>}
107
+ */
108
+ function (url) {
109
+ const img = new Image();
110
+ img.dataset.flag = 'resource-preloader';
111
+ return new Promise(function (resolve, reject) {
112
+ img.addEventListener('load', function () {
113
+ resolve(img);
114
+ });
115
+ img.addEventListener('error', function () {
116
+ reject(new Error(`IMG resource ${url} load failed`));
117
+ });
118
+ // img 标签不需要添加到DOM树
119
+ img.src = url;
120
+ });
121
+ }
122
+ );
123
+ // --------------- 内置JSON加载器 ---------------
124
+ loaderMap.set(
125
+ 'json',
126
+ /**
127
+ * JSON加载器
128
+ * @param {string} url
129
+ * @returns {Promise<Object|Array|null|undefined>}
130
+ */
131
+ function (url) {
132
+ return fetch(url)
133
+ .then(function (res) {
134
+ if (!res.ok) {
135
+ throw new Error(`JSON resource ${url} load failed`);
136
+ }
137
+ return res.json();
138
+ })
139
+ .catch(function (error) {
140
+ throw new Error(`JSON resource ${url} load failed: ${error.message}`);
141
+ });
142
+ }
143
+ );
85
144
 
86
145
  /**
87
- * 注册自定义加载器的方法(导出)
146
+ * 注册自定义加载器的方法
88
147
  * @param {string} type - 资源类型(唯一标识)
89
- * @param {Function} handler - 加载处理函数,接收url参数,返回Promise
148
+ * @param {LoaderHandler} handler - 加载处理函数,接收url参数,返回Promise
90
149
  */
91
- function registerLoader(type, handler) {
150
+ export function registerLoader(type, handler) {
92
151
  if (typeof type !== 'string' || type.trim() === '') {
93
152
  throw new Error('资源类型必须是非空字符串');
94
153
  }
95
- if (typeof handler !== 'function' || handler.constructor.name !== 'Function') {
96
- throw new Error('加载器必须是一个函数,且返回Promise对象');
154
+ const _ = Object.prototype.toString.call(type).slice(8, -1);
155
+ if (['Function', 'AsyncFunction'].includes(_)) {
156
+ throw new Error('加载器必须是一个函数返回Promise对象或一个异步函数');
97
157
  }
98
158
  if (loaderMap.has(type)) {
99
159
  console.warn(`类型为${type}的加载器已存在,将被覆盖`);
@@ -112,5 +172,3 @@ function getLoader(type) {
112
172
  }
113
173
  return loaderMap.get(type);
114
174
  }
115
-
116
- export { registerLoader, getLoader, wrapLoadPromise }; // 导出wrapLoadPromise,避免冗余
package/src/scheduler.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import {getGlobalConfig} from './config.js';
2
- import {getLoader, wrapLoadPromise} from './loader.js';
2
+ import {wrapLoadPromise} from './loader.js';
3
3
 
4
4
  /**
5
5
  * 检测循环依赖(深度优先遍历,配置字段改为dependencies)
@@ -49,26 +49,27 @@ function checkAllCycles(configList) {
49
49
 
50
50
  /**
51
51
  * 递归加载单个资源及其所有依赖(保证依赖先加载,配置字段改为dependencies)
52
- * @param {string|number} resourceId - 资源ID
52
+ * @param {string|number} name - 资源ID
53
53
  * @param {Array} configList - 完整配置数组
54
54
  * @param {number} timeout - 超时时间
55
55
  * @param {Map} loadedMap - 已加载资源的结果缓存
56
+ * @returns {Promise<ResourceLoadResult>} 加载结果
56
57
  */
57
- async function loadResourceWithDeps(resourceId, configList, timeout, loadedMap) {
58
+ async function loadResourceWithDeps(name, configList, timeout, loadedMap) {
58
59
  // 若已加载,直接返回缓存结果
59
- if (loadedMap.has(resourceId)) {
60
- return loadedMap.get(resourceId);
60
+ if (loadedMap.has(name)) {
61
+ return loadedMap.get(name);
61
62
  }
62
63
 
63
- const currentConfig = configList.find(item => item.name === resourceId);
64
+ const currentConfig = configList.find(item => item.name === name);
64
65
  if (!currentConfig) {
65
- throw new Error(`未找到ID为${resourceId}的资源配置`);
66
+ throw new Error(`未找到name为${name}的资源配置`);
66
67
  }
67
68
 
68
69
  // 1. 先加载所有依赖(改为dependencies)
69
70
  const dependencies = currentConfig.dependencies || [];
70
- for (const depId of dependencies) {
71
- await loadResourceWithDeps(depId, configList, timeout, loadedMap);
71
+ for (const _ of dependencies) {
72
+ await loadResourceWithDeps(_, configList, timeout, loadedMap);
72
73
  }
73
74
 
74
75
  // 2. 再加载当前资源的urls(顺序加载,一个成功即可)
@@ -86,13 +87,13 @@ async function loadResourceWithDeps(resourceId, configList, timeout, loadedMap)
86
87
 
87
88
  // 3. 缓存加载结果
88
89
  const result = {
89
- resourceId,
90
+ name,
90
91
  config: currentConfig,
91
- loadResult,
92
+ result:loadResult,
92
93
  status,
93
94
  error,
94
95
  };
95
- loadedMap.set(resourceId, result);
96
+ loadedMap.set(name, result);
96
97
  return result;
97
98
  }
98
99
 
@@ -101,23 +102,21 @@ async function loadResourceWithDeps(resourceId, configList, timeout, loadedMap)
101
102
  * @param {Array} urls - 资源地址数组
102
103
  * @param {string} type - 资源类型
103
104
  * @param {number} timeout - 超时时间
104
- * @returns {Promise<Object>} 第一个成功的加载结果
105
+ * @returns {Promise<LoadResult>} 成功的加载结果
105
106
  */
106
107
  async function loadUrlsInOrder(urls, type, timeout) {
107
108
  if (!Array.isArray(urls) || urls.length === 0) {
108
109
  throw new Error('urls必须是非空数组');
109
110
  }
110
111
 
111
- const loader = getLoader(type);
112
112
  let lastError;
113
113
 
114
114
  // 按顺序遍历urls,直到有一个加载成功
115
115
  for (const url of urls) {
116
116
  try {
117
- return await wrapLoadPromise(url, loader, timeout);
117
+ return await wrapLoadPromise(url, type, timeout);
118
118
  } catch (error) {
119
- lastError = error;
120
- continue; // 加载失败,继续下一个url
119
+ lastError = error; // 加载失败,继续下一个url
121
120
  }
122
121
  }
123
122
 
@@ -130,7 +129,7 @@ async function loadUrlsInOrder(urls, type, timeout) {
130
129
  * @param {Array<ResourceConfig>} configList - 输入配置数组
131
130
  * @returns {Promise<ResourceLoadResult[]>} 按配置定义顺序的加载结果数组
132
131
  */
133
- async function resourcePreloader(configList) {
132
+ export async function resourcePreloader(configList) {
134
133
  if (!Array.isArray(configList) || configList.length === 0) {
135
134
  throw new Error('配置数组必须是非空数组');
136
135
  }
@@ -169,7 +168,7 @@ async function resourcePreloader(configList) {
169
168
  const loadedMap = new Map();
170
169
 
171
170
  // 4. 按配置定义的顺序,并行加载同层级无依赖资源(保证依赖先加载,结果保留原始顺序)
172
- const rawOrderPromises = configList.map(async (config) => {
171
+ const rawOrderPromises = configList.map(async function(config) {
173
172
  return await loadResourceWithDeps(config.name, configList, globalTimeout, loadedMap);
174
173
  });
175
174
 
@@ -181,5 +180,3 @@ async function resourcePreloader(configList) {
181
180
  return result;
182
181
  });
183
182
  }
184
-
185
- export {resourcePreloader};
package/types/index.d.ts CHANGED
@@ -25,11 +25,11 @@ export interface LoadResult {
25
25
  // 资源加载结果类型
26
26
  export interface ResourceLoadResult {
27
27
  /** 资源ID */
28
- resourceId: string;
28
+ name: string;
29
29
  /** 原始配置 */
30
30
  config: ResourceConfig;
31
31
  /** 加载结果 */
32
- loadResult: LoadResult;
32
+ result: LoadResult;
33
33
  /** 加载状态 */
34
34
  status: 'success' | 'failed';
35
35
  /** 错误信息 */