jsly 3.1.6 → 3.1.7
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 +69 -0
- package/dist/index.cjs.js +131 -0
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.esm.js +130 -1
- package/dist/index.esm.js.map +1 -1
- package/dist/index.umd.js +3 -3
- package/dist/index.umd.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -227,3 +227,72 @@ color: '#0f0'
|
|
|
227
227
|
| `config.tag` | `string` | `'span'` | 包裹关键词的标签名 |
|
|
228
228
|
| `config.bgColor` | `string` | `'#ff0'` | 背景颜色 |
|
|
229
229
|
| `config.color` | `string` | `'#001'` | 文本颜色 |
|
|
230
|
+
|
|
231
|
+
### 基于 requestAnimationFrame 的定时器(rafInterval)
|
|
232
|
+
使用 requestAnimationFrame 实现类似 setInterval 的效果。
|
|
233
|
+
更适合动画、轮播、游戏循环等需要与浏览器帧同步的场景。
|
|
234
|
+
|
|
235
|
+
```javascript
|
|
236
|
+
import { rafInterval } from 'jsly'
|
|
237
|
+
|
|
238
|
+
// 每秒执行一次
|
|
239
|
+
const stop = rafInterval(() => {
|
|
240
|
+
console.log('tick')
|
|
241
|
+
}, 1000)
|
|
242
|
+
|
|
243
|
+
// 停止执行
|
|
244
|
+
stop()
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
在 Vue 中使用
|
|
248
|
+
|
|
249
|
+
```javascript
|
|
250
|
+
import { rafInterval } from 'jsly'
|
|
251
|
+
import { onMounted, onUnmounted } from 'vue'
|
|
252
|
+
|
|
253
|
+
let stop
|
|
254
|
+
|
|
255
|
+
onMounted(() => {
|
|
256
|
+
stop = rafInterval(() => {
|
|
257
|
+
console.log('frame update')
|
|
258
|
+
}, 16) // 约 60fps
|
|
259
|
+
})
|
|
260
|
+
|
|
261
|
+
onUnmounted(() => {
|
|
262
|
+
stop()
|
|
263
|
+
})
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
### 基轮询函数(poll)
|
|
267
|
+
用于按固定间隔重复执行任务,直到:
|
|
268
|
+
- 返回结果为 truthy
|
|
269
|
+
- 超时
|
|
270
|
+
- 手动停止
|
|
271
|
+
适用于接口状态查询、等待资源加载、检测条件成立等场景。
|
|
272
|
+
|
|
273
|
+
```javascript
|
|
274
|
+
import { poll } from 'jsly'
|
|
275
|
+
|
|
276
|
+
// 轮询接口直到 ready === true
|
|
277
|
+
const { promise, stop } = poll(
|
|
278
|
+
async () => {
|
|
279
|
+
const res = await fetch('/api/status').then(r => r.json())
|
|
280
|
+
return res.ready && res
|
|
281
|
+
},
|
|
282
|
+
{
|
|
283
|
+
interval: 2000, // 每 2 秒执行一次
|
|
284
|
+
timeout: 10000 // 10 秒超时
|
|
285
|
+
}
|
|
286
|
+
)
|
|
287
|
+
|
|
288
|
+
promise
|
|
289
|
+
.then(data => {
|
|
290
|
+
console.log('成功:', data)
|
|
291
|
+
})
|
|
292
|
+
.catch(err => {
|
|
293
|
+
console.error('轮询失败:', err)
|
|
294
|
+
})
|
|
295
|
+
|
|
296
|
+
// 如需手动停止
|
|
297
|
+
// stop()
|
|
298
|
+
```
|
package/dist/index.cjs.js
CHANGED
|
@@ -7689,6 +7689,135 @@ function highlightKeyword(text, keyword, config = {
|
|
|
7689
7689
|
return text.replace(pattern, match => `<${tag} style="${style}">${match}</${tag}>`);
|
|
7690
7690
|
}
|
|
7691
7691
|
|
|
7692
|
+
/**
|
|
7693
|
+
* 基于 requestAnimationFrame 实现的定时器(RAF Interval)
|
|
7694
|
+
*
|
|
7695
|
+
* 功能类似于 setInterval,但内部使用 requestAnimationFrame 驱动。
|
|
7696
|
+
* 相比 setInterval:
|
|
7697
|
+
* - 与浏览器刷新率同步,更平滑
|
|
7698
|
+
* - 页面不可见时会自动暂停(节省性能)
|
|
7699
|
+
* - 不易出现掉帧或时间漂移问题
|
|
7700
|
+
*
|
|
7701
|
+
* 适用于动画、轮播、游戏循环等需要与渲染帧同步的场景。
|
|
7702
|
+
*
|
|
7703
|
+
* @template {(...args: any[]) => any} F
|
|
7704
|
+
* @param {F} callback - 每次间隔触发时执行的函数。
|
|
7705
|
+
* @param {number} delay - 执行间隔时间(毫秒)。
|
|
7706
|
+
* @returns {() => void} 返回一个停止函数,用于取消循环。
|
|
7707
|
+
*
|
|
7708
|
+
* @example
|
|
7709
|
+
* const stop = rafInterval(() => {
|
|
7710
|
+
* console.log('每秒执行一次')
|
|
7711
|
+
* }, 1000)
|
|
7712
|
+
*
|
|
7713
|
+
* // 停止
|
|
7714
|
+
* stop()
|
|
7715
|
+
*
|
|
7716
|
+
* @example
|
|
7717
|
+
* // 在 Vue 中使用
|
|
7718
|
+
* let stop
|
|
7719
|
+
* onMounted(() => {
|
|
7720
|
+
* stop = rafInterval(() => {
|
|
7721
|
+
* rotate.value += 1
|
|
7722
|
+
* }, 16)
|
|
7723
|
+
* })
|
|
7724
|
+
*
|
|
7725
|
+
* onUnmounted(() => {
|
|
7726
|
+
* stop()
|
|
7727
|
+
* })
|
|
7728
|
+
*/
|
|
7729
|
+
function rafInterval(callback, delay) {
|
|
7730
|
+
if (typeof callback !== 'function') {
|
|
7731
|
+
throw new TypeError('rafInterval expected a function as the first argument');
|
|
7732
|
+
}
|
|
7733
|
+
let start = performance.now();
|
|
7734
|
+
let frameId = null;
|
|
7735
|
+
let stopped = false;
|
|
7736
|
+
function loop(now) {
|
|
7737
|
+
if (stopped) return;
|
|
7738
|
+
const delta = now - start;
|
|
7739
|
+
if (delta >= delay) {
|
|
7740
|
+
callback();
|
|
7741
|
+
// 使用 += 防止时间漂移
|
|
7742
|
+
start += delay;
|
|
7743
|
+
}
|
|
7744
|
+
frameId = requestAnimationFrame(loop);
|
|
7745
|
+
}
|
|
7746
|
+
frameId = requestAnimationFrame(loop);
|
|
7747
|
+
return function stop() {
|
|
7748
|
+
stopped = true;
|
|
7749
|
+
if (frameId) cancelAnimationFrame(frameId);
|
|
7750
|
+
};
|
|
7751
|
+
}
|
|
7752
|
+
|
|
7753
|
+
/**
|
|
7754
|
+
* 轮询函数(Polling)
|
|
7755
|
+
*
|
|
7756
|
+
* 按指定间隔重复执行异步任务,直到:
|
|
7757
|
+
* 1. 任务返回 truthy 值(成功)
|
|
7758
|
+
* 2. 超时
|
|
7759
|
+
* 3. 被手动停止
|
|
7760
|
+
*
|
|
7761
|
+
* 常用于:
|
|
7762
|
+
* - 接口状态查询
|
|
7763
|
+
* - 等待资源加载完成
|
|
7764
|
+
* - 检测条件成立
|
|
7765
|
+
*
|
|
7766
|
+
* @template T
|
|
7767
|
+
* @param {() => Promise<T> | T} task - 需要轮询执行的函数(支持同步或异步)。
|
|
7768
|
+
* @param {Object} [options]
|
|
7769
|
+
* @param {number} [options.interval=1000] - 每次轮询间隔时间(毫秒)。
|
|
7770
|
+
* @param {number} [options.timeout=0] - 超时时间(毫秒),0 表示不限制。
|
|
7771
|
+
* @returns {{ promise: Promise<T>, stop: () => void }}
|
|
7772
|
+
*
|
|
7773
|
+
* @example
|
|
7774
|
+
* const { promise, stop } = poll(
|
|
7775
|
+
* () => fetch('/api/status').then(r => r.json()),
|
|
7776
|
+
* { interval: 2000, timeout: 10000 }
|
|
7777
|
+
* )
|
|
7778
|
+
*
|
|
7779
|
+
* promise.then(res => console.log('成功:', res))
|
|
7780
|
+
*/
|
|
7781
|
+
function poll(task, {
|
|
7782
|
+
interval = 1000,
|
|
7783
|
+
timeout = 0
|
|
7784
|
+
} = {}) {
|
|
7785
|
+
if (typeof task !== 'function') {
|
|
7786
|
+
throw new TypeError('poll expected a function as the first argument');
|
|
7787
|
+
}
|
|
7788
|
+
let stopped = false;
|
|
7789
|
+
let startTime = Date.now();
|
|
7790
|
+
let timer = null;
|
|
7791
|
+
const promise = new Promise((resolve, reject) => {
|
|
7792
|
+
async function execute() {
|
|
7793
|
+
if (stopped) return;
|
|
7794
|
+
try {
|
|
7795
|
+
const result = await task();
|
|
7796
|
+
if (result) {
|
|
7797
|
+
resolve(result);
|
|
7798
|
+
return;
|
|
7799
|
+
}
|
|
7800
|
+
if (timeout && Date.now() - startTime >= timeout) {
|
|
7801
|
+
reject(new Error('Polling timeout'));
|
|
7802
|
+
return;
|
|
7803
|
+
}
|
|
7804
|
+
timer = setTimeout(execute, interval);
|
|
7805
|
+
} catch (err) {
|
|
7806
|
+
reject(err);
|
|
7807
|
+
}
|
|
7808
|
+
}
|
|
7809
|
+
execute();
|
|
7810
|
+
});
|
|
7811
|
+
function stop() {
|
|
7812
|
+
stopped = true;
|
|
7813
|
+
if (timer) clearTimeout(timer);
|
|
7814
|
+
}
|
|
7815
|
+
return {
|
|
7816
|
+
promise,
|
|
7817
|
+
stop
|
|
7818
|
+
};
|
|
7819
|
+
}
|
|
7820
|
+
|
|
7692
7821
|
exports.$bus = $bus;
|
|
7693
7822
|
exports.buildObjFormData = buildObjFormData;
|
|
7694
7823
|
exports.camelToSnake = camelToSnake;
|
|
@@ -7700,6 +7829,8 @@ exports.debounce = debounce;
|
|
|
7700
7829
|
exports.deepDiff = deepDiff;
|
|
7701
7830
|
exports.generateBrowserId = generateBrowserId;
|
|
7702
7831
|
exports.highlightKeyword = highlightKeyword;
|
|
7832
|
+
exports.poll = poll;
|
|
7833
|
+
exports.rafInterval = rafInterval;
|
|
7703
7834
|
exports.randomHash = randomHash;
|
|
7704
7835
|
exports.sha256 = sha256;
|
|
7705
7836
|
exports.shallowDiff = shallowDiff;
|