【零基础JavaScript教程】#14 JavaScript Promise 是什么?异步(非同步)编程必须掌握的技巧 程序员终于可以逃出回调地狱callback hell了!!

 https://youtu.be/CTChl_DYTz0


☕ ☕ ☕ 如果觉得这些教学对你有用,那就请我喝杯咖啡吧! 我会继续为你创作更多免费的编程教学视频,让你轻松入门编程。 ✅ 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

Popular posts from this blog

【编程入门】使用 HTML CSS 制作登录页面 (零基础菜鸟必看) | How to create a login form in html css

怎么制作网页?仅使用html css制作你人生第一个专属网页 (免费网页设计教程) | How to create a website for free | 网页编程系列 第1集

2021 網頁編程自學小白要怎麼學才能真真快速入門編程? (內附路線圖+ 3個王牌技能) | Web Development Roadmap For Beginners 2021