面试必考:从setTimeout到Promise和fetch

前言

JavaScript是一种单线程语言,这意味着它一次只能执行一个任务。这种设计简化了编程模型,但也带来了挑战:如何处理耗时操作而不阻塞主线程?

一、 异步编程基础

1.同步 vs 异步执行

arduino 复制代码
// 同步代码示例
console.log(1);
console.log(2);
console.log(3);
// 输出顺序:1 2 3

2.异步代码示例

javascript 复制代码
console.log(1);
setTimeout(function() {
  console.log(2);
}, 1000);
console.log(3);
// 输出顺序:1 3 2(1秒后)

其中setTimeout是一个延迟函数,设定在一秒后执行,所以改变了原有的代码执行顺序

3.事件循环机制

JavaScript通过事件循环机制处理异步操作:

  1. 同步代码立即执行
  2. 异步代码被放入事件队列
  3. 当调用栈为空时,事件队列中的任务按顺序执行

二、Promise:异步编程的解决方案

1.Promise基本用法

javascript 复制代码
const promise = new Promise((resolve, reject) => {
  // 异步操作代码
  // 成功时调用 resolve(value)
  // 失败时调用 reject(error)
});

2. 示例

javascript 复制代码
console.log(1);
const p = new Promise((resolve) => {
  setTimeout(function() {
    console.log(2);
    resolve();
  }, 3000);
});
p.then(() => {
  console.log(3);
});
console.log(4);
// 输出顺序:1 4 2 3

3.Promise处理文件读取

javascript 复制代码
import fs from 'fs';

console.log(1);

const p = new Promise((resolve, reject) => {
  console.log(3); // 同步执行
  
  fs.readFile('./a.txt', function(err, data) {
    if (err) {
      reject(err);
      return;
    }
    resolve(data.toString());
  });
});

p.then(data => {
  console.log(data);
}).catch(err => {
  console.log(err);
});

console.log(4);
// 输出顺序:1 3 4 [文件内容]

注意:被Promise实例包裹的同步代码并不会延时触发,而是正常按照顺序执行

三、fetch API:网络请求

javascript 复制代码
// 基本用法
fetch("https://api.github.com/orgs/lemoncode/members")
  .then((response) => response.json())
  .then((data) => {
    // 处理数据
    console.log(data);
  })
  .catch((error) => {
    console.error('Error:', error);
  });

实际应用示例

xml 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>GitHub Members</title>
</head>
<body>
  <ul id="members"></ul>
  <script>
    fetch("https://api.github.com/orgs/lemoncode/members")
      .then((response) => response.json())
      .then((members) => {
        const membersList = document.getElementById("members");
        membersList.innerHTML = members
          .map((member) => {
            return `<li>${member.login}</li>`;
          })
          .join("");
      })
      .catch((error) => {
        console.error('Error fetching members:', error);
      });
  </script>
</body>
</html>

异步编程最佳实践

1. 错误处理

go 复制代码
// 使用catch处理Promise错误
someAsyncFunction()
  .then(result => {
    // 处理成功结果
  })
  .catch(error => {
    // 处理错误
    console.error('An error occurred:', error);
  });

2. 并行执行多个异步操作

less 复制代码
// 使用Promise.all同时执行多个异步操作
Promise.all([
  fetch('/api/users'),
  fetch('/api/posts'),
  fetch('/api/comments')
])
.then(([users, posts, comments]) => {
  // 所有请求都完成后执行
})
.catch(error => {
  // 任何一个请求失败都会进入这里
});

3. async/await语法糖

vbnet 复制代码
// 使用async/await使异步代码更易读
async function fetchData() {
  try {
    const response = await fetch('/api/data');
    const data = await response.json();
    return data;
  } catch (error) {
    console.error('Error fetching data:', error);
  }
}

总结

JavaScript的异步编程模型虽然初看起来复杂,但理解其核心概念后,可以编写出高效、非阻塞的代码。关键要点包括:

  • JavaScript是单线程的,使用事件循环处理异步操作
  • setTimeout是基础的异步机制
  • Promise提供了更强大的异步控制能力
  • fetch是处理网络请求的现代API
  • async/await语法让异步代码更易读

掌握这些概念和工具,将帮助你编写更高效、更可靠的JavaScript应用程序。

相关推荐
Hilaku28 分钟前
我用 Gemini 3 Pro 手搓了一个并发邮件群发神器(附源码)
前端·javascript·github
UrbanJazzerati30 分钟前
统计学的"测谎仪":一文搞懂方差、标准差与“N-1”的秘密
面试
全栈前端老曹39 分钟前
【包管理】npm init 项目名后底层发生了什么的完整逻辑
前端·javascript·npm·node.js·json·包管理·底层原理
HHHHHY1 小时前
mathjs简单实现一个数学计算公式及校验组件
前端·javascript·vue.js
顾林海1 小时前
Android文件系统安全与权限控制:给应用数据上把“安全锁”
android·面试·操作系统
青莲8431 小时前
Android 动画机制完整详解
android·前端·面试
iReachers1 小时前
HTML打包APK(安卓APP)中下载功能常见问题和详细介绍
前端·javascript·html·html打包apk·网页打包app·下载功能
愈努力俞幸运1 小时前
vue3 demo教程(Vue Devtools)
前端·javascript·vue.js
持续前行1 小时前
在 Vue3 中使用 LogicFlow 更新节点名称
前端·javascript·vue.js
Anita_Sun1 小时前
Underscore.js 整体设计思路与架构分析
前端·javascript