Node.js异步编程——async/await实现

一、async/await基础语法

在Node.Js编程中,async关键字用于定义异步函数,这个异步函数执行完会返回一个Promise对象,异步函数的内部可以使用await关键字来暂停当前代码的继续执行,直到Promise操作完成。

在用法上,async关键字主要用于声明一个异步函数,await关键字主要用于等待Promise操作的返回结果,若await等待的Promise操作被rejected,此时会抛出异常,需要对异常采用"try/catch"处理。

async/await的语法格式: 

async function() {
    await [Asynchronous Action]}

async/await代码样例: 

1.等待Promise执行结果,并利用try/catch捕获异常

//定义异步函数
async function fetchData() {
    try {
        //异步操作,从API获取数据
        //使用await等待函数执行完成
        const response = await fetch('https://test.com/');
        const data = await response.json();
        console.log('The data is:', data);
    } catch (error) {
        console.error('Err occured:', error);
    }
}

//调用异步函数
fetchData();

2.async时序测试

async function async1() {
    console.log('async1 start');
    await async2();
    console.log('async1 end');    
  }
async function async2() {
    console.log('async2 finish');        
  }
console.log('script start');  
async1();
console.log('script end');

运行结果:

script start
async1 start
async2 finish
script end
async1 end

二、async/await和Promise的关系

1.async/await的语法是基于Promise来实现的。

2.async/await对Promise进行了封装,异步编程时避免了繁琐的Promise链式调用。

3.async/await的设计是为了简化Promise异步编程的实现方式,代码可读性更强。

4.async/await基于Promise增加了对执行步骤的控制,可以通过await来暂停/恢复执行。

基于Promise实现的异步操作:

fetchData()
  .then(data => process(data))
  .then(result => save(result))
  .catch(err => console.error(err));

基于async/await实现的异步操作:

try {
  const data = await fetchData();
  const result = await process(data);
  await save(result);
} catch (err) {
  console.error(err);
}

以上代码实现中,基于".then"实现的连续操作会让每一个步骤立即执行,基于await实现的连续操作可以让当前步骤暂停等待。

以下两段代码的实现效果相同: 

Demo1:基于async实现的Hello打印

async function func() {
    return "Hello";
  }

func().then(
    console.log("Print Hello")
);

运行结果:

Print Hello

Demo2:基于Promise实现的Hello打印

function func() {
    return Promise.resolve("Hello");
  }

func().then(
    console.log("Print Hello")
);

运行结果:

Print Hello

三、利用Promise.all实现并发编程

Promise.all用于处理多个Promise任务的并发执行,Promise.all执行完会返回一个新的Promise对象。

基础语法:

Promise.all(iterable);

调用Promise.all的时候输入一个可迭代对象,比如数组,这个可迭代对象包含多个Promise实例,如果多个Promise实例全部执行成功,会返回按顺序排列的resolved数组,如果任意一个Promise实例执行失败会立即抛出第一个失败的Promise实例的reject原因,其他Promise实例仍会执行。

代码样例:

const p1 = Promise.resolve(1);
const p2 = new Promise(resolve => setTimeout(() => resolve(2), 1000));
const p3 = Promise.resolve(3);

Promise.all([p1, p2, p3])
  .then(results => console.log(results));

运行结果:

[ 1, 2, 3 ]

Promise.all与await组合,在实现并发操作时的代码范式:

const [res1, res2] = 
   await Promise.all([task1(), task2()]);

Promise.all代码实战:模拟api并发请求

async function fetchData(endpoint, delay) {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        const success = 1;
        success
          ? resolve(`${endpoint} response (${delay}ms delay)`)
          : reject(`${endpoint} timeout`);
      }, delay);
    });
  }
  async function executeRequests() {
    try {
      const requests = [
        fetchData('/users', 1200),
        fetchData('/posts', 800),
        fetchData('/comments', 1500)
      ];
      console.log('Starting parallel requests...');
     
      const results = await Promise.all(requests);
     
      console.log('\nAll requests completed:');
      results.forEach((res, index) =>
        console.log(`Result ${index + 1}:`, res)
      );
     
      return results;
    } catch (error) {
      console.error('\nError:', error);
      throw new Error(`Process failed: ${error}`);
    }
  }
  (async () => {
    try {
      const data = await executeRequests();
      console.log('\nFinal data:', JSON.stringify(data, null, 2));
    } catch (err) {
      console.error('Global error handler:', err.message);
    }
  })();

运行结果:

Starting parallel requests...

