首页
Preview

异步 JavaScript 的艺术:释放非阻塞代码的力量!

欢迎来到异步 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 无缝处理异步操作,而不阻塞主线程。

  1. 异步回调

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);
  });

fetchDataprocessDatafurtherProcessing 都是返回 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 的力量,我相信这将有助于优化你的应用程序,再次阅读更多博客,我承诺,你不需要等待。如果你喜欢,就点赞。再见👋👋

译自:https://medium.com/@nirbhaykumar5572/the-art-of-asynchronous-javascript-unleashing-the-power-of-non-blocking-code-f38782646df4

版权声明:本文内容由TeHub注册用户自发贡献,版权归原作者所有,TeHub社区不拥有其著作权,亦不承担相应法律责任。 如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

点赞(0)
收藏(0)
一个人玩
先找到想要的,然后出发

评论(0)

添加评论