为何,async这颗糖很甜,也很咸呢?
你们都知道,async函数是Generator函数的语法糖,那什么是Generator函数呢? 若是你还没了解Generator,Generator异步调用,这篇文章为你介绍了Generator函数的原理和使用方法。
咱们先来看一个最简单的Generator函数javascript
function * generator(x){
var y = yield x + 1;
return y;
}
var gen = generator();
gen.next(1); //{value:2,done:false}
复制代码
这个案例是最简单的Generator函数的实现,咱们再来看一下,async函数的简单例子java
async function generator(x){
var y = await x + 1;
return y;
}
genertor(1).then(value => console.log(value)); //2
复制代码
对比上面两段代码,明显感受到,使用async后,代码变得更加清晰,同时,再也不须要手动调用next方法,就行实现异步加载,固然,为了代码清晰,上面的代码并没用异步调用,正常状况下,await后面的表达式为promise对象。
相对于Generator函数,async有下面几点好处 :git
先定义一个 Fetch 方法用于获取 github user 的信息:github
function fetchUser() {
return new Promise((resolve, reject) => {
fetch('https://api.github.com/users/superman66')
.then((data) => {
resolve(data.json());
}, (error) => {
reject(error);
})
});
}
复制代码
Promise 方式json
function getUserByPromise() {
fetchUser()
.then((data) => {
console.log(data);
}, (error) => {
console.log(error);
})
}
getUserByPromise();
复制代码
使用promise后,代码的执行变的很清晰,这能解决咱们当前问题,但有一种状况,若是咱们的需求有屡次请求,切每次请求都须要上次请求的结果,这就变的很麻烦了。固然,有的小伙伴说了,那咱们就能够继续的then()下去啊,能够,绝对能够,可是,随着请求次数的增多,代码中出现更多数量的then,若是不加以注释,也会变的晦涩难懂,这不是咱们想要的结果。继续。。。 Generator 方式api
function* fetchUserByGenerator() {
const user = yield fetchUser();
return user;
}
const g = fetchUserByGenerator();
const result = g.next().value;
result.then((v) => {
console.log(v);
}, (error) => {
console.log(error);
})
复制代码
Generator 的方式解决了 Promise 的一些问题,流程更加直观、语义化。可是 Generator 的问题在于,函数的执行须要依靠执行器,每次都须要经过 g.next() 的方式去执行。
async 方式promise
async function getUserByAsync(){
let user = await fetchUser();
return user;
}
getUserByAsync()
.then(v => console.log(v));
复制代码
哇。。。一样的结果,async像丝般顺滑,搞定了。真甜。。。异步
前文说到,async函数返回一个Promise对象。async
async function generator(x){
var y = await x + 1;
return y;
}
genertor(1).then(value => console.log(value)); //2
复制代码
promise函数then方法的执行前提是,await后面的表达式以获取到值。而后将值以参数的形式传入后面的函数中(例子中直接在控制台中打印出来)。 await后面能够是promise对象,也能够是基础数据。async 函数返回的 Promise 对象,必须等到内部全部的 await 命令的 Promise 对象执行完,才会发生状态改变。函数
const delay = timeout => new Promise(resolve=> setTimeout(resolve, timeout));
async function f(){
await delay(1000);
await delay(2000);
await delay(3000);
return 'done';
}
f().then(v => console.log(v)); // 等待6s后才输出 'done'
复制代码
正常状况下,await 命令后面跟着的是 Promise ,若是不是的话,也会被转换成一个 当即 resolve 的 Promise。
async function f() {
return await 1
};
f().then( (v) => console.log(v)) // 1
复制代码
若是await后面的异步操做出错,那么等同于async函数返回的 Promise 对象被reject。
async function f() {
await new Promise(function (resolve, reject) {
throw new Error('出错了');
});
}
f()
.then(v => console.log(v))
.catch(e => console.log(e))
// Error:出错了
复制代码
上面代码中,async函数f执行后,await后面的 Promise 对象会抛出一个错误对象,致使catch方法的回调函数被调用,它的参数就是抛出的错误对象。 防止出错的方法,也是将其放在try...catch代码块之中。
async function f() {
try {
await new Promise(function (resolve, reject) {
throw new Error('出错了');
});
} catch(e) {
}
return await('hello world');
}
复制代码
若是有多个await命令,能够统一放在try...catch结构中。
async function main() {
try {
const val1 = await firstStep();
const val2 = await secondStep(val1);
const val3 = await thirdStep(val1, val2);
console.log('Final: ', val3);
}
catch (err) {
console.error(err);
}
}
复制代码
当咱们在编写JavaScript异步代码的时候,人们常常在一个接着一个的函数调用前面添加await关键字.这会致使性能问题,由于在一般状况下,一个语句的执行并不依赖前一个语句的执行,可是由于添加了await关键字,你仍旧须要等待前一个语句执行完才能执行一个语句.
(async () => {
const pizzaData = await getPizzaData() // async call
const drinkData = await getDrinkData() // async call
const chosenPizza = choosePizza() // sync call
const chosenDrink = chooseDrink() // sync call
await addPizzaToCart(chosenPizza) // async call
await addDrinkToCart(chosenDrink) // async call
orderItems() // async call
})()
复制代码
解释: 1.得到披萨的列表. 2.得到饮料的列表. 3.从披萨列表中选择披萨. 4.从饮料列表中选择饮料. 5.把选择的披萨加入购物车 6.把选择的饮料加入购物车. 7.确认订单 错误:得到披萨列表和饮料列表能够同时进行,不必等待获取披萨列表后再去获取饮料列表。 如何解决这个问题呢?
async function selectPizza() {
const pizzaData = await getPizzaData() // async call
const chosenPizza = choosePizza() // sync call
await addPizzaToCart(chosenPizza) // async call
}
async function selectDrink() {
const drinkData = await getDrinkData() // async call
const chosenDrink = chooseDrink() // sync call
await addDrinkToCart(chosenDrink) // async call
}
(async () => {
const pizzaPromise = selectPizza()
const drinkPromise = selectDrink()
await pizzaPromise
await drinkPromise
orderItems() // async call
})()
// 我更喜欢下面这种实现.
(async () => {
Promise.all([selectPizza(), selectDrink()]).then(orderItems) // async call
})()
复制代码
很清晰的展示出,代码的执行顺序,相较于上一个,性能有了明显的提升。 ##总结 仍是题目的那句话,async函数很甜,也很咸。不要过度的去使用async/await,由于彻底不影响异步执行的操做,若是非要同步执行,随着调用接口的增长,回严重影响性能。瑕不掩瑜,async的便利性,很大程度上会减小开发量,同时代码的可读性也有很大的提升。
若是你以为这篇文章对你有帮助,别忘了给点个赞呦~ 每周会给你们分享一到两篇文章,但愿跟你们一块儿学习,一块儿进步。