稀土掘金 稀土掘金

大白话透彻讲解 Promise 的使用,读完你就懂了

一、为什么使用Promise?

我们知道 js 执行的时候,一次只能执行一个任务,它会阻塞其他任务。由于这个缺陷导致 js 的所有网络操作,浏览器事件,都必须是异步执行。异步执行可以使用回调函数执行。

常见的异步模式有以下几种:

  • 定时器
  • 接口调用
  • 事件函数
// setTimeout 示例
function callBack(){
 console.log('执行完成')
}
console.log('before setTimeout')
setTimeout(callBack,1000)// 1秒后调用callBack函数
console.log('after setTimeout')

运行后控制台输出结果为:

before setTimeout
after setTimeout
执行完成 //1秒后打印

上述定时器是在固定时间触发某个回调函数。

对于 ajax 网络请求就没有这么简单了,可能有多个网络请求是关联的,先执行某个请求返回结果后,第一个返回结果作为第二个请求的参数,调用第二个网络请求。如此,如果业务复杂,网络请求太多时,回调也很多,容易出现回调地狱。所以 Promise 出现了,专门解决异步回调地狱问题。

Promise 翻译成中文:承诺、保证。

通俗地讲,Promise 就像一个容器,里面存放着未来才会结束,返回结果的容器,返回的结果只需要在出口处接收就好了。从语法上讲,Promise 是一个对象,从它可以获取异步操作的消息。

二、Promise基本使用

下列用到的所有定时器模拟我们的 ajax 请求。

Promise 实例化的时候,传入的参数是一个函数,函数中接收两个参数:

const p = new Promise((resolve,reject)=>{
setTimeout(()=>{
 resolve('123')
 },1000)
}).then(res=>{
 console.log(res) //1秒后打印123
})

传入的 resolve 和 reject 本身都是函数。其作用分别为:

resolve - 把 Promise 的状态从进行中变为成功状态。

reject - 把 Promise 的状态从进行中变为拒绝状态。

Promise的三种状态:

pending :进行中,表示 Promise 还在执行阶段,没有执行完成。

fulfilled:成功状态,表示 Promise 成功执行完成。

rejected:拒绝状态,表示 Promise 执行被拒绝,也就是失败。

Promise 的状态,只可能是其中一种状态,从进行中变为成功或失败状态之后,状态就固定了,不会再发生改变。

Promise.then

执行 resolve 时,Promise 状态变为 fulfilled ,会执行 .then 方法。then 方法接收的参数也是一个函数,函数中携带一个参数,该参数是 resolve(res) 返回的数据。

const p = new Promise((resolve,reject)=>{
setTimeout(()=>{
 resolve('哎呦喂')
 },1000)
}).then(res=>{
 console.log(res) //1秒后打印哎呦喂
})

Promise.catch

执行 reject 时,Promise 状态从 pending 变为 rejected,会执行 catch 方法,catch 方法接收的也是一个函数,函数中携带一个参数,该参数为 reject(err) 返回的数据。

const p = new Promise((resolve,reject)=>{
 setTimeout(()=>{
  reject('error message')
  },1000)
 }).then(res=>{
  console.log(res)//不执行
 }).catch(err=>{
  console.log('err',err)//1秒后打印 error message
})

三、Promise 链式调用

制作一个模拟网络请求:

  • 第一次返回 a,
  • 修改返回的结果为 aa,作为第二次网络请求返回的结果。
  • 修改结果为 aaa,作为第三次返回结果。
const pp = new Promise((resolve,reject)=>{
 setTimeout(()=>{
  resolve('a')
 },1000)
}).then(res=>{
 console.log('res1',res) //1秒后打印 a
 return new Promise((resolve,reject)=>{
  setTimeout(()=>{
   resolve(res+'a')
   },1000)
 })
}).then(res=>{
  console.log('res',res) //2秒后打印 aa
  return new Promise((resolve,reject)=>{
   setTimeout(()=>{
    resolve(res+'a')
    },1000)
  })
 }).then(res=>{
  console.log('res3',res) //3秒后打印 aaa
})

这种场景其实就是接口的多层嵌套使用,Promise 可以把多层嵌套按照线性的方式进行书写,非常优雅。我们把 Promise 的多层嵌套调用就叫做链式调用。

上述实例,有三层嵌套就 new 了 3 个Promise,代码写得比较多,我们看看在实现功能的前提下如何能够简化。

四、Promise 嵌套使用的简写

promise传入的函数参数reject是一个非必传的参数,如果不需要处理失败时的结果时,我们可以省略掉 reject 。代码如下:

//简化1
const ppp = new Promise((resolve,reject)=>{
 setTimeout(()=>{
  resolve('a')
  },1000)
 }).then(res=>{
  console.log('res1',res)
  return new Promise(resolve=>resolve(res+'a'))
}).then(res=>{
 console.log('res',res)
 return new Promise(resolve=>resolve(res+'a'))
}).then(res=>{
 console.log('res3',res)
})

Promise 嵌套使用时,内层的 Promise 可以省略不写,所以我们可以直接把 Promise 相关的去掉,直接返回,代码如下:

