【零基础JavaScript教程】#14 JavaScript Promise 是什么?异步(非同步)编程必须掌握的技巧 程序员终于可以逃出回调地狱callback hell了!!
☕ ☕ ☕ 如果觉得这些教学对你有用,那就请我喝杯咖啡吧! 我会继续为你创作更多免费的编程教学视频,让你轻松入门编程。 ✅ https://bit.ly/3kCOpFK ✅ (免费) JavaScript教程系列: https://bit.ly/310cHle ✅ 更多精彩的JavaScript入门课程: http://bit.ly/js-for-beginners ✅ JavaScript相关书籍: 1:The Definitive Guide: Master the World's Most-Used Programming Language - 7th Edition (强烈推荐👍) https://amzn.to/31s30uH ✅(通告)”Codetisan 自学编程社区“ 已经正式开通啦,三人行必有我师,同学们再也不用独自一人闷头自学编程了,快去社区里和其他小伙伴们互动吧! ▶︎ https://bit.ly/2AHylzN 🔆订阅我的YouTube频道,让你从一个0基础编程的菜鸟快速成为编程大师!🔆 http://bit.ly/2TBkXo1 ▶︎ 文轩解码更精彩的平台 ◀︎ ‣‣ Blogger :https://bit.ly/2yMz0PC ‣‣ Twitter: https://bit.ly/2R74FS1 ‣‣ Facebook: https://bit.ly/35crcmz ‣‣ Instagram: https://bit.ly/2KH6Wjw ‣‣ Github: https://bit.ly/2SHtsx4 #javascript-promise #javascript教学 #编程入门
文字内容:
Hi, 大家好,我是文轩
欢迎再次收看文轩解码
如果你想和其他同学一起学习和讨论JavaScript编程
可以扫描这个二维码
去到自学编程社区里和其他同学一起互动
上期视频我们学习了同步执行和异步执行的区别
也弄清楚了callback在异步执行里扮演的角色
如果还没看上期的视频
稍后可以回看一下
我在这里就简单介绍一下同步执行和异步执行
同步执行 synchronous execution
的意思是任务会一个接一个有序的被执行
先执行完当前的任务才执行下一个任务
异步执行一般适用于执行超长任务
所谓的超长任务
就像JS程序向第三方服务器发送网络请求获取数据
这些请求可能需要3秒甚至更长的时间完成
而且完成时间是不可预测的
如果JS程序因为超长任务阻塞JS引擎的运行
那就会导致JS程序出现死机状态
为了避免大阻塞
当JS程序发现需要执行超长任务的时候
就会让程序异步执行这些超长任务
一边执行超长任务
一边执行剩余的任务
这样超长任务就不会因为耗时而堵住剩余的任务
随着JavaScript不停的迭代
异步执行的应用也发生了重大的变化
从一开始使用传统callback回调异步代码
到后期升级到Promise
最近还从Promise过渡到async-await
JavaScript不停的迭代
不仅优化了语言的本身的性能
还让新学员轻松上手更容易操作的JavaScript
今天这个视频我会专注在JavaScript Promise
async await会在下个视频再和你们细说
不想错过的话记得订阅关注频道
接下来要问一个很重要的问题
那就是为什么callback用得好好的
还要加入Promise呢?
虽然callback能帮我们达到目的 执行异步代码
但它也有自己的弊端
callback在复杂的程序容易造成callback hell
俗称回调地狱
如果程序够复杂的话
就会出现类似这样的情况
a函数里执行b函数
b执行c函数
一层一层的嵌套下去
不利于短时间内明白代码的逻辑
还会加大后期调试的难度
如果我们换一个方法
像这样
你觉得这样比起刚才的callback hell
哪一个的可读性高一点?
我个人就觉得这个代码的可读性比callback hell更高
更直观
当a函数执行完它所有的任务
就会执行then里的回调函数
当这个回调函数执行完之后
就会执行下一个then里的回调函数
以此类推
Promise的出现不是把callback的概念从JavaScript里抹去
Promise的出现是让我们编写更简洁的代码
让程序员更容易维护源代码
Promise,从字面上来看的话
是承诺的意思
Promise就像我们在现实生活里承诺对方做一件事
它的结果有两个
要嘛履行承诺
要嘛反悔
不履行承诺
假设你现在使用一个打车软件
去呼叫专车送你去机场
打开软件之后你输入目的地
然后发送请求
看那辆车能过来接你
这时候你的请求是处于匹配待定的状态
过了一会儿
司机A在打车软件里看到了你的订单
然后他就点击接单
承诺会过去接你
把你送去机场
同学们这里要注意
这只是一个承诺
司机可能在路上因为某种原因
选择取消订单
拒绝履行他之前许下的承诺
如果司机安全把你送去机场
这才代表司机履行了承诺
订单才算完成
当你发送网约专车请求的时候
承诺是处于pending待定状态
如果司机取消订单
承诺就会从pending变成reject拒绝状态
要是司机成功把你送去机场
Promise这时候就会变成resolve被履行的状态
接下来
我们将刚才的打车场景用JavaScript模拟一下
看看要怎么创建Promise object
然后再具体了解怎么完成和拒绝Promise
那现在我们切换到VS Code开始实操的部分
要创建Promise object
我们需要使用new Promise语句
我们先定义一个变量p
用来储存Promise object
然后再输入 = new Promise()
在小括号这里我们需要提供回调函数callback
这个回调函数有两个参数
一个叫resolve(完成)
一个叫reject(拒绝)
resolve和reject都是函数
所以我们可以在回调函数里调用resolve()
告诉Promise任务已近完成
如果中途Promise报错或者拒绝履行承诺
我们可以调用reject()
我们在小括号这里输入function
小括号
大括号
接着在参数列表这里输入resolve作为第一个参数
然后输入reject作为第二个参数
现在我们继续在回调函数里编写代码
首先我们要判断司机是否把乘客送去机场了
如果安全送达机场
我们就调用resolve()
如果司机没把乘客送去机场
我们就调用reject()
先插入if else语句
接着在小括号里输入一个boolean值
sentToAirport
这个值我们需要在上面定义一下
不然等一下运行的时候会报错
let sentToAirport
把这个变量设置成true
模拟司机把乘客送去机场了
如果sentToAirport的值是true
我们在if的部分调用resolve()
如果sentToAirport的值是false
我们在else这里调用reject()
基本上我们用来创建Promise的代码就完成了
那接下来我们就要调用这个Promise
我们该怎么调用它呢?
其实当JavaScript执行new Promise
创建Promise object的时候
Promise的回调函数就开始执行了
所以我们要关心的不是Promise怎么被调用
而是要关心Promise在完成任务后
程序该怎么处理Promise返回的信息
p变量现在是一个Promise object
这个object提供了一个方法(method) 叫 then()
如果想在p Promise完成后
执行后续的代码
我们可以这样定义
p.then()
p.then的意思是
当这个Promise里的代码执行完之后
就会跳到then这里执行then里的代码
我们在then里需要提供一个回调函数
我们在这里输入一个简单的回调函数
只打印promise resolved
来证明Promise完成后真的会返回到then的部分
我们还需要在resolve之前输入
console.log("sent to airport")
来证明这里的代码被执行过
好的,现在我们保存刷新一下页面
看看console里输出什么
console先打印sent to airport
然后才打印promise resolved
因为sentToAirport的值是true
所以程序会执行这个部分
打印sent to airport
当执行到resolve()
Promise这时候就被告知已经履行了承诺
现在需要返回到调用代码
接着程序就会跳到then里
执行这里的console.log
打印promise resolved
刚才我们执行了resolve的部分
现在我们来执行reject的部分
我们把sentToAirport变量设置成false
这样if语句会判断为false
程序跳到else部分执行reject
我们在else语句里添加一个console.log
证明一下程序会执行到这个部分
我们输出cannot send to airport吧
当程序执行reject函数的时候
程序会报错
这是Promise的默认行为
我来给你们演示一下
保存刷新
console显示cannot send to airport
是对的
因为程序跳到了else语句执行这里的代码
然后接着执行reject()
执行完reject()函数后
JavaScript就会报错
这和我刚才说的默认行为是吻合的
如果我们不想出现这个Uncaught错误
就需要在then后面添加catch语句
用来捕捉这个Uncaught error
我们在这里添加.catch
然后小括号
小括号里我们需要提供一个回调函数
这个函数主要的功能是处理捕捉到的错误
程序可以在捕获到这些错误后给用户显示提醒
或者跳到其他的页面
函数体里我们简单的打印promise rejected
我们就不做复杂的后续处理了
那现在我们来保存刷新页面看看程序还会不会报错
嗯,加了catch之后就不会报错
因为Uncaught的错误已经被catch捕获和进行处理了
这行语句有点长
把.then移到下一行
把.catch也移到下一行吧
这样可读性就提高了不少
在真实的代码里
一般我们需要从Promise里返回一些值
不然我们使用Promise就没有太大的意义
Promise返回值和普通函数返回值的方法是不一样的
我们在函数里一般使用return关键字返回值
但在Promise里我们不能那么做
即便我们把Promise赋予了p
但p被赋予的仅仅是一个Promise
不是最终值
最终值只有通过调用resolve或者reject才能得到
假设现在我们要把sent to airport
作为字符串本返回到then()
我们可以这样表示
我们先删掉这行console.log
接着在resolve的小括号里
输入from resolve(): sent to airport字符串
返回值的部分ok了
那接下来
我们来看要怎么在then()里获取这个返回值
要获取resolve返回的值
我们需要在then里的回调函数添加一个参数
我们叫它message吧
接着我们更新一下输出的信息
我们在console log里
打印从resolve返回的message
确认一下resolve是不是真的能返回值到调用代码
我们把sentToAirport设置成true
让Promise执行resolve函数
那现在我们来保存刷新验证一下
嗯,从resolve传回来的字符串成功显示了
当resolve函数被调用的时候
小括号里的值就会返回到then()里
这里除了能返回字符串
也能返回任何的JavaScript值
像数值,object等等
这些返回值会体现在回调函数里的参数
这样回调函数里的代码
就能使用这些返回值做进一步的处理
reject也能返回值
一般reject返回的值是错误信息
我给你们演示一下
假设司机取消了订单
我们可以在reject函数里输入
from reject(): order cancelled的字符串
接着我们在catch里的回调函数添加一个参数
也叫它message吧
console.log里还要修改一下
把返回值打印出来
接下来要把sentToAirport设置成false
让程序执行reject promise的部分
好的
现在我们保存刷新页面
看看console里打印些什么
console面板这里打印
from reject(): order cancelled - promise rejected
这部分是从reject返回的值
这也就证明了我们的catch语句成功获取reject返回的值
最后
我给你们演示一个在JavaScript程序里
常被调用的功能之一
那就是 Fetch()
我们可以使用Fetch发送网络请求
从后台服务器里获取数据
一般网络请求都是异步执行的
当程序成功发送网络请求后
会继续执行程序里的下一个任务
不会坐等服务器返回数据
因为程序不能预测服务器返回数据的时长
所以等待服务器返回数据就有可能阻塞JavaScript的运行
好的
现在给你们演示怎么调用fetch函数
先输入fetch
然后小括号
小括号里输入获取用户数据的网址
这里我们输入
https://jsonplaceholder.typicode.com/users
这个网站会返回JSON格式的用户数据
fetch函数会返回一个Promise object
我们可以把它赋予一个变量
像这样
现在f是一个Promise object
意味着f期望承诺会被履行
返回用户数据
当promise返回数据的时候
我们需要定义then和回调函数获取用户数据
我们在下一行输入f.then()
然后再输入回调函数
promise最终会返回用户数据
想在回调函数里获取用户数据
我们该怎么做?
对的
需要在回调函数添加一个参数
我们叫它userData吧
接着在函数体里把这些数据打印出来
我们来保存刷新页面
看看console里打印些什么
这数据的格式好像不太对
我们应该会得到JSON的格式
而不是这一些
估计我们要转换一下格式
我们在这里做一些修改
我们输入return userData.json()
我们先看这一部分userData.json()
它的意思是将userData的原始数据
转换成JSON格式的数据
json函数本身会返回一个Promise
就意味着json()函数也是异步执行的
不能在当下获取转换后的JSON数据
所以我们需要用return关键字
先返回 userData.json() 的Promise
这个Promise会返回到哪儿呢?
答案就是
下一个then()
所以我们需要在下一行添加一个then
才能获取最终的JSON格式
我们在下一行输入.then()
然后在小括号里输入回调函数
要获取userData.json()返回的数据
我们在参数列表里添加一个参数
叫它jsonData
最后我们在函数体里输入
console.log(jsonData)
把最终的用户数据打印出来
先保存一下代码
刷新页面看看我们能不能最终获取JSON格式的用户数据
嗯,是可以的
我们终于把远程服务器的用户数据拿到手了
如果程序需要进一步的处理数据
像数据筛选之类的任务
我们可以在下面
添加一个.then和回调函数去筛选数据
fetch从后台服务器获得原始数据后
会执行第一个then
进行格式转换
原始数据会体现在userData参数里
回调函数里的代码就可以获取
原始数据然后进行格式转换
格式转换是异步执行的
会返回另外一个Promise
所以需要用return关键字返回
这个Promise到下一个then
当这个新Promise完成数据转换后
它下面的then就会开始执行
转换后的数据会体现在jsonData里
所以当我们打印jsonData的时候
它会显示JSON版本的用户数据
而不是原始数据
同学们可能会觉得Promise的概念特别复杂
其实我刚开始接触Promise的时候也是觉得一头雾水
不过到最后用着用着也就上手了
所以同学们也不用太担心
我相信最后你们一定能掌握Promise的运用
好的,我们来总结一下今天的分享
Promise能有效的解决callback hell
这种解决方案让程序回调函数的时候
不会出现类似这样的嵌套回调地狱
使用Promise异步执行的程序
没办法在代码执行的那一刻马上得到结果
所以提供了resolve和reject函数
告知超长任务是否已完成
Then语句会在超长任务完成后被执行
一般Then语句里会编写处理超长任务返回数据的代码
一旦Promise被reject或者因为其他的错误拒绝履行承诺
程序就需要Catch语句捕捉这些错误
避免程序崩溃
好的,今天的分享就到这里
有疑问的话欢迎去到自学编程社区里提问
喜欢这个视频就拜托点赞分享吧
我们下期见,拜拜!
Comments
Post a Comment