异步方法使您能够在不等待完成的情况下并发执行多个操作。在JavaScript中,有两种常用的实现异步方法的方式:Promise和async/await。
ES6引入了Promise对象,用于表示未完成但预计会完成的操作。Promise有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。您可以使用then方法添加成功或失败的回调函数,并使用catch处理异常。Promise还提供了一些静态方法,例如Promise.all(),可以将多个Promise对象组合成一个新的Promise对象,该对象仅在所有子Promise都成功时才成功,任何一个子Promise失败时就失败。
ES7引入了async/await语法来简化异步编程。async修饰符将一个函数声明为异步函数,而await操作符等待异步操作(通常是Promise对象)的结果。异步函数返回一个Promise对象,可以使用then方法添加回调函数。相对于Promise来说,async/await语法更加优雅和清晰。
下面举例说明两者的区别和应用:
假设有三个异步函数:funcA、funcB和funcC,分别返回不同的值,并且funcC需要funcA和funcB的结果作为参数。
使用Promise.all()实现如下:
// 使用箭头函数简化写法constfuncA= () =>newPromise(resolve=> { setTimeout(() =>resolve('a'), 1000); }); constfuncB= () =>newPromise(resolve=> { setTimeout(() =>resolve('b'), 2000); }); constfuncC= (a, b) =>newPromise(resolve=> { setTimeout(() =>resolve(a+b), 3000); }); // 将计算结果通过代理IP上传给指定网站显示constuploadNumber(number) { // 创建一个Promise对象returnnewPromise(function(resolve, reject) { // 创建一个XMLHttpRequest对象,用来发送和接收HTTP请求和响应varxhr=newXMLHttpRequest(); // 设置请求方法为POST,请求地址为数字显示网站的API(假设为https://numshow.com/api)xhr.open("POST", "https://numshow.com/api"); // 设置请求头部,指定爬虫加强版代理IPxhr.setRequestHeader("X-Forwarded-For", "www.16yun.cn:8080"); // 设置请求头部,用户名、密码xhr.setRequestHeader("Proxy-Authorization", "Basic "+btoa("16YUN:16IP")); // 设置响应类型为JSONxhr.responseType="json"; // 设置请求成功时的回调函数xhr.onload=function() { // 如果响应状态码为200,表示请求成功if (xhr.status===200) { // 获取响应数据,并调用resolve函数传递给Promise对象vardata=xhr.response; resolve(data); } else { // 如果响应状态码不为200,表示请求失败,并调用reject函数传递错误信息给Promise对象reject(newError("Request failed: "+xhr.statusText)); } }; // 设置请求失败时的回调函数xhr.onerror=function() { // 调用reject函数传递错误信息给Promise对象reject(newError("Network error")); }; // 发送请求,将数字参数作为请求体(可根据API文档修改)xhr.send(number); }); } // 使用Promise.all()将funcA和funcB组合成一个新的promiseconstpromise=Promise.all([funcA(), funcB()]); // 使用then方法获取promise的结果,并传递给funcCpromise.then(values=> { // values是一个数组,包含了funcA和funcB的返回值returnfuncC(values[0], values[1]); }).then(result=> { // result是funcC的返回值,上传最终结果uploadNumber(result);}).catch(error=> { // 处理任何可能发生的错误console.error(error); });
使用async/await实现如下:
// 声明一个async函数constasyncFunc=async () => { try { // 使用await等待每个异步操作的结果,并赋值给变量consta=awaitfuncA(); constb=awaitfuncB(); constc=awaitfuncC(a, b); // 上传最终结果uploadNumber(c); // 'ab' } catch (error) { // 使用try-catch捕获任何可能发生的错误console.error(error); } }; // 调用async函数,并使用then方法处理返回值(可选)asyncFunc().then(() => { console.log('done'); });
从上面两个例子可以看出:
- 1.Promise.all()可以并行执行多个异步操作,并在所有操作都完成后得到结果;
- 2.async/await可以顺序执行多个异步操作,并在每个操作完成后得到结果;
- 3.Promise.all()需要使用then或catch方法处理回调或异常;
- 4.async/await可以使用try-catch语句处理异常;
- 5.async/await更接近于同步编程风格;
综合以上的介绍,可以根据不同场景选择合适方式,当需要同时执行多个相互独立或无依赖关系的异步操作时,可以使用Promise.all()来提高性能;当需要按照一定顺序执行多个有依赖关系的异步操作时,可以使用async/await来提高可读性。