异步编程 
题目1: 什么是回调函数?如何避免回调地狱? 
答案: 回调函数是作为参数传递给另一个函数的函数,它在某个操作完成后被调用。回调地狱是指多层嵌套的回调函数,使得代码难以阅读和维护。
避免回调地狱的方法:
- 使用 Promise
- 使用 async/await
- 模块化和函数命名
- 使用控制流程库(如 async.js)
扩展:
javascript
// 回调地狱示例
getData(function(a) {
    getMoreData(a, function(b) {
        getMoreData(b, function(c) {
            getMoreData(c, function(d) {
                getMoreData(d, function(e) {
                    // ...
                });
            });
        });
    });
});
// 使用 Promise 改写
getData()
    .then(a => getMoreData(a))
    .then(b => getMoreData(b))
    .then(c => getMoreData(c))
    .then(d => getMoreData(d))
    .then(e => {
        // ...
    })
    .catch(error => {
        // 错误处理
    });题目2: Promise 的基本用法和状态有哪些? 
答案: Promise 是异步编程的一种解决方案,比传统的回调函数更加优雅。
Promise 的基本用法:
javascript
const promise = new Promise((resolve, reject) => {
    // 异步操作
    if (/* 操作成功 */) {
        resolve(value);
    } else {
        reject(error);
    }
});
promise.then(value => {
    // 成功的回调
}).catch(error => {
    // 失败的回调
});Promise 有三种状态:
- Pending(进行中)
- Fulfilled(已成功)
- Rejected(已失败)
扩展: Promise 的状态一旦改变,就不会再变。这也就是 Promise 名字的由来,它的英语意思是"承诺",表示其状态的不可逆性。
题目3: async/await 的工作原理是什么? 
答案: async/await 是建立在 Promise 之上的语法糖,让异步代码看起来像同步代码。
- async函数返回一个 Promise 对象
- await关键字只能在- async函数内部使用
- await会暂停函数的执行,等待 Promise 解决
扩展:
javascript
async function fetchData() {
    try {
        const response = await fetch('https://api.example.com/data');
        const data = await response.json();
        console.log(data);
    } catch (error) {
        console.error('Error:', error);
    }
}题目4: 如何处理异步错误? 
答案: 处理异步错误的主要方法有:
- 使用 Promise 的 .catch()方法
- 在 async/await 中使用 try/catch 块
- 使用 Promise.all()的错误处理
- 全局的未捕获 Promise 错误处理
扩展:
javascript
// Promise 错误处理
promise
    .then(result => {
        // 处理结果
    })
    .catch(error => {
        console.error('Error:', error);
    });
// async/await 错误处理
async function fetchData() {
    try {
        const data = await getData();
        // 处理数据
    } catch (error) {
        console.error('Error:', error);
    }
}
// 全局未捕获 Promise 错误处理
window.addEventListener('unhandledrejection', event => {
    console.error('Unhandled rejection:', event.reason);
});题目5: 什么是 Promise.all() 和 Promise.race()? 
答案:
- Promise.all()接收一个 Promise 数组作为输入,当所有 Promise 都成功时返回一个包含所有结果的数组,如果任何一个 Promise 失败,则立即返回失败的结果。
- Promise.race()同样接收一个 Promise 数组,但只要有一个 Promise 完成(无论成功或失败),就立即返回那个 Promise 的结果。
扩展:
javascript
// Promise.all() 示例
const promises = [fetch('/api/data1'), fetch('/api/data2'), fetch('/api/data3')];
Promise.all(promises)
    .then(results => {
        // 处理所有结果
    })
    .catch(error => {
        // 处理任何错误
    });
// Promise.race() 示例
const promise1 = new Promise(resolve => setTimeout(() => resolve('one'), 1000));
const promise2 = new Promise(resolve => setTimeout(() => resolve('two'), 2000));
Promise.race([promise1, promise2])
    .then(result => console.log(result)); // 输出: "one"题目6: 如何实现一个简单的 Promise? 
