function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } // 堆代码 duidaima.com console.log('Hello'); sleep(2000).then(() => { console.log('World!'); });运行这段代码,你会在控制台看到 “Hello”。然后,在短暂的两秒钟后,“World!”v会接着出现。这是一种既简洁又有效的引入延迟的方法。如果你只是为了这个来的,那太好了!但如果你对“为什么”和“怎么做”的原因感到好奇,还有更多可以学习的内容。JavaScript中处理时间有其细微之处,了解这些可能会对你有所帮助。
require 'net/http' require 'json' url = 'https://api.github.com/users/jameshibbard' uri = URI(url) response = JSON.parse(Net::HTTP.get(uri)) puts response['public_repos'] puts 'Hello!'正如人们所期望的,这段代码向GitHub API发送一个请求以获取我的用户数据。然后解析响应,输出与我的GitHub帐户关联的公共仓库的数量,最后在屏幕上打印“Hello!”。执行是从上到下进行的。相比之下,这是相同功能的JavaScript版本:
fetch('https://api.github.com/users/jameshibbard') .then(res => res.json()) .then(json => console.log(json.public_repos)); console.log('Hello!');如果你运行这段代码,它会先在屏幕上输出“Hello!”,然后输出与我的GitHub帐户关联的公共仓库的数量。这是因为在JavaScript中,从API获取数据是一个异步操作。JavaScript解释器会遇到 fetch 命令并发送请求。然而,它不会等待请求完成。相反,它会继续执行,将“Hello!”输出到控制台,然后当请求在几百毫秒后返回时,它会输出仓库的数量。
console.log('Hello'); setTimeout(() => { console.log('World!'); }, 2000);这将在控制台上输出 "Hello",然后两秒后输出 "World!"。在很多情况下,这已经足够了:做某事,然后在短暂的延迟后,做其他事情。问题解决!但不幸的是,事情并不总是那么简单。你可能会认为 setTimeout 会暂停整个程序,但事实并非如此。它是一个异步函数,这意味着其余的代码不会等待它完成。
console.log('Hello'); setTimeout(() => { console.log('World!'); }, 2000); console.log('Goodbye!');你会看到以下输出:
Hello Goodbye! World!注意“Goodbye!”是如何出现在“World!”之前的?这是因为 setTimeout 不会阻塞其余代码的执行。
console.log('Hello'); setTimeout(1000); console.log('World');"Hello" 和 "World" 会立即被记录在控制台上,之间没有明显的延迟。
for (let i = 0; i < 5; i++) { setTimeout(() => { console.log(i); }, i * 1000); }花一秒钟考虑一下上面的代码片段可能会发生什么。它不会在每个数字之间延迟一秒钟打印数字 0 到 4。相反,你实际上会得到五个 4,它们在四秒后一次性全部打印出来。为什么呢?因为循环不会暂停执行。它不会等待 setTimeout 完成才进入下一次迭代。
function greet(){ alert('Howdy!'); } setTimeout(greet, 2000);它可以是一个指向函数的变量(函数表达式):
const greet = function(){ alert('Howdy!'); }; setTimeout(greet, 2000);或者它可以是一个匿名函数(在这种情况下是箭头函数):
// 堆代码 duidaima.com setTimeout(() => { alert('Howdy!'); }, 2000);也可以将一段代码字符串传递给 setTimeout 以供其执行:
3.它比替代方案慢,因为它必须调用JS解释器
function pollDOM () { const el = document.querySelector('my-element'); if (el.length) { // Do something with el } else { setTimeout(pollDOM, 300); // try again in 300 milliseconds } } pollDOM();这假设该元素最终会出现。如果你不确定这是否会发生,你需要考虑取消计时器(使用 clearTimeout 或 clearInterval)。
let delay = 1000; // 从1秒的延迟开始 for (let i = 0; i < 5; i++) { setTimeout(() => { console.log(`这是消息 ${i + 1}`); }, delay); delay += 1000; // 每次迭代延迟增加1秒 }在这个示例中,第一条消息将在1秒后出现,第二条消息在2秒后,依此类推,直到第五条消息在5秒后。这种方法的优点是它不阻塞,易于实现,并且不需要了解 promises 或 async/await。然而,它不适用于需要精确计时或错误处理的复杂异步操作
(async () => { const res = await fetch(`https://api.github.com/users/jameshibbard`); const json = await res.json(); console.log(json.public_repos); console.log('Hello!'); })();现在,代码从上到下执行。JavaScript 解释器等待网络请求完成,首先记录公共仓库的数量,然后记录“Hello!”消息。
function sleep(milliseconds) { const date = Date.now(); let currentDate = null; do { currentDate = Date.now(); } while (currentDate - date < milliseconds); } console.log('Hello'); sleep(2000); console.log('World!');正如预期的那样,这将在控制台上打印“Hello”,暂停两秒,然后打印“World!”
function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } console.log('Hello'); sleep(2000).then(() => { console.log('World!'); });这段代码将在控制台上打印“Hello”,等待两秒,然后打印“World!”在底层,我们使用setTimeout 方法在给定的毫秒数后解析一个 promise。
function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } async function delayedGreeting() { console.log('Hello'); await sleep(2000); console.log('World!'); await sleep(2000); console.log('Goodbye!'); } delayedGreeting();这看起来更好看,但这意味着使用 sleep 函数的任何代码都需要被标记为 async。当然,这两种方法仍然有一个缺点(或特点),那就是它们不会暂停整个程序的执行。只有你的函数会睡眠:
function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } async function delayedGreeting() { console.log('Hello'); await sleep(2000); // await只暂停当前的异步函数 console.log('World!'); } delayedGreeting(); console.log('Goodbye!');上面的代码会依次打印出:
Hello Goodbye! World!这样,你可以根据需要灵活地使用不同的方法和技术来实现JavaScript中的延迟和异步操作。
console.log('Hello'); setTimeout(() => { console.log('World!'); }, 2000);👍 优点:容易理解,非阻塞。 👎 缺点:对异步操作的控制有限。 📝 何时使用:适用于简单的、一次性的延迟,或基础轮询。
setTimeout(() => { console.log('Hello'); }, 1000); setTimeout(() => { console.log('World!'); }, 2000);👍 优点:非阻塞性,易于实现,不需要了解 promises 或 async/await。 👎 缺点:不适用于复杂的异步操作。没有错误处理。 📝 何时使用:用于有时间间隔的简单序列。
console.log('Hello'); const date = Date.now(); let currentDate = null; do { currentDate = Date.now(); } while (currentDate - date < 2000); console.log('World!');👍 优点:模仿传统的sleep行为。 👎 缺点:阻塞整个线程,可能会冻结UI或导致程序崩溃。 ⚠️ 强烈不推荐:只有在你绝对需要暂停执行并且意识到其中的风险时才使用。
const sleep = function(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } console.log('Hello'); sleep(2000).then(() => { console.log('World!'); });👍 优点:非阻塞性,对异步操作有更多的控制。 👎 缺点:需要理解promises。更长的promise链可能会变得有点混乱。 📝 何时使用:当你需要更多对时间和异步操作的控制时。
function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } async function delayedGreeting() { console.log('Hello'); await sleep(2000); console.log('World!'); await sleep(2000); console.log('Goodbye!'); } delayedGreeting();👍 优点:语法清晰,易于阅读,非阻塞。 👎 缺点:需要理解async/await和promises。需要在模块外部“包装”函数。 ✅ 强烈推荐:这是最现代和干净的方法,尤其是在处理多个异步操作时。