乐趣区

javascript异步与promise

同期异步系列文章推荐谈一谈 javascript 异步 javascript 异步中的回调 javascript 异步之 Promise.all()、Promise.race()、Promise.finally()javascript 异步之 Promise.resolve()、Promise.reject()javascript 异步之 Promise then 和 catchjavascript 异步之 async(一)javascript 异步之 async(二)javascript 异步实战 javascript 异步总结归档
我们说处理 javascript 异步最常用的方式就是通过回调函数,对于回调函数我们昨天对此做了介绍简单快速,我们一般使用嵌套回调或者链式回调,会产生以下问题

当采用嵌套回调时,会导致层级太多,不利于维护
所以我们又采用了链式回调,对嵌套回调进行拆分,拆分后的函数间耦合度很高,
如果需要传递参数,函数之间的关联性会更高,而且要对参数进行校验以提高代码的健壮性

如果将我们自己的回调函数传递给第三方插件或者库,就要考虑一些不可控因素

调用回调过早
调用回调过晚(或不被调用)
调用回调次数过多或者过少

promise 的存在就是为了解决以上问题虽然我们日常写回调函数不会有这么严格的要求,但是如果不这样去写回调函数,就会存在隐患,当在团队协作的时候,显得编码规范显得尤为重要
本文不重点介绍如何使用 promise,重点介绍的是 promise 解决了哪些异步回调出现的问题。
什么是 promise
我们来看一个场景,有助于我们了解 promise
设想一下这个场景,我去 KFC,交给收银员 10 元,下单买一个汉堡,下单付款。到这里,我已经发出了一个请求(买汉堡),启动了一次交易。但是做汉堡需要时间,我不能马上得到这个汉堡,收银员给我一个收据来代替汉堡。到这里,收据就是一个承诺 (promise), 保证我最后能得到汉堡。所以我需要好好的保留的这个收据,对我来说,收据就是汉堡,虽然这张收据不能吃,我需要等待汉堡做好,等待收银员叫号通知我等待的过程中,我可以做些别的事情收银员终于叫到了我的号,我用收据换来了汉堡当然还有一种情况,当我去柜台取汉堡的时候,收银员告诉我汉堡卖光了,做汉堡的师傅受伤了等等原因,导致了我无法得到这个汉堡虽然我有收据(承诺),但是可能得到汉堡(成功),可能得不到汉堡(失败)我由等待汉堡变成了等到或者等不到,这个过程不可逆,
上面很形象的介绍了 promise,上面的等待汉堡和得到汉堡,汉堡卖光了,得不到汉堡,分别对应 promise 的三种状态三种状态:pending(进行中)、fulfilled(已成功)和 rejected(已失败)(一旦状态改变,就不会再变)
回调函数调用过早
调用过早就是将异步函数作为同步处理了,我们之前说过,javascript 以单线程同步的方式执行主线程,遇到异步会将异步函数放入到任务队列中,当主线程执行完毕,会循环执行任务队列中的函数,也就是事件循环,直到任务队列为空。
事件循环和任务队列
事件循环就像是一个游乐场,玩过一个游戏后,你需要重新排到队尾才能再玩一次任务队列就是,在你玩过一个游戏后,可以插队接着玩
我们看一个栗子
const promise = new Promise((resolve, reject) => {
resolve(“ 成功啦 ”)
});
promise.then(res => {
console.log(res);
console.log(“ 我是异步执行的 ”);
})
console.log(‘ 我在主线程 ’);
看下输出,重点看输出顺序
// 我在主线程
// 成功啦
// 我是异步执行的
直接手动是 promise 的状态切为成功状态,console.log(“ 我是异步执行的 ”); 这段代码也是异步执行的提供给 then() 的回调永远都是异步执行的,所以 promise 中不会出现回调函数过早执行的情况
回调函数调用过晚或不被调用
回调函数调用过晚
回调函数调用过晚的处理原理和调用过早很类似,在 promise 的 then() 中存放着异步函数,所有的异步都存在于 js 的任务队列中,当 js 的主线程执行完毕后,会依次执行任务队列中的内容,不会出现执行过晚的情况
回调函数不被调用
我们用栗子说话
const promise = new Promise((resolve, reject) => resolve(‘ 成功啦 ’))
promise.then(s => console.log(s));
console.log(‘ 我在主线程 ’);
成功状态的输出
// 我在主线程
// 成功啦
成功状态下回调被调用继续看一下失败的回调
const promise = new Promise((resolve, reject) => reject(‘ 失败啦 ’))
promise.then(null, s => console.log(s));
console.log(‘ 我在主线程 ’);
失败状态的输出
// 我在主线程
// 失败啦
失败状态下回调被调用所以说,不管是失败还是成功,回调函数都会被调用
回调函数调用次数过多或者过少
调用次数过多
我们之前说了 promise 有三种状态 pending(进行中)、fulfilled(已成功)和 rejected(已失败)状态一旦状态改变,就不会再变一个栗子
const promise = new Promise((resolve, reject) => {
reject(‘ 失败啦 ’)
resolve(‘ 成功啦 ’)
});
promise.then(res => {
console.log(` 我是异步执行的成功:${res}`);
},err=>{
console.log(` 我是异步执行的失败:${err}`);
}).catch(err => {
console.log(err);
})
console.log(‘ 我在主线程 ’);
输出
// 我在主线程
// 我是异步执行的失败: 失败啦
当状态变为失败时,就不会再变为成功,成功的函数也不会执行,反之亦然
调用次数过少
回调函数正常是调用一次,过少 =>0 次 => 回调函数不被调用,上面刚刚讨论过
原文链接
参考链接 JavaScript Promise 迷你书 Promise 对象 ES6 系列之我们来聊聊 Promise

退出移动版