JavaScript中的异步操作详解

JavaScript中的同步与异步

JavaScript是单线程语言,但它的执行机制包含同步和异步两种方式

同步执行

  • 代码按照编写顺序一行一行执行
  • 前一个任务执行完才能执行下一个任务
  • 如果某个任务耗时很长,会阻塞后续代码执行

异步执行

  • 不会阻塞代码继续执行

常见的默认异步操作:

  1. 网络请求(Ajax、Fetch)
  2. 文件操作
  3. 定时器(setTimeout、setInterval)
  4. 事件监听

异步操作分类表

操作类型 默认行为 可否改为同步 推荐方式
Ajax (XMLHttpRequest) 异步 是(不推荐) 保持异步,使用Promise封装
Fetch 异步 使用async/await
定时器 (setTimeout/setInterval) 异步 Promise封装 + async/await
事件监听 异步 Promise封装 + async/await
文件操作(Node.js) 异步 是(不推荐) 使用异步方法 + async/await
DOM操作 同步 - 批量处理,使用requestAnimationFrame
普通计算 同步 - 大量计算考虑Web Worker

示例代码

  1. Ajax操作对比:
// 同步Ajax(不推荐)
const xhr = new XMLHttpRequest();
xhr.open('GET', '/api/data', false); // false表示同步
xhr.send();
console.log(xhr.responseText); // 阻塞直到接收到响应

// 异步Ajax(推荐)
// Promise封装
function ajaxPromise(url) {
    
    
    return new Promise((resolve, reject) => {
    
    
        const xhr = new XMLHttpRequest();
        xhr.open('GET', url);
        xhr.onload = () => resolve(xhr.responseText);
        xhr.onerror = () => reject(xhr.statusText);
        xhr.send();
    });
}

// 使用async/await
async function getData() {
    
    
    try {
    
    
        const data = await ajaxPromise('/api/data');
        console.log(data);
    } catch (error) {
    
    
        console.error('请求失败:', error);
    }
}
  1. 定时器操作:
// 原始定时器(异步)
setTimeout(() => {
    
    
    console.log('3秒后执行');
}, 3000);

// Promise封装(推荐)
function delay(ms) {
    
    
    return new Promise(resolve => setTimeout(resolve, ms));
}

// 使用async/await
async function delayedOperation() {
    
    
    console.log('开始');
    await delay(3000);
    console.log('3秒后执行');
}
  1. 事件监听:
// 传统方式
button.addEventListener('click', () => {
    
    
    console.log('点击了按钮');
});

// Promise封装(单次事件)
function waitForClick(element) {
    
    
    return new Promise(resolve => {
    
    
        element.addEventListener('click', resolve, {
    
     once: true });
    });
}

// 使用async/await
async function handleUserInteraction() {
    
    
    console.log('等待点击');
    await waitForClick(button);
    console.log('按钮被点击了');
}
  1. 文件操作(Node.js):
// 同步方式(不推荐)
const fs = require('fs');
const data = fs.readFileSync('file.txt', 'utf8');
console.log(data);

// 异步方式(推荐)
const fsPromises = require('fs').promises;

async function readFile() {
    
    
    try {
    
    
        const data = await fsPromises.readFile('file.txt', 'utf8');
        console.log(data);
    } catch (error) {
    
    
        console.error('读取失败:', error);
    }
}

异步操作管理最佳实践

  1. 并行操作处理:
// 多个异步操作并行执行
async function parallel() {
    
    
    try {
    
    
        const [users, posts, comments] = await Promise.all([
            fetch('/api/users'),
            fetch('/api/posts'),
            fetch('/api/comments')
        ]);
        return {
    
    
            users: await users.json(),
            posts: await posts.json(),
            comments: await comments.json()
        };
    } catch (error) {
    
    
        console.error('并行请求失败:', error);
    }
}
  1. 错误重试机制:
async function fetchWithRetry(url, maxRetries = 3) {
    
    
    for (let i = 0; i < maxRetries; i++) {
    
    
        try {
    
    
            return await fetch(url);
        } catch (error) {
    
    
            if (i === maxRetries - 1) throw error;
            // 指数退避
            await new Promise(resolve => 
                setTimeout(resolve, Math.pow(2, i) * 1000)
            );
        }
    }
}
  1. 取消操作:
// 使用AbortController
async function fetchWithTimeout(url, timeout = 5000) {
    
    
    const controller = new AbortController();
    const timeoutId = setTimeout(() => controller.abort(), timeout);
    
    try {
    
    
        const response = await fetch(url, {
    
    
            signal: controller.signal
        });
        clearTimeout(timeoutId);
        return await response.json();
    } catch (error) {
    
    
        if (error.name === 'AbortError') {
    
    
            throw new Error('请求超时');
        }
        throw error;
    }
}
  1. 状态管理:
class AsyncOperation {
    
    
    constructor() {
    
    
        this.state = 'idle'; // idle, loading, success, error
        this.data = null;
        this.error = null;
    }

    async execute(promise) {
    
    
        this.state = 'loading';
        try {
    
    
            this.data = await promise;
            this.state = 'success';
            return this.data;
        } catch (error) {
    
    
            this.error = error;
            this.state = 'error';
            throw error;
        }
    }
}

// 使用示例
const operation = new AsyncOperation();
await operation.execute(fetch('/api/data'));

建议和注意事项

  1. 异步操作原则:

    • 默认使用异步方式
    • 避免同步阻塞操作
    • 合理使用并行处理
  2. 错误处理:

    • 始终包含try/catch
    • 实现错误重试机制
    • 提供友好的错误提示
  3. 性能优化:

    • 使用Promise.all并行处理
    • 实现请求缓存
    • 添加超时控制
    • 考虑取消机制
  4. 代码组织:

    • 使用async/await简化代码
    • 抽象通用的异步操作
    • 统一错误处理方式

猜你喜欢

转载自blog.csdn.net/qq_20236937/article/details/146174006
今日推荐