1. asynchronousprogrammingoverview

in JavaScript in, asynchronousprogramming is aprocessing非阻塞operation programming范式. 由于 JavaScript is 单thread , asynchronousprogramming允许程序 in etc.待某些operationcompletion (such asnetworkrequest, file读写, 定时器etc.) 时继续执行othercode, 而不 is 阻塞整个程序 执行.

common asynchronousoperationincluding:

  • networkrequest (AJAX, Fetch API)
  • file读写operation
  • 定时器 (setTimeout, setInterval)
  • eventprocessing
  • Promise and async/await

2. synchronization vs asynchronous

for 了更 good 地understandingasynchronousprogramming, 我们先来比较synchronization and asynchronouscode 执行方式:

2.1 synchronizationcode

synchronizationcode按照code 顺序依次执行, before 一个operationcompletion after 才会执行 under 一个operation.

console.log('开始执行'); // synchronizationoperation: 立即执行 function synchronousOperation() { console.log('synchronizationoperation执行in...'); // mock耗时operation for (let i = 0; i < 1000000000; i++) { // 空循环, mock耗时 } console.log('synchronizationoperationcompletion'); } synchronousOperation(); console.log('继续执行othercode'); // 输出顺序: // 开始执行 // synchronizationoperation执行in... // synchronizationoperationcompletion // 继续执行othercode

2.2 asynchronouscode

asynchronouscode不会阻塞程序 执行, 而 is in after 台执行, 当operationcompletion after throughcallbackfunction, Promise or async/await 来processing结果.

console.log('开始执行'); // asynchronousoperation: 不会阻塞 after 续code执行 function asynchronousOperation() { console.log('asynchronousoperation开始'); setTimeout(function() { console.log('asynchronousoperationcompletion'); }, 2000); } asynchronousOperation(); console.log('继续执行othercode'); // 输出顺序: // 开始执行 // asynchronousoperation开始 // 继续执行othercode // (2秒 after ) asynchronousoperationcompletion

3. callbackfunction

callbackfunction is 最basic asynchronousprogramming模式, 它 is a serving asparameter传递给另一个function function, 当asynchronousoperationcompletion时被调用.

3.1 basiccallback

// mockasynchronousoperation function fetchData(callback) { console.log('开始获取data...'); setTimeout(function() { const data = { name: '张三', age: 25 }; console.log('data获取completion'); callback(data); // 调用callbackfunction, 传递data }, 2000); } // 调用asynchronousfunction, 传入callback fetchData(function(data) { console.log('processing获取 to data:', data); console.log('dataprocessingcompletion'); }); console.log('继续执行othercode...'); // 输出顺序: // 开始获取data... // 继续执行othercode... // (2秒 after ) data获取completion // processing获取 to data: { name: '张三', age: 25 } // dataprocessingcompletion

3.2 callback地狱

当 many 个asynchronousoperation需要按顺序执行时, callbackfunction会嵌套 in 一起, 形成所谓 "callback地狱" (Callback Hell) , 使code难以阅读 and maintenance.

// callback地狱example function getUser(userId, callback) { setTimeout(function() { console.log('获取userinformation'); callback({ id: userId, name: '张三' }); }, 1000); } function getPosts(user, callback) { setTimeout(function() { console.log('获取user帖子'); callback([{ id: 1, title: '帖子1' }, { id: 2, title: '帖子2' }]); }, 1000); } function getComments(posts, callback) { setTimeout(function() { console.log('获取帖子评论'); callback([{ id: 1, content: '评论1' }, { id: 2, content: '评论2' }]); }, 1000); } // 嵌套 callbackfunction - callback地狱 getUser(1, function(user) { getPosts(user, function(posts) { getComments(posts, function(comments) { console.log('最终结果:', { user: user, posts: posts, comments: comments }); }); }); }); // 输出顺序: // 获取userinformation // 获取user帖子 // 获取帖子评论 // 最终结果: { ... }

4. Promise

