前言
本人之前一直做Android开发,无奈Android现在尴尬的市场环境加上公司Android项目很少,只得转而学习Web前端。过程中发现要学的东西真的太多,只靠记忆实在效果有限,只得借助博客记录其中的一些关键知识,以便自己以后能快速回顾及帮助同样有疑惑的小伙伴。
本文主要讨论JavaScript中的Promise、Generate 函数、Async 函数,对他们有个大概说明及实际场景中的一些使用方式。网上对于他们的说明文章真的很多,百度一搜一大把,读完之后让我云里雾里,感觉懂了又感觉没懂,前前后后读了几十篇文章才懵懵懂懂,实在惭愧。
Promise、Generate 函数、Async 函数之前的异步编程
废话不多说了,首先说说,在这三个函数出来之前js中的异步编程—回调,让我用代码说话
const fun1 = (value,logValue) => {
setTimeout(()=>{
value(logValue);
},1000)
}
const fun2 = (value,logValue) => {
setTimeout(()=>{
value(logValue);
},1000)
}
const fun3 = (value,logValue) => {
setTimeout(()=>{
value(logValue);
},1000)
}
fun1((f1) => {
console.log(f1);
fun2((f2) => {
console.log(f2);
fun3((f3)=>{
console.log(f3);
},'fun3')
},'fun2')
},'fun1')
fun1、fun2、fun3分别模拟延时操作。实际的业务场景是,我要fun1 执行完成后,再去执行fun2,fun2执行完成后再去执行fun3,他们都是延时操作,可以看到具体实现方式,使用嵌套的方式,在fun1调用传入回调函数,在回调函数中调用fun2,又在调用fun2的同时传入回调,在回调函数中调用fun3,这种方式让代码嵌套层数过多,代码不够优雅,用网上的话说,这是“回调地狱”。(我本人倒是觉得还好,最多代码楼层太多,看起来不优雅而已。实际情况中我好像也没用碰到太多层的情况)
Promise的说明及实现方式
我们先看下Promise的创建方式
new Promise(function(resolve, reject){
if(true){
resolve('sucess')
}else{
reject('fail')
}
})
看起来这还是回调,成功的时候回调 resole,失败的时候调用reject。其实Promise本身只是解决“回调地狱”而出现的另一种“实现方式”(换了一种写法)。那Promise的具体写法是怎样的呢?我还是用上面的案例,这一次我们换成Promised 的写法。
const fun1 = () => {
return new Promise((resolve, reject)=>{
setTimeout(()=>{
resolve('fun1');
},1000)
})
}
const fun2 = (val) => {
return new Promise((resolve, reject)=>{
setTimeout(()=>{
resolve(val);
},1000)
})
}
const fun3 = (val) => {
return new Promise((resolve, reject)=>{
setTimeout(()=>{
resolve(val);
},1000)
})
}
fun1().then((v1)=>{
console.log(v1)
return fun2('fun2')
}).then((v2)=>{
console.log(v2)
return fun3('fun3')
}).then((v3)=>{
console.log(v3)
})
我们稍微改造了下fun1、fun2、fun3.让他们都返回的了Promise对象,之后调用then方法,并传入回调,then中的回调方法,就是resolve。Promise让所有的回调全部用了then进行传入,这种链式写法,看上去会清晰些。(网上说的,我看来看去还是觉得回调式更舒服,我仿佛是个智障)
Generate 函数的说明及实现
Generate 函数的基本语法
function * fun(x){
const a = yield x+1;
yield a;
}
相比普通函数,多了一个“*” 已经函数体中多了 一个 yield的关键词。Generate 函数相比普通函数,最大的调用区别是,如果把普通函数比喻成马车,这货就是一个耕田的牛,不打他不走。普通的函数调用,就一溜到底,这货执行的时候。首先给返回一个迭代器。你每次调用 next()方法。他往下走一下,直到遇到yield或者return ;
还是用我们开始的案例来换个写法说明吧。
let f;
const fun1 = (value) => {
setTimeout(()=>{
value('fun1');
},1000)
}
const fun2 = (value) => {
setTimeout(()=>{
value('fun2');
},1000)
}
const fun3 = (value) => {
setTimeout(()=>{
value('fun3');
},1000)
}
const callback = (t)=>{
console.log(t)
f.next() //在这个回调函数一致调用next,以便让他自动走下去
}
function * runAll(){
yield fun1(callback)
yield fun2(callback)
yield fun3(callback)
}
f = runAll() //给了你一个迭代器,等于啥也没干。
f.next(); //启动一下
我之前有个很大的误区,认为yield是等执行完成才会走next。所以我连续调用了三次。f.next()结果三个方法的打印同时出现,显然是不对的。
Async函数的说明及用法
网上对Async的一致说明是,这就是Generate函数的升级版,既然是升级那更好用啦。先看看他的语法
async function fun (x){
const a = await x + 1;
await a;
}
相当于Generate 把“*“变成了async 把 yield变成了 await,就这样?然后不是,搞这么大动静,只是换个写法,不是闲的蛋疼么。Async函数可以像普通函数一样,一溜到底,而且不是每次都要next()。另外 await后返回的是Promise对象。
const fun1 = () => {
return new Promise((resolve, reject)=>{
setTimeout(()=>{
resolve('fun1');
console.log('fun1');
},1000)
})
}
const fun2 = () => {
return new Promise((resolve, reject)=>{
setTimeout(()=>{
resolve('fun2');
console.log('fun2');
},1000)
})
}
const fun3 = () => {
return new Promise((resolve, reject)=>{
setTimeout(()=>{
resolve('fun3');
console.log('fun3');
},1000)
})
}
async function runAll (){
await fun1();
await fun2();
await fun3();
}
runAll();
async之所以能一溜到底的走下去,是三个函数中都要调用resolve方法,各位可以拿掉resolve看看效果。我贴上代码,给位可以直接放在浏览器允许看看允许执行结果。