前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JavaScript开发中关于Promise的使用详解

JavaScript开发中关于Promise的使用详解

原创
作者头像
三掌柜
发布2024-09-24 23:30:56
1381
发布2024-09-24 23:30:56
举报
文章被收录于专栏:三掌柜的技术空间

目录

  • 前言
  • 为什么要用Promise语法?
  • 回调地狱(Callback Hell)
  • Promise的基本使用
  • 结束语

前言

做过前端开发的都知道,JavaScript是单线程语言,浏览器只分配给JS一个主线程,用来执行任务,但是每次一次只能执行一个任务,这些任务形成一个任务队列排队等候执行;但是某些任务是比较耗时的,如网络请求,事件的监听,以及定时器,如果让这些非常耗时的任务一一排队等候执行,那么程序执行效率会非常的低,甚至会导致页面假死。因此,浏览器为这些耗时的任务开辟了新的线程,主要包括http请求线程、浏览器事件触发线程、浏览器定时触发器,但是这些任务都是异步的,这就涉及到了前端开发的异步回调操作处理,前端处理异步回调操作用到的就是Async/Await和Promise。而且在前端相关的面试的时候,面试官一般都会问到关于Promise相关的使用问题,甚至在笔试中也会出一些关于Promise和setTimeout的执行结果,这说明Promise的使用对于前端开发来说是非常重要的一个知识点。那么本篇博文就来分享一下关于Promise的使用相关的知识点。

为什么要用Promise语法?

Promise作为替代回调函数执行,作为异步操作的处理方法;是JS异步执行时候,回调函数嵌套回调函数的这一问题的解决方法,Promise更简洁地控制函数执行流程。Promise对象其实表示是一个异步操作的最终成败,以及结果值,也就是一个代理值,是ES6中的一种异步回调解决方案。

Promise对象代理的值其实是未知的,状态是动态可变的,因此Promise对象的状态有三种:进行中、结束、失败,它运行的时候,只能从进行中到失败,或者是从进行中到成功。使用Promise对象只要是通过同步的表达形式来运行异步代码。

①pending:初始状态,既不成功,也不失败;

②fulfilled:操作成功结束;

③rejected:操作失败。

具体的流程图如下所示:

回调地狱(Callback Hell)

回调地狱也叫回调嵌套或者函数混乱的调用,通俗点讲就是:需要发送三个网络请求,第三个请求依赖第二个请求的结果,第二个请求依赖第一个请求的结果。不断增加的嵌套使用。

回调函数的弊病:开发者阅读起来很费神、吃力,不利于排查错误,更不能直接return,等等。如:

代码语言:txt
复制
setTimeout(() => {
 
    console.log(1)
 
    setTimeout(() => {
 
        console.log(2)
 
        setTimeout(() => {
 
            console.log(3)   
 
        },3000)         
 
    },2000)
 
  },1000)
 

Promise的基本使用

Promise构造函数里面有两个参数:resolve和reject,该两个参数表示的是异步操作的结果,也就是Promise成功或失败的状态。

①异步操作成功,调用resolve函数,将Promise对象的状态改为fulfilled。

②异步操作失败,调用rejected函数,将Promise对象的状态改为rejected。

举一个使用例子,比较规范的写法是把Promise封装到一个函数里然后同时返回一个Promise,如下所示:

