backup: js delay loop

 

在一次执行结束后等待指定间隔再执行下次

 

--see-also  https://developer.mozilla.org/zh-CN/docs/Web/API/Window/setInterval

确保执行时间短于定时器时间间隔

如果你的代码逻辑执行时间可能比定时器时间间隔要长,建议你使用递归调用了 setTimeout() 的具名函数。例如,使用 setInterval() 以 5 秒的间隔轮询服务器,可能因网络延迟、服务器无响应以及许多其他的问题而导致请求无法在分配的时间内完成。因此,你可能会发现排队的 XHR 请求没有按顺序返回。

在这些场景下,应首选递归调用 setTimeout() 的模式:

js
 
(function loop() {
  setTimeout(function () {
    // 在这里编写代码逻辑

    loop();
  }, delay);
})();

在上面的代码片段中,声明了一个具名函数 loop(),并被立即执行。loop() 在完成代码逻辑的执行后,会在内部递归调用 setTimeout()。虽然该模式不保证以固定的时间间隔执行,但它保证了上一次定时任务在递归前已经完成。

 

 1 const loop = (firstNoDelay, delay, callbackFn) => {
 2   // firstNoDelay : true 立即执行第一次
 3   // delay 单位毫秒
 4   const wrappedCallback = () => {
 5     try {
 6       callbackFn();
 7       return [];
 8     } catch (err) {
 9       return [ err ];
10     }
11   };
12 
13   let running = true;
14   let timer = null;
15   const loopInner = () => {
16     timer = setTimeout(() => {
17       if (running) {
18         wrappedCallback();
19         loopInner();
20       }
21     }, delay);
22   }
23 
24   const firstPromise = firstNoDelay ? new Promise((resolve, reject) => {
25     return resolve(wrappedCallback());
26   }) : Promise.resolve([]);
27 
28   firstPromise.then((r) => {
29     // console.log('[DEBUG] loop result of first', r);
30     loopInner();
31     return 0;
32   });
33 
34   return () => {
35     running = false;
36     const t = timer;
37     if (t == null) {
38       console.log("no timer");
39     } else {
40       timer = null;
41       console.log("clear timer", t);
42       clearTimeout(t);
43     }
44   };
45 };

 

html 示例

 1 <!DOCTYPE html>
 2 <html>
 3 <head>
 4     <title>test recurse timeout</title>
 5 </head>
 6 <body>
 7     <button id="startBtn">start</button>
 8     <button id="stopBtn">stop</button>
 9     <div id="testDiv"></div>
10 
11     <script>
12         const loop = (firstNoDelay, delay, callbackFn) => {
13           // firstNoDelay : true 立即执行第一次
14           // delay 单位毫秒
15           const wrappedCallback = () => {
16             try {
17               callbackFn();
18               return [];
19             } catch (err) {
20               return [ err ];
21             }
22           };
23 
24           let running = true;
25           let timer = null;
26           const loopInner = () => {
27             timer = setTimeout(() => {
28               if (running) {
29                 wrappedCallback();
30                 loopInner();
31               }
32             }, delay);
33           }
34 
35           const firstPromise = firstNoDelay ? new Promise((resolve, reject) => {
36             return resolve(wrappedCallback());
37           }) : Promise.resolve([]);
38 
39           firstPromise.then((r) => {
40             // console.log('[DEBUG] loop result of first', r);
41             loopInner();
42             return 0;
43           });
44 
45           return () => {
46             running = false;
47             const t = timer;
48             if (t == null) {
49               console.log("no timer");
50             } else {
51               timer = null;
52               console.log("clear timer", t);
53               clearTimeout(t);
54             }
55           };
56         };
57         document.addEventListener("DOMContentLoaded", () => {
58             console.log("loaded");
59             const testDiv = document.getElementById("testDiv");
60             const startBtn = document.getElementById("startBtn");
61             const stopBtn = document.getElementById("stopBtn");
62 
63             const loopTerms = [];
64             startBtn.addEventListener("click", () => {
65                 startBtn.disabled = true;
66                 const startTimeTxt = `${new Date()}`
67                 const clearLoop = loop(true, 1000, () => {testDiv.innerText = `${startTimeTxt} \n ${new Date()}`});
68                 loopTerms.push(clearLoop);
69             });
70             stopBtn.addEventListener("click", () => {
71                 startBtn.disabled = false;
72                 for (let clrLoop = loopTerms.shift(); clrLoop; clrLoop = loopTerms.shift()) {
73                     clrLoop();
74                 }
75             });
76         });
77     </script>
78 </body>
79 </html>

 

--- THE END ---

 

posted @ 2025-02-09 13:41  太初谷神  阅读(16)  评论(0)    收藏  举报