环球新资讯:深入探讨JavaScript中的async函数

时间:2022-11-03 20:58:53       来源:转载

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中文网其它相关文章!

关键词: 加载数据 回调函数 可以使用