Promise is ES6 引入 一种processingasynchronousoperation object, 它代表一个asynchronousoperation 最终completion ( or 失败) 及其结果值. Promise 可以解决callback地狱 issues, 使asynchronouscode更加清晰 and 易于maintenance.

4.1 Promise basic用法

// creation Promise const promise = new Promise(function(resolve, reject) { // asynchronousoperation setTimeout(function() { const success = true; if (success) { resolve('operation成功!'); // 成功时调用 resolve } else { reject('operation失败!'); // 失败时调用 reject } }, 2000); }); // using Promise promise .then(function(result) { console.log('成功:', result); return 'processing after 结果'; }) .then(function(processedResult) { console.log('processing:', processedResult); }) .catch(function(error) { console.log('error:', error); }) .finally(function() { console.log('operationcompletion, 无论成功 or 失败都会执行'); }); console.log('Promise creationcompletion, etc.待结果...'); // 输出顺序: // Promise creationcompletion, etc.待结果... // (2秒 after ) 成功: operation成功! // processing: processing after 结果 // operationcompletion, 无论成功 or 失败都会执行

4.2 Promise 链式调用

Promise 一个 important features is 可以链式调用, 每个 then method都返回一个 new Promise, 这使得我们可以按顺序执行 many 个asynchronousoperation, 而不需要嵌套callback.

// using Promise 重写之 before callback地狱example function getUser(userId) { return new Promise(function(resolve) { setTimeout(function() { console.log('获取userinformation'); resolve({ id: userId, name: '张三' }); }, 1000); }); } function getPosts(user) { return new Promise(function(resolve) { setTimeout(function() { console.log('获取user帖子'); resolve([{ id: 1, title: '帖子1' }, { id: 2, title: '帖子2' }]); }, 1000); }); } function getComments(posts) { return new Promise(function(resolve) { setTimeout(function() { console.log('获取帖子评论'); resolve([{ id: 1, content: '评论1' }, { id: 2, content: '评论2' }]); }, 1000); }); } // using Promise 链式调用, 避免callback地狱 getUser(1) .then(function(user) { return getPosts(user).then(function(posts) { return { user: user, posts: posts }; }); }) .then(function(data) { return getComments(data.posts).then(function(comments) { return { user: data.user, posts: data.posts, comments: comments }; }); }) .then(function(result) { console.log('最终结果:', result); }) .catch(function(error) { console.log('error:', error); }); // 更简洁 链式调用写法 getUser(1) .then(user => getPosts(user).then(posts => ({ user, posts }))) .then(({ user, posts }) => getComments(posts).then(comments => ({ user, posts, comments }))) .then(result => console.log('最终结果:', result)) .catch(error => console.log('error:', error));

4.3 Promise 静态method

// Promise.all - etc.待所 has Promise completion const promise1 = new Promise(resolve => setTimeout(() => resolve('结果1'), 1000)); const promise2 = new Promise(resolve => setTimeout(() => resolve('结果2'), 2000)); const promise3 = new Promise(resolve => setTimeout(() => resolve('结果3'), 1500)); Promise.all([promise1, promise2, promise3]) .then(results => { console.log('所 has Promise completion:', results); // 输出: 所 has Promise completion: [ '结果1', '结果2', '结果3' ] }) .catch(error => { console.log(' has Promise 失败:', error); }); // Promise.race - etc.待第一个completion Promise Promise.race([promise1, promise2, promise3]) .then(result => { console.log('第一个completion Promise 结果:', result); // 输出: 第一个completion Promise 结果: 结果1 }) .catch(error => { console.log(' has Promise 失败:', error); }); // Promise.resolve - creation一个已解决 Promise Promise.resolve('直接结果') .then(result => { console.log('Promise.resolve 结果:', result); // 输出: Promise.resolve 结果: 直接结果 }); // Promise.reject - creation一个已拒绝 Promise Promise.reject('直接error') .catch(error => { console.log('Promise.reject error:', error); // 输出: Promise.reject error: 直接error });

5. async/await

