js异步

简介: js异步

JavaScript 中的异步(Asynchronous)是处理耗时操作(如网络请求、文件读写、定时器等)的核心机制,它允许程序在等待这些操作完成时继续执行其他任务,而非阻塞主线程。这对于保证页面流畅性(避免 UI 卡顿)至关重要。

一、为什么需要异步?

JavaScript 是单线程语言(同一时间只能执行一段代码),如果直接执行耗时操作(如等待服务器响应),会导致主线程阻塞,页面出现“假死”(无法点击、滚动等)。
异步机制通过“先注册任务,后续回调执行”的方式,解决了单线程的阻塞问题。

二、异步的三种实现方式

1. 回调函数(Callback)

最早的异步实现方式,通过将后续操作定义为函数,作为参数传递给异步任务,任务完成后自动调用。

示例:定时器回调

console.log('开始');

// 异步任务:1秒后执行回调函数
setTimeout(function callback() {
   
  console.log('定时器完成');
}, 1000);

console.log('结束'); // 先执行,不会等待定时器

输出顺序

开始
结束
定时器完成  // 1秒后执行

问题:多层嵌套时会产生“回调地狱”(Callback Hell),代码可读性差。

// 回调地狱示例(多层嵌套)
fetchData1(function(data1) {
   
  fetchData2(data1, function(data2) {
   
    fetchData3(data2, function(data3) {
   
      // 更多嵌套...
    });
  });
});

2. Promise(ES6 新增)

解决回调地狱问题,通过链式调用(then())组织异步代码,使流程更清晰。

Promise 三种状态

  • pending(进行中):初始状态。
  • fulfilled(已成功):操作完成,调用 resolve() 触发。
  • rejected(已失败):操作出错,调用 reject() 触发。

示例:用 Promise 处理异步请求

// 定义一个返回 Promise 的异步函数
function fetchData() {
   
  return new Promise((resolve, reject) => {
   
    // 模拟网络请求(1秒后返回数据)
    setTimeout(() => {
   
      const success = true;
      if (success) {
   
        resolve({
    name: '鸿蒙', version: '4.0' }); // 成功时返回数据
      } else {
   
        reject(new Error('请求失败')); // 失败时返回错误
      }
    }, 1000);
  });
}

// 调用异步函数(链式调用)
fetchData()
  .then(data => {
   
    console.log('数据:', data);
    return data.version; // 可将结果传递给下一个 then
  })
  .then(version => {
   
    console.log('版本号:', version);
  })
  .catch(error => {
   
    console.error('出错:', error.message); // 捕获所有错误
  })
  .finally(() => {
   
    console.log('无论成功失败都会执行');
  });

优势:扁平化链式调用,避免嵌套;catch() 统一处理错误。

3. async/await(ES7 新增)

基于 Promise 的语法糖,用同步代码的形式编写异步逻辑,可读性更强。

使用规则

  • async 修饰函数:函数返回值自动包装为 Promise。
  • await 修饰 Promise:暂停执行,等待 Promise 完成后再继续。
  • await 只能在 async 函数中使用。

示例:用 async/await 重写上面的代码

// 复用上面定义的 fetchData()(返回 Promise)
async function handleData() {
   
  try {
   
    console.log('开始请求');
    const data = await fetchData(); // 等待 Promise 完成
    console.log('数据:', data);

    const version = data.version;
    console.log('版本号:', version);
  } catch (error) {
   
    console.error('出错:', error.message); // 捕获错误
  } finally {
   
    console.log('处理结束');
  }
}

// 调用异步函数
handleData();

优势:代码结构与同步逻辑一致,最接近自然语言,易于理解和调试。

三、异步执行顺序:事件循环(Event Loop)

JavaScript 异步代码的执行依赖事件循环机制,核心流程:

  1. 同步任务:直接在主线程执行,执行完立即返回。
  2. 异步任务
    • 放入“任务队列”(分为宏任务队列和微任务队列)。
    • 主线程空闲时,优先执行所有微任务,再执行一个宏任务,反复循环。

