加入收藏 | 设为首页 | 会员中心 | 我要投稿 银川站长网 (https://www.0951zz.com/)- 云通信、基础存储、云上网络、机器学习、视觉智能!
当前位置: 首页 > 综合聚焦 > 编程要点 > 语言 > 正文

async函数的使用有什么益处 使用形式是怎样

发布时间:2023-08-10 11:14:11 所属栏目:语言 来源:
导读:这篇文章主要讲解了“async函数的使用有什么好处,使用形式是怎样”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“async函数的使用有什么好处,使

这篇文章主要讲解了“async函数的使用有什么好处,使用形式是怎样”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“async函数的使用有什么好处,使用形式是怎样”吧!

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的特点:

await必须写在 async 函数中

await右侧的表达式一般为 promise 对象

await返回的是 promise 成功的值

await的 promise 失败了,就会抛出异常,需要通过 try...catch捕获处理

说白了: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>

登录后复制

总结:

(1)await命令后面的Promise对象,运行结果可能是rejected,所以最好把await命令放在try...catch代码块中。

(2)如果有多个await命令后面的异步操作,如果不存在继发关系,最好让它们同时触发。

比如:await Promise.all([a(), b()]),这里简单提一下

(3)await命令只能用在async函数之中,如果用在普通函数,就会报错。

(4)(理解一下async的运行原理) async 函数可以保留运行堆栈,普通函数内部运行一个异步任务时,如果异步任务运行结束普通函数可能早就运行完了,异步任务的上下文环境已经消失了,如果异步任务报错,错误堆栈将不包括普通函数;而async函数内部的异步任务运行时,async函数是暂停执行的,所以一旦async函数内部的异步任务运行报错,错误堆栈将包括async函数。

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的自动执行器,改在语言底层提供,因此代码量少。

从上文代码我们可以总结以下几点:

(1)Generator函数执行需要借助执行器,而async函数自带执行器,即async不需要像生成器一样需要借助 next 方法才能执行,而是会自动执行。

(2)相比于生成器函数,我们可以看到 async 函数的语义更加清晰

(3)上面就说了,async函数可以接受Promise或者其他原始类型,而生成器函数yield命令后面只能是Promise对象或者Thunk函数。

(4)async函数返回值只能是Promise对象,而生成器函数返回值是 Iterator 对象。

(编辑:银川站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章