欢迎来到异步 JavaScript 的精彩世界!在 Web 开发领域中,响应速度和用户体验至关重要,理解和掌握异步编程的力量是必不可少的。异步 JavaScript,通常称为 async JavaScript,使我们能够执行代码而不阻塞主线程,确保操作流畅高效。
在本博客中,我们将深入探讨异步 JavaScript 的概念和技术。我们将探索异步编程如何通过允许多个任务同时运行来提高 Web 应用程序的性能和响应速度。无论你是初学者想要掌握基本原理,还是经验丰富的开发人员寻求高级策略,本指南都将为你提供知识和工具,使你的 JavaScript 代码更加高效、可扩展和用户友好。
我们将揭开异步 JavaScript 的神秘面纱,揭秘回调、Promise 和 async/await 等概念,并揭示实用案例和最佳实践。本博客可能有点长,请耐心等待,你会喜欢的✌️!
- Promise 在 JavaScript 中,Promise 是表示异步操作最终完成或失败的对象。它实际上是一个返回的对象,你可以将回调函数附加到它上面,而不是将回调函数传递到一个函数中。
let promise = new Promise((resolve, reject) => {
let flag = false;
let n = 7;
for(let i = 1; i <= 7; i++)
if(n % i === 0)
flag = true;
// if no is is prime
// After 1 second, check the condition and resolve or reject the promise
setTimeout(() => {
if (flag) {
resolve('Promise fulfilled!');
} else {
reject('Promise rejected!');
}
}, 1000);
});
// Attach then() and catch() handlers to the Promise
promise
.then(value => {
// This will be executed if the promise is resolved
console.log(value); // Output: Promise fulfilled!
})
.catch(error => {
// This will be executed if the promise is rejected
console.log(error);
});
在此示例中,创建了一个 Promise,它将根据 condition 的值在 1 秒后解决或拒绝。如果 Promise 成功,将调用 <em>resolve</em>
函数,如果 Promise 失败,则调用 reject 函数。
当 Promise 解决时,将调用 <em>then</em>
方法并接收传递给 resolve 函数的值。类似地,当 Promise 被拒绝时,将调用 catch 方法并接收传递给 reject 函数的值。
2. setTimeout
在此问题中,setTimeout
函数起着关键作用。它是一种方法,可以在指定的毫秒数后调用函数或计算表达式。在 JavaScript 中,setTimeout 用于延迟执行一段代码。
console.log("Starting the timer...");
setTimeout(() => {
console.log("Timeout completed!");
}, 2000);
在我们的示例中,回调函数是一个简单的箭头函数,将“Timeout completed!”记录到控制台。我们将延迟设置为 2000 毫秒,相当于 2 秒。但是,重要的是要注意,JavaScript 运行时不会在继续执行下一行代码之前等待此延迟。相反,它继续执行后续指令,展示了 JavaScript 的非阻塞特性。
一旦指定的延迟时间已过(在本例中为 2 秒),回调函数就会被添加到任务队列中。但是,重要的是要理解,回调函数的执行可能不会立即发生在延迟之后。由于 JavaScript 的事件驱动性和单线程事件循环,实际执行可能会有轻微延迟。这种延迟是由运行时处理排队在回调函数之前的其他任务所导致的。
考虑到主 JavaScript 线程正在执行长时间操作的情况。在这种情况下,即使计时器已完成其后台任务,回调函数仍必须等待阻塞操作完成。事件循环一次只能处理一个任务,并按照它们排队的顺序处理任务。
因此,重要的是将 setTimeout 中指定的“2 秒”解释为在调用回调函数之前的最短延迟时间,而不是保证的延迟时间。如果 JavaScript 运行时正在处理其他任务,则回调函数的执行可能需要比 2 秒更长的时间。这种行为强调了理解 JavaScript 异步性质的重要性,因为它可以显著影响代码的性能和行为。
此外,JavaScript 提供了一个有用的函数 clearTimeout,它可以取消之前使用 setTimeout 建立的超时。在自然发生回调函数之前,使用 clearTimeout 很方便地防止回调函数的执行。
console.log("lets start");
// setTimeout returns a Timeout object which can be used to reference the timer
let timeoutId = setTimeout(() => {
console.log("Timeout completed!");
}, 2000);
// Some condition or logic
if (/* some condition */) {
// Cancels the timeout
clearTimeout(timeoutId);
}
总之,这个例子突显了 JavaScript 的非阻塞行为,以及 setTimeout 和事件循环如何实现异步执行。理解和有效地利用 JavaScript 中的异步编程可以大大提高代码的响应速度和效率。
文章有点长了,但是考虑到 JavaScript 的性质,我们能做什么呢……稍微再耐心一点,等一会儿吧😊……
3. JavaScript 的事件循环
事件循环充当监督员,确保 JavaScript 能够有效地处理异步任务。它跟踪调用栈和任务队列。每当调用栈为空时,它就从任务队列中获取下一个任务并执行它。这个过程允许 JavaScript 无缝处理异步操作,而不阻塞主线程。
- 异步回调
JavaScript 通过利用异步代码执行来处理并发操作。
- 当遇到异步操作(例如 setTimeout 或 fetch)时,JavaScript 设置它并继续执行其余代码,而不等待操作完成。
- 异步操作在与主 JavaScript 线程分开的后台中运行。一旦异步操作完成,它的回调函数就会被放置在任务队列中。
- 事件循环不断检查调用栈是否为空。当它为空时,事件循环从任务队列中获取第一个任务,并将其推入调用栈以进行立即执行。
- 这个过程不断重复,使 JavaScript 能够处理多个操作,尽管它是单线程的。 为了在代码执行中引入延迟,可以使用 Promise 和 setTimeout 创建一个“sleep”函数。该函数返回一个 Promise,该 Promise 在指定的延迟后解决,模拟代码执行的延迟。
JavaScript 提供了 async 和 await 关键字,以简化使用 Promise 的工作。通过将函数声明为 async,当调用它时,它会返回一个 Promise。异步函数可以使用 await 暂停执行,直到 Promise 被满足,使异步代码看起来和行为更像同步代码。
在 Web 页面场景中,如果需要在单击按钮时从服务器加载数据,则必须异步处理请求,以避免冻结整个页面。目标是允许页面保持响应,而不是等待服务器的响应。可以使用此类异步技术来实现…
// The 'async' keyword allows the use of 'await' inside the function
button.addEventListener('click', async () => {
// Show a loading spinner
preloader.style.display = 'block';
try {
// Fetch data from server
let response = await fetch('https://api.icons/preloader');
// Parse the JSON response
let items = await response.json();
// Update the UI with the new items
displayItems(items);
} catch (error) {
// Handle any errors
console.error('Error:', error);
} finally {
// Hide the loading spinner
preloader.style.display = 'none';
}
});
5. Async/await
通过提供更简单的语法,Async/await 简化了编写和理解异步代码。它允许我们暂停代码执行,直到 Promise 被解决,消除了冗长的 .then() 和 .catch() 链。这使得代码更易读,并有助于更简洁地处理错误。
// Using explicit .then() and .catch() with promises
fetchData()
.then(res => {
// Handle the response
return processData(res);
})
.then(ress => {
// Handle the processed data
})
.catch(err => {
// Handle any errors
});
//more readable code
// Using async/await
async function nirbhayKumar() {
try {
const response = await fetchData();
console.log("Response:", response);
const result = await processData(response);
console.log("Processed data:", result);
} catch (error) {
console.error("Error:", error);
}
}
nirbhayKumar();
在第一种方法中,使用 .then() 链接 Promise 来处理响应并按顺序处理数据。如果发生任何错误,则在 .catch() 块中捕获并处理它们。第二种方法使用了 async/await 语法,使得代码看起来更像同步的并且更易于跟踪。在 async 函数中,使用 await 关键字暂停执行直到 promises 被解析。这允许代码执行的线性流程,类似于传统的同步编程。任何出现的错误都在 try-catch 块中被捕获和处理。
6. Promise 链接
Promise 链接是 JavaScript 中用于顺序执行多个异步操作的一种技术。它有助于避免嵌套的回调函数并提高代码的可读性。链中的每个 then
接收前一个 promise 的结果,使得步骤之间的数据流动容易。如果链中的 promise 被拒绝,后续的 then
方法将被跳过,直到遇到一个 catch
方法。
fetchData()
.then(responseData => {
console.log("Response:", responseData);
return processData(responseData); // This returns a new promise
})
.then(processedData => {
console.log("Processed data:", processedData);
return furtherProcessing(processedData); // This returns another new promise
})
.then(finalResult => {
console.log("Final result:", finalResult);
})
.catch(error => {
console.error("Error:", error);
});
fetchData
、processData
和 furtherProcessing
都是返回 promises 的异步函数。then
方法被链接在一起,每个 then
等待前一个 promise 解析后开始其操作。如果链中的任何 promise 被拒绝,最后的 catch 方法将被调用来处理错误。
7**. finally 的重要性**
在 JavaScript 中,.finally
方法是 Promise 的一个强大功能。它允许你指定代码,无论 Promise 是否被完成或拒绝都将被执行。这使得它对于清理操作或应始终执行的任务非常有用,无论 Promise 的结果如何。
let onload = true;
fetch('https://api/github/user/nirbhay97')
.then(res => {
if (!res.ok) {
throw new Error('Network response was not ok');
}
return response.json();
})
.then(data => console.log(data.public_repos))
.catch(error => console.error('Error:', error))
.finally(() => {
onload = false;
console.log('Fetch operation finished');
});
我们在这里使用 fetch(返回一个 Promise)来检索在 GitHub 上 nirbhay97 用户名拥有的公共存储库的计数。然后我们使用 .then
来处理响应,并使用 .catch
来处理任何错误。最后,无论 fetch 操作成功与否,.finally
都被调用以将 isload 设置为 false 并在控制台中记录一条消息。
太好了,你终于释放了异步 JS 的力量,我相信这将有助于优化你的应用程序,再次阅读更多博客,我承诺,你不需要等待。如果你喜欢,就点赞。再见👋👋
评论(0)