8.0 来自老曾es6的前言:
- 哈喽小伙伴们,爱说‘废’话的Z又回来了,欢迎来到Super IT曾的博客时间,上一节说了字符串,面向对象以及json的知识,这一节我们继续我们知识的海洋,一起奋斗不秃头!不足的欢迎提问留言。
我发誓我真的没有P图😂,没想到这个系列被小编看上了,从发布这个系列起就都上热门了,怪害羞的,哈哈让人老脸一红的既视感,既然如此!我会认真把这个系列做完的,然后带你们搞项目搞框架!我们一起搞事情!那现在我们就开始吧!这一节是es6结局哦,下节就要说es789....的啦哈哈哈。
9.0 Promise
- 老曾英语教学开始,promise是什么,是承诺,我可是一言九鼎的人啊,别说四匹马,四十匹马都拉不回来我,那么解释起来promise就是这件事我肯定会做,至于多久做嘛~反正肯定会做的对吧!那么promise和我们es6有什么关系呢?我们先卖个关子。
- 这里就要先提到两个东西了,相信有一定基础的小伙伴一定知道我想说啥,对就是异步和同步。
两步 | 特点1 | 特点2 |
---|---|---|
异步 | 操作之间没啥关系,可同时进行多个操作 | 代码更复杂 |
同步 | 同时只能做一件事 | 代码简单 |
那么你肯定又想问异步和同步项目中怎么应用的?我拿它来干嘛?我打个比方:
这里的图片数据文字数据等等都不是写死的吧,都需要从后台去拿,如果你使用异步,这时候就好比这种代码,也叫回调地狱,这种好吓人哦,要是上百条数据上千条那怎么遭得住,不知道你们遭得住不,反正我是遭不住。
//callback-hell 回调地狱
getFileContent('a.json',data => {
console.log("data",data)
getFileContent(data.next, data2 =>{
console.log('data2',data2)
getFileContent(data2.next, data3 =>{
console.log('data3',data3)
})
})
})
这个时候就要请出我们的Promise了,它的作用就是用来消除异步操作,它具体是怎么的呢?一句话概括:
- 用同步的方式,书写异步的代码
9.1 Promise到底怎么用
- 我们以一个ajax示例来看,你说你不知道ajax怎么办,没关系,你跟着看,以我对你的了解你看得懂哈哈,至少不影响代码阅读,跟着看了之后,回头自己个儿再看一下ajax教程你就完全懂了,废话暂时到这,先看目录结构:
- 现在,问题来了,我要在index里面ajax请求这两个json文件,成功打印出里面json内容,失败则弹出失败,想想怎么做?提示一点,Promise.all的使用:
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.js"></script>
<script>
let p1 = new Promise((resolve, reject) =>{
//异步代码
$.ajax({
url: 'dataA.text',
dataType: 'json',
success(arr) {
resolve(arr)
},
error(err) {
reject(err)
}
})
})
let p2 = new Promise((resolve, reject) =>{
$.ajax({
url: 'dataB.text',
dataType: 'json',
success(arr) {
resolve(arr)
},
error(err) {
reject(err)
}
})
})
Promise.all([
p1,p2
]).then((arr) =>{
let [resA,resB] = arr
alert("all success")
console.log(resA,resB)
},(err) =>{
alert("fails")
console.log(err)
})
</script>
光看代码有没有理解一点呢,别急代码会继续优化,我们先来解析代码,使用箭头函数和解构赋值的地方都是我们前面博客说过的咯,忘记的童鞋就自己翻看一下老曾之前的博文啦,当然我也是贴心大暖男,放图来给你注释解析:
- 有道翻译 resolve--解决了,reject--拒绝了
- 那拿到我们这里就明明白白了,resolve成功,reject失败
图一,对应请求成功失败的执行以及返回:
- Promise对应成功失败的执行以及返回,绿字对绿框,紫字对紫框,红字对红框,顺便一提,无论是请求或是什么,有失败的函数一定要执行养成良好的习惯,我之前就不爱写失败的返回,蜜汁自信有没有哈哈哈,就会导致有时候不知道错误原因。
这样我怕你还不知道p1,p2,我给你打印一下可好?😋毕竟自己的粉自己疼p1,p2,console的代码中间有个逗号哈,只不过被线遮住了,看图就发现是promise对象:
现在来简化代码,我说过,我是个懒人,虽说p1和p2直接ctrl c+ctrl v再改改一个字母代码就好了,但我都懒得复制粘贴,两大坨代码看着就emm那啥,我们一个函数封装一下嘛:
<script>
function createPromise(url){
return new Promise((resolve, reject) =>{
$.ajax({
url: url,
dataType: 'json',
success(arr) {
resolve(arr)
},
error(err) {
reject(err)
}
})
})
}
let p1 = createPromise("dataA.text")
let p2 = createPromise("dataB.text")
Promise.all([
p1,p2
]).then((arr) =>{
let [resA,resB] = arr
alert("all success")
console.log(resA,resB)
},(err) =>{
alert("fails")
console.log(err)
})
</script>
这样就清爽的多了有没有,当然这远远不够,你还能像到更优化的吗?不能的话就跟着来,看看代码打印出啥?
let p = $.ajax({url:'dataA.text',dataTape:'json'})
console.log(p)
发现没jQuery返回的本身就有promise对象,所以我们不用自己用p1,p2接收一个promise,现在直接用就好了:
<script>
Promise.all([
$.ajax({url:"dataA.text",dataType:'json'}),
$.ajax({url:'dataB.text',dataTape:'json'})
]).then((arr) =>{
console.log("success",arr)
},(err) =>{
console.log('fail',err)
})
</script>
这样是不是爽多了有没有!!!!
- 这才是Promise的完美用法,Promise.all是必须全部成功才执行成功,更像‘与’有没有,这里我们提一下另外一个,Promise.race,这个的话意思就是那个来了就先执行哪个,有一个成功都会执行成功的函数。
10.0 generator
10.1 generator的基本功能
- 这是个啥?英语不好不存在哇搜一搜,翻译过来就是生成器。那这个有啥用?通俗易懂的来对比一下。
- 普通函数:一路到底 —— 高铁火车
- generator函数:随叫随停 —— 出租车
那么我们就来看看这个generator和普通函数有啥不同?瞅瞅看打印出来是啥?猜猜?说实话我最开始也不知道哈哈哈😄,这里提示一下yield翻译过来是放弃的意思,我们这里把他理解为暂时放弃。
<script>
function *show(){
alert('a');
yield;
alert('b')
}
show()
</script>
你是不是觉得会弹出一个a,没想到吧,啥也没有,控制台也不报错,这时候咋办呢?alert(show())
,同时 console.log(show())
一下,查看一下呢?
alert出来的倒没啥,就告诉你执行出来是个生成器对象,但是当我们看他里面的时候就会发现里面有一个next方法,这个就很重要了。
那我们就来 show().next();
执行一下看看是个啥?
那如果既要显示a又要显示b呢?我们试试这样写:
let obj = show()
obj.next();
obj.next();
这样a,b就都出来了,这里只放了b,所以next给人的感觉就是踹一步走一下的感觉对吧。那你要问老曾老曾这个generator的原理是怎么实现走走停停的呢?你猜我给你说不说哈哈,当然要说。
- generator的基本原理在这里就是把原来的*show()函数划分为了两个小函数,当然你是看不见的,这里就相当于划分为了show1和show2,各自执行alert('a')和alert('b')。
10.2 细说yield
yield传参
- 上一个小点我们刚说了,yield是暂时放弃的意思,同时也对Promise有了一个基本的了解,那来看看这段代码你能猜对执行结果嘛?
<script>
function *show(){
alert('a');
let a = yield;
alert('b');
alert(a);
}
let gen = show();
gen.next(12);
gen.next(5);
</script>
注意重点来了!
5???有没有怀疑人生?哈哈我很懵逼啊表示,来来来我们来分析一下两个next分别执行的是*show的哪两段代码:
第一次next是不是应该是白框框的代码,碰到yield暂停了嘛,第二次next就是黄框框的代码。所以 gen.next(5);
是给谁传递的值,看黄框框,是不是就是给 let a
传递的值,这样不难理解吧。
- 那你说如果想给上面白框框alert值怎么办?
function *show(num1,num2){
alert(`${num1} ${num2}`)
alert('a');
let a = yield;
alert('b');
alert(a);
}
let gen = show(9,99);
gen.next(12);
gen.next(5);
这样就可以了嘛,所以也可以看出第一个next对于yield传参是废的,是没有用的好吧。
yield返回
*来来来,yield传参玩完了我们来说说返回,一样一样来猜猜代码执行结果是什么?
<script>
function *show(){
alert('a');
yield 12;
alert('b');
return 55;
}
let gen = show();
let res1 = gen.next();
console.log(res1)
let res2 = gen.next();
console.log(res2)
</script>
相信机智的你至少已经看出来了一点,这里的done就是是否执行完毕,那按照之前白框框和黄框框的理解,返回value是12和55能理解吗?还不能理解的话我们就来继续看~
yield到底是个啥
- 这里咱就不搞代码了,咱来搞一个接地气的伪代码,你来品品:
说白了就像是一个厨房的分工以yield隔开,各做各的事情,就这么简单,还不懂得小伙伴评论区留言哦~
10.3 generator的实例
- 介绍完了generator也了解了它的基本使用,那我们不是说它也可以用来消除异步操作嘛?那具体是怎么做的呢?
- 首先我们需要一个runner文件,我会把它放在github上,文章末尾有github链接点进去在es6的15的文件夹里就可以看到啦,没找到文件的可以私聊我😊。
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.js"></script>
<script src="runner.js"></script>
<script>
runner(function *(){
let data1 = yield $.ajax({url:'dataA.text',dataType:'json'})
let data2 = yield $.ajax({url:'dataB.text',dataType:'json'})
let data3 = yield $.ajax({url:'dataC.text',dataType:'json'})
console.log(data1,data2,data3)
})
</script>
对应的dataA,B,C就有了,这里要注意一点就是我们第一个$.ajax返回的promise返回给了谁,我们这里其实返回给了runner去处理然后yield暂停,处理完了后就会回到data1继续执行,完了第二个ajax就会给data2,依次data3。
11.0 异步操作总结
11.1回调
//回调
$.ajax({
url: xxx,
dataType: 'json'
success(data1){
$.ajax({
url: xxx,
dataType: 'json'
success(data2){
$.ajax({
url: xxx,
dataType: 'json'
success(data3){
//完事儿
},
error(){
alert('错了');
}
});
},
error(){
alert('错了');
}
});
},
error(){
alert('错了');
}
});
11.2 Promise
//Promise
Promise.all([
$.ajax({url: xxx, dataType: 'json'}),
$.ajax({url: xxx, dataType: 'json'}),
$.ajax({url: xxx, dataType: 'json'})
]).then(results=>{
//完事儿
}, err=>{
alert('错了');
});
11.3 generator
//generator
runner(function *(){
let data1=yield $.ajax({url: xxx, dataType: 'json'});
let data2=yield $.ajax({url: xxx, dataType: 'json'});
let data3=yield $.ajax({url: xxx, dataType: 'json'});
//完事儿
});
11.4 Promise的缺点
- 光看上面的11.2和11.3是不是感觉两个差别不大,确实,但是如果promise带逻辑,就比如一个用户登录了是vip怎么怎么样,不是VIP又怎么怎么样?这个时候我们的代码是什么样子的呢?
//带逻辑-Promise
Promise.all([
$.ajax({url: 'getUserData', dataType: 'json'})
]).then(results=>{
let userData=results[0];
if(userData.type=='VIP'){
Promise.all([
$.ajax({url: 'getVIPItems', dataType: 'json'})
]).then(results=>{
let items=results[0];
//生成列表、显示...
}, err=>{
alert('错了');
});
}else{
Promise.all([
$.ajax({url: 'getItems', dataType: 'json'})
]).then(results=>{
let items=results[0];
//生成列表、显示...
}, err=>{
alert('错了');
});
}
}, err=>{
alert('失败');
});
我的天一大堆,来看看普通回调,这个时候说实话我还不如用普通回调。
//带逻辑-普通回调
$.ajax({url: 'getUserData', dataType: 'json', success(userData){
if(userData.type=='VIP'){
$.ajax({url: 'getVIPItems', dataType: 'json', success(items){
//生成列表、显示...
}, error(err){
alert('错了');
}});
}else{
$.ajax({url: 'getItems', dataType: 'json', success(items){
//生成列表、显示...
}, error(err){
alert('错了');
}});
}
}, error(err){
alert('错了');
}});
普通回调都比Promise好对吧,但是有了generator,来看看它怎么写?
//带逻辑-generator
runner(function *(){
let userData=yield $.ajax({url: 'getUserData', dataType: 'json'});
if(userData.type=='VIP'){
let items=yield $.ajax({url: 'getVIPItems', dataType: 'json'});
}else{
let items=yield $.ajax({url: 'getItems', dataType: 'json'});
}
//生成、...
});
这个时候是不是感觉他的优势一下子就显现出来了,就和我们平时的普通函数执行一样,简单粗暴。
好了到这里我们的ES6说的就差不多了!!!!!!!!四个系列终于说完。
———————————————————————分割线——————
都看到这里了,只能说明一点,咱俩真的真的真的很有缘分啊!不点个赞再走嘛,😊😀,顺手加个关注嘛,偷偷收藏我博文的小可爱我后台看得到的嘛,点个赞给老曾支持支持,不出意外接下来我一直都在哈哈哈,学知识写博客不着急,基础打好,项目直接上手6到飞起。
下节说ES7,及之后版本的内容
你好,朋友😀,都看到这里了,说明咱俩是真的有缘,要不留个评论或者点个赞再走😊?