常见任务类型

  • 宏任务setTimeoutsetIntervalDOM 事件网络请求等。
  • 微任务Promise.then/catch/finallyasync/awaitqueueMicrotask等。

执行顺序示例

console.log('1(同步)');

setTimeout(() => {
   
  console.log('2(宏任务)');
}, 0);

Promise.resolve().then(() => {
   
  console.log('3(微任务)');
});

console.log('4(同步)');

输出顺序

1(同步)
4(同步)
3(微任务)  // 同步任务执行完后,先清空调用微任务
2(宏任务)  // 微任务执行完后,执行一个宏任务

四、实际开发中的异步场景

  1. 网络请求:用 fetchaxios(基于 Promise)获取后端数据。

    async function getUsers() {
         
      const response = await fetch('https://api.example.com/users');
      const users = await response.json(); // 解析 JSON(也是异步)
      console.log(users);
    }
    
  2. 文件操作:浏览器中读取本地文件(如 FileReader)。

    function readFileAsync(file) {
         
      return new Promise((resolve, reject) => {
         
        const reader = new FileReader();
        reader.onload = () => resolve(reader.result); // 成功回调
        reader.onerror = () => reject(reader.error); // 失败回调
        reader.readAsText(file); // 异步读取文件
      });
    }
    
  3. 定时器:延迟执行或定期执行任务(如轮询接口)。

    // 轮询数据(每3秒一次)
    async function pollData() {
         
      while (true) {
         
        await fetchData(); // 等待本次请求完成
        await new Promise(resolve => setTimeout(resolve, 3000)); // 等待3秒
      }
    }
    

总结

  • 异步核心:避免单线程阻塞,提高程序响应速度。
  • 实现方式:从回调函数→Promise→async/await,逐步优化可读性和易用性,推荐优先使用 async/await
  • 关键机制:事件循环决定异步任务的执行顺序,记住“先微任务,后宏任务”。

掌握异步是 JavaScript 进阶的关键,尤其在处理网络请求、定时器等场景时不可或缺。

目录
相关文章
设置VSCode代码编辑器右侧的Minimap代码缩略图滚动条切换显示、隐藏的快捷键Alt+M
设置VSCode代码编辑器右侧的Minimap代码缩略图滚动条切换显示、隐藏的快捷键Alt+M
|
XML JSON JavaScript
如何在js中,读取json文件?
如何在js中,读取json文件?
|
存储 前端开发 JavaScript
实现一个简单的JavaScript日期选择器
实现一个简单的JavaScript日期选择器
|
Web App开发 开发者
利用chrome控制台调试post请求
利用chrome控制台调试post请求
1141 0
|
JSON JavaScript 前端开发
JavaScript读取本地json文件方式
JavaScript读取本地json文件方式
|
并行计算 前端开发 JavaScript
Web Worker:让前端飞起来的隐形引擎
在现代 Web 开发中,前端性能优化是一个至关重要的课题,尤其是对于计算密集型的应用,如图像处理、视频处理、大规模数据分析等任务。单线程的 JavaScript 引擎常常成为性能瓶颈,导致应用变得迟缓。Web Worker,作为一种强大的技术,使得前端能够在后台进行并行计算,从而实现高效的任务处理,不影响主线程的运行和用户的交互体验。
909 108
|
数据库 对象存储
2025年 | 5月云大使推广奖励规则
【近期云大使规则升级】①上线老用户返佣规则。②企业云大使提现功能上线。③优化推广奖励限制。④调整用户关联周期。⑤新增沉睡用户返利 。⑥推荐企业认证新用户首购最高奖励45%。
|
存储 NoSQL JavaScript
Node.js导入MongoDB具体操作指南
通过本文,您已经学会了如何在Node.js中导入MongoDB并执行基本的CRUD操作。Node.js与MongoDB的结合使得构建高效、可扩展的后端服务变得更加容易。通过遵循本文的步骤,您可以快速设置并运行一个强大的数据存储和处理系统。希望这篇指南能为您的开发工作提供实用的帮助。
465 13
|
网络协议 网络架构
【IP协议】IP协议报头结构
【IP协议】IP协议报头结构
422 2