//简化2
const pppp = new Promise((resolve,reject)=>{
 setTimeout(()=>{
  resolve('a')
 },1000)
}).then(res=>{
 return  res+'a'
}).then(res=>{
 return res+'a'
}).then(res=>{
 console.log('res3',res)
})

有的同学就在想,怎么都是成功状态的举例和简写,我们的失败状态catch可以简写吗?

答案是肯定的,我们简化为2层嵌套,与上述功能一致。

const ppppp = new Promise((resolve,reject)=>{
 setTimeout(()=>{
  reject('a')
 },1000)
}).catch(err=>{
 return new Promise((resolve,reject)=>{
  setTimeout(()=>{
   reject(err+'a')
  },1000)
 })
}).catch(err=>{
 console.log('err',err)
})

//简写1
const pppppp = new Promise((resolve,reject)=>{
 setTimeout(()=>{
  reject('a')
  },1000)
 }).catch(err=>{
  return new Promise((resolve,reject)=>reject(err+'a'))
 }).catch(err=>{
  console.log('err',err)
 })

//简写2
const ppppppp = new Promise((resolve,reject)=>{
 setTimeout(()=>{
  reject('a')
  },1000)
 }).catch(err=>{
  throw err+'a'
 }).catch(err=>{
  console.log('err',err)
})

注意:失败简写省略掉Promise时,使用的 throw 抛出异常。

五、Promise方法

5.1、all 方法

Promise.all 方法,提供了并行执行异步操作的能力,并且在所有异步操作完成之后,统一返回所有结果。具体使用如:

Promise.all([
 new Promise(resolve=>resolve('a')),
 new Promise(resolve=>resolve('b')),
]).then(res=>{
 console.log('all',res)//【'a' , 'b'】
 })

all 接收到的是一个数组,数组长度取决于 Promise 的个数。

一些游戏类的素材比较多的应用,打开网页时,预先加载需要用到的各类资源,所有的都加载完后,再进行页面的初始化。

5.2、race方法

race翻译成中文:赛跑。就是谁跑得最快,谁才能触碰到终点的胜利线。

Promise.race 用法与 all 一样,只是返回结果上不同,它返回的是执行最快的那个 Promise 的结果。

Promise.race([
 new Promise(resolve=>
  setTimeout(()=>{
   resolve('a')
   },100)
  ),
 new Promise(resolve=>
  setTimeout(()=>{
   resolve('a')
   },200)
  ),
 ]).then(res=>{
  console.log('race',res) // 返回 a
})

聚圣源末日小说名典公司起名网免费测试方法起名字女孩有个思教育机构起名字大全免费法证先锋4粤语在线观看武魔工作室起名测试免费猪年男宝宝起名大全喷泉公司起名大全1996年日历简捷五行八字起名测名称辰南免费起姓名评分网适合公司起名的卖酒公司起名巫师2攻略唢呐大全黄姓男孩起名字大全免费口袋e行销官网机甲之无尽升级道家起名琛怎么起名字装卸服务公司起名字大全网游之全球在线注册装饰公司起名字大全发财日记在线观看完整版男孩姓金起什么名字好激活英文特色小吃网淀粉肠小王子日销售额涨超10倍罗斯否认插足凯特王妃婚姻让美丽中国“从细节出发”清明节放假3天调休1天男孩疑遭霸凌 家长讨说法被踢出群国产伟哥去年销售近13亿网友建议重庆地铁不准乘客携带菜筐雅江山火三名扑火人员牺牲系谣言代拍被何赛飞拿着魔杖追着打月嫂回应掌掴婴儿是在赶虫子山西高速一大巴发生事故 已致13死高中生被打伤下体休学 邯郸通报李梦为奥运任务婉拒WNBA邀请19岁小伙救下5人后溺亡 多方发声王树国3次鞠躬告别西交大师生单亲妈妈陷入热恋 14岁儿子报警315晚会后胖东来又人满为患了倪萍分享减重40斤方法王楚钦登顶三项第一今日春分两大学生合买彩票中奖一人不认账张家界的山上“长”满了韩国人?周杰伦一审败诉网易房客欠租失踪 房东直发愁男子持台球杆殴打2名女店员被抓男子被猫抓伤后确诊“猫抓病”“重生之我在北大当嫡校长”槽头肉企业被曝光前生意红火男孩8年未见母亲被告知被遗忘恒大被罚41.75亿到底怎么缴网友洛杉矶偶遇贾玲杨倩无缘巴黎奥运张立群任西安交通大学校长黑马情侣提车了西双版纳热带植物园回应蜉蝣大爆发妈妈回应孩子在校撞护栏坠楼考生莫言也上北大硕士复试名单了韩国首次吊销离岗医生执照奥巴马现身唐宁街 黑色着装引猜测沈阳一轿车冲入人行道致3死2伤阿根廷将发行1万与2万面值的纸币外国人感慨凌晨的中国很安全男子被流浪猫绊倒 投喂者赔24万手机成瘾是影响睡眠质量重要因素春分“立蛋”成功率更高?胖东来员工每周单休无小长假“开封王婆”爆火:促成四五十对专家建议不必谈骨泥色变浙江一高校内汽车冲撞行人 多人受伤许家印被限制高消费

聚圣源 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化