async函数
async函数的返回值为 promise 对象,promise对象的结果由async函数执行的返回值决定。async函数能使得异步操作变得更加方便,简而言之就是 Generator 的语法糖。
(资料图)
定义async函数,特点是即便函数内部返回结果不是promise对象,调用函数其最后的返回结果依然是promise对象,代码如下:
如果返回的结果不是 Promise 对象的情况下:
<script> async function fn(){ // 返回的结果是字符串 // return "123" // // 返回的结果是undefined // return; // 返回的结果是抛出一个异常 throw new "error" } const result = fn() console.log(result);</script>
登录后复制
如果返回的结果是 Promise 对象时,我们正常使用 then 方法即可,如下:
<script> async function fn(){ return new Promise((resolve,reject)=>{ // resolve("成功的数据") reject("失败的数据") }) } const result = fn() // 调用 then 方法 result.then((value)=>{ console.log(value); },(reason)=>{ console.log(reason); // 打印失败的数据 })</script>
登录后复制
await 表达式
通过上文的对 async 介绍,感觉其功能有点鸡肋,其实恰恰不是,而是 async 需要搭配 await 一起使用才能达到语法糖的效果。
说白了:await就相当于 then 方法的第一个回调函数,只返回成功的值,失败的值需要 try...catch来捕获。
async函数内部抛出错误,会导致返回的 Promise 对象变为reject状态。抛出的错误对象会被catch方法回调函数接收到。
<script> const p = new Promise((resolve,reject)=>{ // resolve("用户数据") reject("用户加载数据失败了") }) async function fn(){ // 为防止promise是失败的状态,加上try...catch进行异常捕获 try { // await 返回的结果就是 promise 返回成功的值 let result = await p console.log(result); } catch (error) { console.log(error);//因为是失败的状态,所以打印:用户加载数据失败了 } } fn()</script>
登录后复制
async使用形式
// 函数声明async function foo() {} // 函数表达式const foo = async function () {}; // 对象的方法let obj = { async foo() {} };obj.foo().then(...) // Class 的方法class Storage { constructor() { this.cachePromise = caches.open("avatars"); } async getAvatar(name) { const cache = await this.cachePromise; return cache.match(`/avatars/${name}.jpg`); }} const storage = new Storage();storage.getAvatar("jake").then(…); // 箭头函数const foo = async () => {};
登录后复制
async读取文件
和之前讲解的 promise 读取文件内容 一样,我们也可以使用async进行文件的读取,代码如下:
// 1.引入 fs 模块const fs = require("fs") // 2.读取文件function index(){ return new Promise((resolve,reject)=>{ fs.readFile("./index.md",(err,data)=>{ // 如果失败 if(err) reject(err) // 如果成功 resolve(data) }) })}function index1(){ return new Promise((resolve,reject)=>{ fs.readFile("./index1.md",(err,data)=>{ // 如果失败 if(err) reject(err) // 如果成功 resolve(data) }) })}function index2(){ return new Promise((resolve,reject)=>{ fs.readFile("./index2.md",(err,data)=>{ // 如果失败 if(err) reject(err) // 如果成功 resolve(data) }) })} // 3.声明一个 async 函数async function fn(){ let i = await index() let i1 = await index1() let i2 = await index2() console.log(i.toString()); console.log(i1.toString()); console.log(i2.toString());}fn()
登录后复制
async发送AJAX请求
和之前讲解 promise发送ajax请求 一样,我们也可以使用async进行发送ajax请求,代码如下:
<script> // 发送 AJAX请求,返回的结果是 Promise 对象 function sendAjax(url){ return new Promise((resolve,reject)=>{ // 创建对象 const x = new XMLHttpRequest() // 初始化 x.open("GET",url) // 发送 x.send() // 事件绑定 x.onreadystatechange = function(){ if(x.readyState === 4){ if(x.status >= 200 && x.status < 300){ // 如果响应成功 resolve(x.response) // 如果响应失败 reject(x.status) } } } }) } // promise then 方法测试 // const result = sendAjax("https://ai.baidu.com/").then(value=>{ // console.log(value); // },reason=>{}) // async 与 await 测试 async function fn(){ // 发送 AJAX 请求 let result = await sendAjax("https://ai.baidu.com/") console.log(result); } fn()</script>
登录后复制
与生成器(Generator)相比
我们发现 async与await之间的关系 和 Generator与yield之间的关系十分类似,不熟悉Generator的朋友可以看一下我之前的文章:生成器讲解 ;一比较就发现: async函数就是将 Generator 函数的星号(*)替换成async,将yield替换成await。代码比较如下:
<script> // Generator 函数 function * person() { console.log("hello world"); yield "第一分隔线" console.log("hello world 1"); yield "第二分隔线" console.log("hello world 2"); yield "第三分隔线" } let iterator = person() // console.log(iterator); 打印的就是一个迭代器对象,里面有一个 next() 方法,我们借助next方法让它运行 iterator.next() iterator.next() iterator.next() // async函数 const person1 = async function (){ console.log("hello world"); await "第一分隔线" console.log("hello world 1"); await "第二分隔线" console.log("hello world 2"); await "第三分隔线" } person1()</script>
登录后复制
async函数的实现原理就是将 Generator 函数和自动执行器包装在一个函数里。
<script> async function fn(args) {} // 等同于 function fn(args) { // spawn函数就是自动执行器 return spawn(function* () {}); }</script>
登录后复制
我们可以分析一下 Generator 和 async 代码的书写特点和风格:
<script> // Generator 函数 function Generator(a, b) { return spawn(function*() { let r = null; try { for(let k of b) { r = yield k(a); } } catch(e) { /* 忽略错误,继续执行 */ } return r; }); } // async 函数 async function async(a, b) { let r = null; try { for(let k of b) { r = await k(a); } } catch(e) { /* 忽略错误,继续执行 */ } return r; }</script>
登录后复制
所以 async 函数的实现符合语义也很简洁,不用写Generator的自动执行器,改在语言底层提供,因此代码量少。
从上文代码我们可以总结以下几点:
【推荐学习:javascript高级教程】
以上就是深入探讨JavaScript中的async函数的详细内容,更多请关注php中文网其它相关文章!