Promise,async/await JavaScript中的期约和异步


前言

这一部分的理解在JavaScript的中也是比较复杂的东西,虽然对我来说,现阶段还没有什么大的影响,但实际上已经隐隐约约对我解决问题看待的思路和学习中有影响了。外加上一个师妹对这一部分很是迷惑,作为师兄证明能不挺身而出,手把手教学~~~~加上快要国庆了,上班摸鱼的时间多了,怎么能错过整理学习,铲除心中的迷惑的好机会呢


一、为什么需要异步

首先我们的JavaScript是单线程的。这必然导致很多的不便利,我们总不能等着前面的人慢慢的处理完它的事情才轮到我们,这样带浪费资源了、
举个例子:有客人来你家做客了,你爸叫你去泡茶,你需要洗杯子(3min),烧开水(15min),冲茶叶(1min),准备点心(2min)。那么要是单线程下来,是不是需要(3+15+1+2=21min)但实际上我们只需要16min,这就是在数学上的统筹,我们在一开始就烧开水,这个时间里,我们就可以做其他的事情,等到开水好了,其他的也就做完了,也就剩下冲茶叶了。
这就是我们需要对JavaScript进行优化调整的地方,也就是用到异步的思想。
再有个例子就是我们向服务器请求数据,我们不可能说等他好了才执行下面的操作,我们对请求的接口,往往会使用到ansyc 和 awite 来处理。

在这里插入图片描述

二、异步的过程

在这里插入图片描述

首先,我们来了一个任务,我们会先判断他是同步还是异步,同步的会直接进入到主线程执行,异步的会进入到任务队列,等待主线程的全部执行完后,再把任务队列的任务加载到主线程进行处理

如下:


function load (src, resolve) {
	let script = document.createElement('script')
	script.src = src;
	script.onload = resolve;
	document.body.appendChild(script);
}
//a();
//b();
load("a.js", () => {
    a();
})
load('b.js', () => {
    b();
})

console.log('------->666666');

我们创建加载脚本,脚本是“异步”调用的,因为它从现在开始加载,但是在这个加载函数执行完成后才运行。

所以这里会优先执行输出666666,再来执行js的,因为后两者属于异步,同时我们会发现这里a和b的输出顺序会有时不同,这是应为他们是按照谁先加载完成,谁就先加入到任务队列中的。同时我们不能直接调用脚本里面的方法,因为我们不知道脚本什么时候加载完成,我们需要把调用写到回调函数里面去。
在这里插入图片描述
那么我们要是想先输出a再来输出b呢,或者说a的值依赖于b的返回值呢?这里就要嵌套回调,那么要把b写到a的回调函数里面了。这样我们可想而知,当只是一两个的时候,我们还比较好处理,但是当我们在b中还需要调用一个c呢?c中再调用一个d呢?…这时候,非常的不便于维护,代码的层次也变得很深,回调地狱就出现了~~~
为了解决上面的问题,我们就有了promise(期约)的出现

三、promise(期约)

1.期约状态

首先期约有是三个状态

  • 待定(pending)
  • 兑现(fulfilled)
  • 拒绝(rejected)

console.log(new Promise((resolve, reject) => {}));
console.log(new Promise((resolve, reject) => {
    resolve('成功')
}));
console.log(new Promise((resolve, reject) => {
    reject('失败')
}));

结果如图:在这里插入图片描述

2.期约的注意点

Promise有几个点要注意的:

  • 三个状态,能且只能处于其中之一。
  • 状态的改变通过执行器函数改变,通常命名为resolve 和 reject,状态改变为兑现和拒绝。
  • Promise 解决的是异步编码风格的问题,不是其他的问题~~~

promise的使用

  • then:为期约实例添加处理程序
  • catch:为期约实例添加拒绝处理程序
  • finally:这个是无法知道期约状态的,所以一般用来清理代码
let p = new Promise((resolve, reject) => {
    console.log('initial promise reject');
    reject()
});

p.catch(()=> console.log('reject handler'))
 .then(()=> console.log('resolve handler'))
 .finally(()=> console.log('finally handler'))

console.log('1');

结果如图:
在这里插入图片描述

在 new Promise()的时候,Promise的执行器就会立马执行
输出:initial promise reject

但是调用reject()会触发异步操作,传入的then()方法的函数会被添加到任务队列并异步执行

所以先输出:1,才有后面的输出。

使用promise,它的三个方法都是返回期约的,所以有效的解决了回调地狱的问题。

3.微任务

那么promise里添加的任务会添加到哪里去呢?其实这里还有一个叫微任务的概念
在这里插入图片描述
我们把消息队列中的任务称为宏任务,每个宏任务中都包含了一个微任务队列,等宏任务中的主要功能都直接完成之后,这时候,渲染引擎并不着急去执行下一个宏任务,而是执行当前宏任务中的微任务先。

总结来说:每一个宏任务都有对应的微任务,该宏任务的微任务会在下一个宏任务执行前先执行,微任务的执行时长会影响计算到当前宏任务的执行时长。当当前的宏任务回调创建到宏任务和微任务时,微任务会先执行

四、await/async

await/async是对promise的进一步优化,Promise 的编程方式,当比较复杂的情况,会有大量的 then 方法,虽然解决了回调地狱的问题,但是在语义,阅读性等,还是很不便,这就是 async/await 出现的原因,使用 async/await 可以实现用同步代码的风格来编写异步代码

async
用来声明异步函数,使其具有异步特性,返回的是一个期约对象

await
可以暂停异步函数的执行,等待期约的解决

红宝石上面的一个例子:

async function foo() {
	console.log(2);
	console.log( await Promise.resolve(8));
	console.log(9);
}
async function bar() {
	console.log(4);
	console.log( await (6));
	console.log(5);
}

console.log(1);
foo();
console.log(3);
bar();
console.log(5);


 //输出结果:1 2 3 4 5 6 7 8 9

(1) 打印1;
(2) 调用异步函数foo();
(3) (在foo()中)打印2;
(4) (在foo中) await 关键字暂停执行,向消息队列中添加一个期约在落定之后执行的任务
(5) 期约立即落定、把给 await 提供的任务添加到消息队列;
(6) foo()退出
(7) 打印3;
(8) 调用异步函数bar();
(9) (在bar()中)打印4;
(10) (在bar()中) await关键暂停执行,为立即可用的值6向消息队列中添加一个任务;
(11) bar()退出;
(12) 打印5
(13) 顶级线程执行完毕;
(14) javaScript行时从消息队列中取出解决 await期约处理程序,并将解决的值8提供给它;
(15) JavaScript行时向消息队列中添加一个恢复执行foo()函数的任务;
(16) JavaScript行时从消息队列中取出恢复执行bar()的任务及值6;
(17) (在bar()中)恢复执行, await取得值6;
(18) (在bar()中)打印6;
(19) (在bar()中)打印7
(20) bar()返回;
(21) 异步任务完成, JavaScript消息队列中取出恢复执行foo()的任务及值8;
(22) (在foo()中)打印8;
(23) (在foo()中)打印9;
(24) foo()返回。


总结

提示:这里对文章进行总结:
例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

文默

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值