All requests completed:
Result 1: /users response (1200ms delay)
Result 2: /posts response (800ms delay)
Result 3: /comments response (1500ms delay)

Final data: [
  "/users response (1200ms delay)",
  "/posts response (800ms delay)",
  "/comments response (1500ms delay)"
]

四、代码实战

Demo1:基于async/await和Dom实现的模拟网页登录验证

<!DOCTYPE html>
<html>
<head>
    <title>Async/Await Web Demo</title>
    <style>
        .container { padding: 20px; max-width: 600px; margin: 0 auto; }
        button { padding: 10px 20px; background: #2196F3; color: white; border: none; cursor: pointer; }
        .loader { display: none; border: 3px solid #f3f3f3; border-top: 3px solid #3498db; border-radius: 50%; width: 20px; height: 20px; animation: spin 1s linear infinite; }
        @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }
        .result-section { margin-top: 20px; padding: 15px; background: #f5f5f5; }
    </style>
</head>
<body>
    <div class="container">
        <h2>Async Operations Demo</h2>
        <button onclick="executeOperations()">Run Async Tasks</button>
        <div id="loading" class="loader"></div>
        <div id="results" class="result-section"></div>
    </div>

    <script>
        const asyncOperations = {
            fetchUser: () => new Promise(resolve =>
                setTimeout(() => resolve({ id: 1, name: 'John Doe' }), 1200)),
            
            getStats: () => new Promise(resolve =>
                setTimeout(() => resolve({ visits: 1520, active: true }), 800)),
            
            validate: () => new Promise((resolve, reject) =>
                setTimeout(() => Math.random() > 0.3
                    ? resolve('Validation passed')
                    : reject('Error: Validation failed'), 1000))
        };

        async function executeOperations() {
            const resultsDiv = document.getElementById('results');
            const loader = document.getElementById('loading');
            
            try {
                // Clear previous results
                resultsDiv.innerHTML = '';
                loader.style.display = 'inline-block';
                
                // Execute parallel async operations
                const [user, stats, validation] = await Promise.all([
                    asyncOperations.fetchUser(),
                    asyncOperations.getStats(),
                    asyncOperations.validate()
                ]);

                // Build result display
                resultsDiv.innerHTML = `
                    <h3>Results:</h3>
                    <p>User: ${user.name}</p>
                    <p>Visits: ${stats.visits}</p>
                    <p>Status: ${validation}</p>
                `;
            } catch (error) {
                resultsDiv.innerHTML = `<div style="color: red;">${error}</div>`;
            } finally {
                loader.style.display = 'none';
            }
        }
    </script>
</body>
</html>

运行结果:

Demo2:基于async/await实现的音乐下载器

<!DOCTYPE html>
<html>
<head>
    <title>音乐下载模拟器</title>
    <style>
        .progress-bar { width: 200px; height: 20px; border: 1px solid #ccc; }
        .progress { height: 100%; background: #4CAF50; transition: width 0.3s; }
    </style>
</head>
<body>
    <button onclick="startDownloads()">开始下载全部歌曲</button>
    <div id="downloadStatus"></div>
    <script>
        async function downloadSong(songName, duration) {
            const statusDiv = document.getElementById('downloadStatus');
            const item = document.createElement('div');
            item.innerHTML = `${songName}: <div class="progress-bar"><div class="progress" style="width:0%"></div></div>`;
            statusDiv.appendChild(item);
           
            let progress = 0;
            return new Promise((resolve, reject) => {
                const interval = setInterval(() => {
                    progress += 20;
                    item.querySelector('.progress').style.width = `${progress}%`;
                    if (progress >= 100) {
                        clearInterval(interval);
                        resolve(`${songName} 下载完成`);
                    }
                }, duration / 5); // 分5次完成进度更新
            });
        }


        // 启动全部下载(并行执行)
        async function startDownloads() {
            try {
                const songs = [
                    { name: "音乐1.mp3", duration: 2000 },
                    { name: "音乐2.mp3", duration: 2500 },
                    { name: "音乐3.mp3", duration: 1800 }
                ];
           
                const promises = songs.map(song =>
                    downloadSong(song.name, song.duration)
                );
                await Promise.all(promises);
                alert("所有文件下载完成!");
            } catch (error) {
                console.error("下载失败:", error);
            }
        }
    </script>
</body>
</html>

运行结果:

参考阅读:

https://www.programiz.com/javascript/async-await

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function

https://www.geeksforgeeks.org/explain-async-await-with-promises-in-node-js/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员与背包客_CoderZ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值