async/await is ES2017 引入 语法糖, 它基于 Promise, 使asynchronouscode看起来更像synchronizationcode, 进一步improving了code readable 性 and 可maintenance性.

5.1 basic用法

// 定义asynchronousfunction async function fetchData() { console.log('开始获取data...'); // using await etc.待 Promise completion const result = await new Promise(function(resolve) { setTimeout(function() { resolve('data获取成功!'); }, 2000); }); console.log('获取 to data:', result); return 'processing after 结果'; } // 调用asynchronousfunction fetchData() .then(function(result) { console.log('最终结果:', result); }) .catch(function(error) { console.log('error:', error); }); console.log('asynchronousfunction调用completion, etc.待结果...'); // 输出顺序: // 开始获取data... // asynchronousfunction调用completion, etc.待结果... // (2秒 after ) 获取 to data: data获取成功! // 最终结果: processing after 结果

5.2 errorprocessing

// asynchronousfunctionin errorprocessing async function fetchData() { try { console.log('开始获取data...'); // mock成功 and 失败 circumstances const success = false; const result = await new Promise(function(resolve, reject) { setTimeout(function() { if (success) { resolve('data获取成功!'); } else { reject('data获取失败!'); } }, 2000); }); console.log('获取 to data:', result); return 'processing after 结果'; } catch (error) { console.log('捕获 to error:', error); throw error; // 重 new 抛出error, 让调用者知道 } finally { console.log('operationcompletion, 无论成功 or 失败都会执行'); } } // 调用asynchronousfunction fetchData() .then(function(result) { console.log('最终结果:', result); }) .catch(function(error) { console.log('调用者捕获 to error:', error); }); // 输出顺序: // 开始获取data... // (2秒 after ) 捕获 to error: data获取失败! // operationcompletion, 无论成功 or 失败都会执行 // 调用者捕获 to error: data获取失败!

5.3 asynchronousfunction 链式调用

// 重写之 before example, using async/await function getUser(userId) { return new Promise(function(resolve) { setTimeout(function() { console.log('获取userinformation'); resolve({ id: userId, name: '张三' }); }, 1000); }); } function getPosts(user) { return new Promise(function(resolve) { setTimeout(function() { console.log('获取user帖子'); resolve([{ id: 1, title: '帖子1' }, { id: 2, title: '帖子2' }]); }, 1000); }); } function getComments(posts) { return new Promise(function(resolve) { setTimeout(function() { console.log('获取帖子评论'); resolve([{ id: 1, content: '评论1' }, { id: 2, content: '评论2' }]); }, 1000); }); } // using async/await 重写, code更加清晰 async function fetchUserData(userId) { try { const user = await getUser(userId); const posts = await getPosts(user); const comments = await getComments(posts); return { user: user, posts: posts, comments: comments }; } catch (error) { console.log('error:', error); throw error; } } // 调用asynchronousfunction fetchUserData(1) .then(function(result) { console.log('最终结果:', result); }) .catch(function(error) { console.log('调用者捕获 to error:', error); }); // 输出顺序: // 获取userinformation // 获取user帖子 // 获取帖子评论 // 最终结果: { user: { id: 1, name: '张三' }, posts: [...], comments: [...] }

6. asynchronousprogramming模式

6.1 parallel执行

当 many 个asynchronousoperation之间没 has 依赖relationships时, 可以parallel执行它们以improvingperformance.

// parallel执行 many 个asynchronousoperation async function fetchDataInParallel() { console.log('开始parallel获取data...'); // 同时开始所 has asynchronousoperation const promise1 = new Promise(resolve => setTimeout(() => resolve('data1'), 2000)); const promise2 = new Promise(resolve => setTimeout(() => resolve('data2'), 1500)); const promise3 = new Promise(resolve => setTimeout(() => resolve('data3'), 1000)); // etc.待所 has operationcompletion const [result1, result2, result3] = await Promise.all([promise1, promise2, promise3]); console.log('所 has data获取completion:'); console.log('结果1:', result1); console.log('结果2:', result2); console.log('结果3:', result3); return { result1, result2, result3 }; } fetchDataInParallel() .then(result => console.log('最终结果:', result)) .catch(error => console.log('error:', error)); // 输出顺序: // 开始parallel获取data... // (约2秒 after ) 所 has data获取completion: // 结果1: data1 // 结果2: data2 // 结果3: data3 // 最终结果: { result1: 'data1', result2: 'data2', result3: 'data3' }