代码语言:txt
复制
const delay = (millisecond) => {
 
  return new Promise((resolve, reject)=>{
 
      if (typeof millisecond != 'number') reject(new Error(‘必须是number类型'));
      setTimeout(()=> {
        resolve(`延迟${millisecond}毫秒后输出`)
      }, millisecond)
  })
}

上述例子可以看到Promise有两个参数:resolve和reject。resolve:将异步的执行从pending(请求)变成了resolve(成功返回),是个函数执行返回;reject:见名知意为“拒绝”,从请求变成了"失败",是函数可以执行返回的一个失败结果,推荐返回一个错误new Error(),这样做更加清晰明了,更加规范。

(一) resolve函数

若传入的是非Promise,基本数据类型的数据,则返回成功的Promise;若传入的是Promise,则该对象的结果就决定了resolve的返回结果值。

代码语言:txt
复制
let obj =new Promise((resolve,reject)=>{
 
  resolve(‘yes’);
 
});
 
//1.若传入的是非Promise,基本数据类型的数据,则返回成功的Promise。
 
let p1= Promise.resolve(’123’)
 
//2.若传入的是Promise,则该对象的结果就决定了resolve的返回结果值。
 
let p2 = Promise.resolve(obj);
 
//3.嵌套使用
 
let p3 = Promise.resolve(Promise.resolve(Promise.resolve('abc')));
 
console.log(p3);

(二) rejected函数

Promise.prototype.reject,始终返回的是失败的Promise。

代码语言:txt
复制
let p = Promise.reject(123123);
 
let p2 = Promise.reject('abc');
 
let p3 = Promise.reject(Promise.resolve('ok'));
 
console.log(p3);

(三)Promise的API

Promise的API里面常用的几个方法有:then、catch、finally、all、race等,具体的使用方法下面一一道来。

1.then

then指定成功或失败的回调到当前的Promise。then里面拿到的Promise resolve里面的数据,并返回一个Promise继续提供使用;then方法返回的结果由then指定回调函数决定。实例如下所示:

代码语言:txt
复制
let p=new Promise((resolve,reject)=>{
 
  resolve(‘yes’)
 
})
 
p.then(value=>{
 
  console.log(value)   //这里的value就是上面的yes
 
},reason=>{
 
  console.error(reason)  
 
})

2. catch

catch指定失败的回调,返回的是失败的结果。实例如下所示:

代码语言:txt
复制
let p =new Promise((resolve,reject)=>{
 
  reject('失败!’);
})
p.then(value=>{},reason=>{
  console.error(reason);
})
p.catch(reason=>{
  console.error(reason)
})

3.finally

finally用来进行收尾工作,无论Promise的状态成功和失败与否,当执行完回调函数之后,都会去finally寻找最后的回调函数来执行。实例如下所示:

代码语言:txt
复制
request.finally(function(){
 
    // 最后,而且一定会执行的代码
 
})

4. Promise.all

在多个Promise任务一起执行的时候,若全部成功,则返回一个新的Promise,若其中有一个失败,则返回失败的Promise对象。实例如下所示:

代码语言:txt
复制
let p1 = new Promise((resolve, reject) => {
 
  setTimeout(() => {
 
    resolve(‘yes’);
 
  }, 1000);
 
});
 
let p2 = Promise.resolve('ok');
 
let p3 = Promise.reject('Oh no’);
//所有的
let result = Promise.all([p1, p2, p3]);
console.log(result); 

5.Promise.race

在多个Promise任务同步执行的时候,返回最先结束的Promise任务结果,无论最后是成功还是失败,通俗点将:先到先得。实例如下所示:

代码语言:txt
复制
let p1 = new Promise((resolve, reject) => {
 
  setTimeout(() => {
 
    resolve(‘yes’);
 
  }, 1000);
 
});
 
let p2 = new Promise((resolve, reject) => {
 
  setTimeout(() => {
 
    resolve('ok');
 
  }, 500);
 
});
 
let result = Promise.race([p1, p2]);
 
console.log(result);   //p2  ok

结束语

通过上文关于Promise的详细介绍,结合Async/Await和Promise的对比可以知道Async/Await是近年来JS新增的最具革命性的特性之一,Async/Await会让你看到Promise的语法有多糟糕,而且提供了一个直观的替代方法。但是对于Async/Await你肯定也许会有一些怀疑和顾虑,因为Node7不是LTS(长期支持版本),但是代码迁移很简单,不必担心版本是否稳定的问题。还有就是大部分开发者已经习惯了使用回调函数或者.then来识别异步代码,Async/Await使得异步代码不在“明显”(因为Async/Await使得代码看起来像同步代码),但是在了解使用之后,会很快消除这种短暂的不适应。其实上述两点只是分析一下未来的趋势,但是短期内Promise肯定不会因为Async/Await的出现而立马淘汰出局,也可以说正是有了Promise才有了升级改良版的Async/Await,二者是相互依存,缺一不可的,要想学好前端开发的Async/Await,学习好Promise是前提。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 目录
  • 前言
  • 为什么要用Promise语法?
  • 回调地狱(Callback Hell)
  • Promise的基本使用
    • (一) resolve函数
      • (二) rejected函数
        • (三)Promise的API
          • 1.then
          • 2. catch
          • 3.finally
          • 4. Promise.all
          • 5.Promise.race
      • 结束语
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档