答案: 实现一个简单的 Promise 需要考虑状态管理、异步操作、then 方法链式调用等。以下是一个基本实现:
javascript
class MyPromise {
    constructor(executor) {
        this.state = 'pending';
        this.value = undefined;
        this.reason = undefined;
        this.onFulfilledCallbacks = [];
        this.onRejectedCallbacks = [];
        const resolve = value => {
            if (this.state === 'pending') {
                this.state = 'fulfilled';
                this.value = value;
                this.onFulfilledCallbacks.forEach(cb => cb(value));
            }
        };
        const reject = reason => {
            if (this.state === 'pending') {
                this.state = 'rejected';
                this.reason = reason;
                this.onRejectedCallbacks.forEach(cb => cb(reason));
            }
        };
        try {
            executor(resolve, reject);
        } catch (error) {
            reject(error);
        }
    }
    then(onFulfilled, onRejected) {
        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
        onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason };
        return new MyPromise((resolve, reject) => {
            if (this.state === 'fulfilled') {
                setTimeout(() => {
                    try {
                        const x = onFulfilled(this.value);
                        resolve(x);
                    } catch (error) {
                        reject(error);
                    }
                }, 0);
            }
            if (this.state === 'rejected') {
                setTimeout(() => {
                    try {
                        const x = onRejected(this.reason);
                        resolve(x);
                    } catch (error) {
                        reject(error);
                    }
                }, 0);
            }
            if (this.state === 'pending') {
                this.onFulfilledCallbacks.push(() => {
                    setTimeout(() => {
                        try {
                            const x = onFulfilled(this.value);
                            resolve(x);
                        } catch (error) {
                            reject(error);
                        }
                    }, 0);
                });
                this.onRejectedCallbacks.push(() => {
                    setTimeout(() => {
                        try {
                            const x = onRejected(this.reason);
                            resolve(x);
                        } catch (error) {
                            reject(error);
                        }
                    }, 0);
                });
            }
        });
    }
}扩展: 这个实现包含了 Promise 的基本功能,但还缺少 catch、finally 等方法,以及更复杂的错误处理和 Promise 解析过程。完整的 Promise 实现需要遵循 Promises/A+ 规范。
题目7: 什么是 Generator 函数?它与异步编程有什么关系? 
答案: Generator 函数是 ES6 引入的一种函数类型,可以被暂停和恢复执行。它们通过 yield 关键字来定义暂停点。
Generator 函数与异步编程的关系:
- 可以用于控制异步操作的流程
- 可以将异步操作变成同步的写法
- 是 async/await 的前身和基础
扩展:
javascript
function* asyncFlow() {
    const result1 = yield fetchData1();
    console.log(result1);
    const result2 = yield fetchData2(result1);
    console.log(result2);
}
function run(generator) {
    const iterator = generator();
    function handle(yielded) {
        if (!yielded.done) {
            yielded.value.then(result => handle(iterator.next(result)));
        }
    }
    handle(iterator.next());
}
run(asyncFlow);题目8: 什么是事件循环(Event Loop)? 
答案: 事件循环是 JavaScript 的执行模型,用于管理异步操作。它是一个持续运行的循环,不断地从任务队列中取出任务并执行。
事件循环的主要组成部分:
- 任务队列(Task Queue):存储待执行的任务
- 事件循环(Event Loop):不断地从任务队列中取出任务并执行
- 微任务队列(Microtask Queue):存储微任务,优先级高于宏任务
题目9: 什么是宏任务(Macro-task)和微任务(Micro-task)? 
答案: 宏任务(Macro-task)和微任务(Micro-task)是事件循环中的两种任务类型。
宏任务:
- setTimeout
- setInterval
- setImmediate
- requestAnimationFrame
微任务:
- Promise
- MutationObserver
- process.nextTick(Node.js)
扩展: 在事件循环的每个周期中,宏任务和微任务的执行顺序是有规定的:
- 执行所有微任务
- 执行一个宏任务
- 重复上述过程,直到所有任务执行完毕
扩展:
javascript
// 示例代码
console.log('start');
setTimeout(() => {
    console.log('setTimeout');
});
Promise.resolve().then(() => {
    console.log('Promise');
});
console.log('end');
// 输出顺序:start -> end -> Promise -> setTimeout