6.2 串行执行

当asynchronousoperation之间 has 依赖relationships时, 需要串行执行它们.

// 串行执行 many 个asynchronousoperation async function fetchDataInSequence() { console.log('开始串行获取data...'); // 按顺序执行asynchronousoperation const result1 = await new Promise(resolve => { setTimeout(() => { console.log('获取data1completion'); resolve('data1'); }, 1000); }); const result2 = await new Promise(resolve => { setTimeout(() => { console.log('获取data2completion'); resolve('data2'); }, 1000); }); const result3 = await new Promise(resolve => { setTimeout(() => { console.log('获取data3completion'); resolve('data3'); }, 1000); }); console.log('所 has data获取completion:'); console.log('结果1:', result1); console.log('结果2:', result2); console.log('结果3:', result3); return { result1, result2, result3 }; } fetchDataInSequence() .then(result => console.log('最终结果:', result)) .catch(error => console.log('error:', error)); // 输出顺序: // 开始串行获取data... // (1秒 after ) 获取data1completion // (再1秒 after ) 获取data2completion // (再1秒 after ) 获取data3completion // 所 has data获取completion: // 结果1: data1 // 结果2: data2 // 结果3: data3 // 最终结果: { result1: 'data1', result2: 'data2', result3: 'data3' }

7. Fetch API

Fetch API is 现代浏览器providing 用于fornetworkrequest API, 它基于 Promise, providing了更简洁, 更强 big 方式来for HTTP request.

7.1 basic用法

// using Fetch API 获取data fetch('https://api.example.com/data') .then(response => { if (!response.ok) { throw new Error('networkresponse失败: ' + response.status); } return response.json(); // 解析 JSON response }) .then(data => { console.log('获取 to data:', data); }) .catch(error => { console.log('error:', error); }); // using async/await 语法 async function fetchData() { try { const response = await fetch('https://api.example.com/data'); if (!response.ok) { throw new Error('networkresponse失败: ' + response.status); } const data = await response.json(); console.log('获取 to data:', data); return data; } catch (error) { console.log('error:', error); throw error; } } fetchData() .then(data => console.log('processingdata:', data)) .catch(error => console.log('调用者捕获error:', error));

7.2 发送 POST request

// using Fetch API 发送 POST request async function sendData() { try { const response = await fetch('https://api.example.com/data', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name: '张三', age: 25 }) }); if (!response.ok) { throw new Error('networkresponse失败: ' + response.status); } const data = await response.json(); console.log('server返回 data:', data); return data; } catch (error) { console.log('error:', error); throw error; } } sendData() .then(data => console.log('request成功:', data)) .catch(error => console.log('request失败:', error));

8. asynchronousprogrammingoptimization

asynchronousprogramming虽然强 big , 但也需要注意一些optimizationtechniques, 以improvingcode performance and 可maintenance性.

8.1 避免过度using await

// 不推荐: 不必要 await 导致串行执行 async function fetchData() { const result1 = await fetch('https://api.example.com/data1'); const data1 = await result1.json(); const result2 = await fetch('https://api.example.com/data2'); const data2 = await result2.json(); const result3 = await fetch('https://api.example.com/data3'); const data3 = await result3.json(); return { data1, data2, data3 }; } // 推荐: parallel执行独立 request async function fetchDataoptimizationd() { // 同时开始所 has request const promise1 = fetch('https://api.example.com/data1').then(res => res.json()); const promise2 = fetch('https://api.example.com/data2').then(res => res.json()); const promise3 = fetch('https://api.example.com/data3').then(res => res.json()); // etc.待所 has requestcompletion const [data1, data2, data3] = await Promise.all([promise1, promise2, promise3]); return { data1, data2, data3 }; }

