面试必考:从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应用程序。

相关推荐
文西2952 小时前
this函数的指向问题
javascript
有点笨的蛋2 小时前
JavaScript Promise 机制解析
前端·javascript
程序员爱钓鱼3 小时前
Python编程实战 - Python实用工具与库 - 正则表达式匹配(re 模块)
后端·python·面试
程序员爱钓鱼3 小时前
Python编程实战 - Python实用工具与库 - 爬取并存储网页数据
后端·python·面试
绝无仅有3 小时前
某团互联网大厂的网络协议与数据传输
后端·面试·架构
绝无仅有3 小时前
某多多面试相关操作系统、分布式事务、消息队列及 Linux 内存回收策略
后端·面试·架构
不一样的少年_4 小时前
【前端效率工具】再也不用 APIfox 联调!零侵入 Mock,全程不改代码、不开代理
前端·javascript·浏览器
艾小码4 小时前
Vue组件通信不再难!这8种方式让你彻底搞懂父子兄弟传值
前端·javascript·vue.js
lcc1874 小时前
Vue 数据代理
前端·javascript·vue.js