8.2 using Promise.allSettled

当你需要etc.待所 has Promise completion, 无论它们成功还 is 失败时, 可以using Promise.allSettled.

// using Promise.allSettled const promise1 = Promise.resolve('成功1'); const promise2 = Promise.reject('失败2'); const promise3 = Promise.resolve('成功3'); Promise.allSettled([promise1, promise2, promise3]) .then(results => { console.log('所 has Promise status:', results); // filter出成功 结果 const successfulResults = results .filter(result => result.status === 'fulfilled') .map(result => result.value); console.log('成功 结果:', successfulResults); // filter出失败 结果 const failedResults = results .filter(result => result.status === 'rejected') .map(result => result.reason); console.log('失败 结果:', failedResults); }); // 输出: // 所 has Promise status: [ // { status: 'fulfilled', value: '成功1' }, // { status: 'rejected', reason: '失败2' }, // { status: 'fulfilled', value: '成功3' } // ] // 成功 结果: [ '成功1', '成功3' ] // 失败 结果: [ '失败2' ]

实践case: asynchronousdataprocessing

fake设我们需要 from many 个 API 端点获取data, 并forprocessing after 展示给user. 我们将using async/await and Promise.all 来optimization这个过程.

// mock API request function fetchUsers() { return new Promise(resolve => { setTimeout(() => { console.log('获取userdata'); resolve([ { id: 1, name: '张三', posts: 5 }, { id: 2, name: '李四', posts: 3 }, { id: 3, name: '王五', posts: 8 } ]); }, 1000); }); } function fetchPosts(userId) { return new Promise(resolve => { setTimeout(() => { console.log(`获取user ${userId} 帖子`); resolve([ { id: 1, userId: userId, title: `帖子 ${userId}-1` }, { id: 2, userId: userId, title: `帖子 ${userId}-2` } ]); }, 500); }); } function fetchComments(postId) { return new Promise(resolve => { setTimeout(() => { console.log(`获取帖子 ${postId} 评论`); resolve([ { id: 1, postId: postId, content: `评论 ${postId}-1` }, { id: 2, postId: postId, content: `评论 ${postId}-2` } ]); }, 300); }); } // 主function: 获取所 has data并processing async function fetchAllData() { try { console.log('开始获取data...'); // 1. 获取所 has user const users = await fetchUsers(); console.log('userdata获取completion:', users); // 2. parallel获取所 has user 帖子 const userPostsPromises = users.map(user => fetchPosts(user.id)); const userPosts = await Promise.all(userPostsPromises); console.log('帖子data获取completion:', userPosts); // 3. parallel获取所 has 帖子 评论 const allPosts = userPosts.flat(); // merge所 has 帖子 const commentsPromises = allPosts.map(post => fetchComments(post.id)); const comments = await Promise.all(commentsPromises); console.log('评论data获取completion:', comments); // 4. processingdata, 构建完整 userinformation const result = users.map((user, index) => ({ ...user, posts: userPosts[index].map(post => { const postComments = comments.find(commentList => commentList.some(comment => comment.postId === post.id) ) || []; return { ...post, comments: postComments }; }) })); console.log('dataprocessingcompletion, 最终结果:'); console.log(JSON.stringify(result, null, 2)); return result; } catch (error) { console.log('error:', error); throw error; } finally { console.log('所 has operationcompletion'); } } // 执行主function fetchAllData() .then(result => console.log('执行成功, 返回结果:', result.length, '个user')) .catch(error => console.log('执行失败:', error));

互动练习: asynchronousoperationmock

请completion以 under asynchronousoperationtask:

  1. creation一个mock asynchronousoperationfunction, mocknetworkrequest
  2. implementationparallel执行 many 个asynchronousoperation
  3. implementation串行执行 many 个asynchronousoperation
  4. 比较两种执行方式 performancediff

asynchronousoperationmock器