前端开发:Promise详解

简介: 做过前端开发的都知道,JavaScript是单线程语言,浏览器只分配给JS一个主线程,用来执行任务,但是每次一次只能执行一个任务,这些任务形成一个任务队列排队等候执行;但是某些任务是比较耗时的,如网络请求,事件的监听,以及定时器,如果让这些非常耗时的任务一一排队等候执行,那么程序执行效率会非常的低,甚至会导致页面假死。

前言

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

一、首先,要知道为什么要用Promise语法?

在介绍Promise之前,首先来了解一下JavaScript的特性。搞前端开发的都知道JS是一个传统的单线程编程,它里面的程序运行都是同步的,只有一个主线程,但是随着技术的发展,为了解决前期的缺陷,引入了异步思想,也就是一个异步过程的执行将不再与原有的序列有顺序关系,这就解决了同步执行引起的执行效率不高的缺陷。用一句话解释:异步就是从主线程发射一个子线程来完成任务
再来了解一下Promise,Promise是ES6新增加的,它是一个由ES6提供的类,其主要目的就是很好的处理复杂的异步任务,但是它不是任何浏览器都能支持,比如一些旧版本的浏览器就不支持,只有苹果的Safari10和Windows的Edge14版本以上浏览器才开始支持ES6特性的。
Promise作为替代回调函数执行,作为异步操作的处理方法;是JS异步执行时候,回调函数嵌套回调函数的这一问题的解决方法,Promise更简洁地控制函数执行流程。Promise对象其实表示是一个异步操作的最终成败,以及结果值,也就是一个代理值,是ES6中的一种异步回调解决方案。
Promise对象代理的值其实是未知的,状态是动态可变的,因此Promise对象的状态有三种:进行中、结束、失败,它运行的时候,只能从进行中到失败,或者是从进行中到成功。使用Promise对象只要是通过同步的表达形式来运行异步代码。
①pending:初始状态,既不成功,也不失败;
②fulfilled:操作成功结束;
③rejected:操作失败。

1.png
流程图


怎么构造Promise?这里简单举一个构造Promise的示例:

new Promise(function (resolve, reject) {
   // 要做的事情...
});

通过上面新构造一个Promise 对象好像并没有看出它是怎样很好的处理复杂的异步任务的,那么接下来就是Promise的核心操作。

二、接着,来了解一下回调地狱(Callback Hell)

回调地狱也叫回调嵌套或者函数混乱的调用,通俗点讲就是:需要发送三个网络请求,第三个请求依赖第二个请求的结果,第二个请求依赖第一个请求的结果。不断增加的嵌套使用。
回调函数的弊病:
开发者阅读起来很费神、吃力,不利于排查错误,更不能直接return,等等。如:

setTimeout(() => {
    console.log(1)
    setTimeout(() => {
        console.log(2)
        setTimeout(() => {
            console.log(3)   
        },3000)         
    },2000)
  },1000)

三、最后,也是本章的重头戏,Promise的基本使用

Promise 构造函数只有一个参数,是一个函数,这个函数在构造之后会直接被异步运行,所以我们称之为起始函数。起始函数,也就是Promise的构造函数里面有两个参数:resolve和reject,该两个参数表示的是异步操作的结果,也就是Promise成功或失败的状态。
当 Promise 被构造时,起始函数会被异步执行;resolve 和 reject 都是函数,其中调用 resolve 代表一切正常,reject 是出现异常时所调用的。
①异步操作成功,调用resolve函数,将Promise对象的状态改为fulfilled。
②异步操作失败,调用rejected函数,将Promise对象的状态改为rejected。
举一个使用例子,比较规范的写法是把Promise封装到一个函数里然后同时返回一个Promise,如下所示:

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的返回结果值。

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。

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指定回调函数决定。实例如下所示:

let p=new Promise((resolve,reject)=>{
  resolve(‘yes’)
})

p.then(value=>{
  console.log(value)   //这里的value就是上面的yes
},reason=>{
  console.error(reason)  
})
  1. catch

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

let p =new Promise((resolve,reject)=>{
  reject('失败!’);
})
p.then(value=>{},reason=>{
  console.error(reason);
})
p.catch(reason=>{
  console.error(reason)
})
  1. finally

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

request.finally(function(){
    // 最后,而且一定会执行的代码
})
  1. Promise.all

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

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);
  1. Promise.race

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

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

最后

通过本文关于在前端JS开发中对Promise使用详解,是不是已经完全掌握它的使用以及原理呢?如果读者很好的掌握了本篇内容,那么以后不管是在实际开发过程中还是求职面试中,涉及到Promise的知识点都会游刃有余,Promise的重要性这里不再赘述。以上就是本章全部内容,欢迎关注!

相关文章
|
3天前
|
前端开发 JavaScript 开发者
前端开发中的异步编程:Promise 和 Async/Await 的比较与应用
在现代前端开发中,异步编程是不可或缺的技术。本文将深入探讨Promise和Async/Await这两种主流的异步编程方式,分析它们的优劣势及在实际项目中的应用场景。通过比较它们的语法、可读性和错误处理机制,帮助开发者更好地选择和理解如何在项目中高效地利用这些技术。
|
1天前
|
前端开发 JavaScript 测试技术
前端 JS 经典:Promise 详解
前端 JS 经典:Promise 详解
6 1
|
2月前
|
前端开发 JavaScript
前端 js 经典:Promise
前端 js 经典:Promise
26 1
|
2月前
|
存储 移动开发 前端开发
前端JS中的异步编程与Promise
在了解JavaScript的异步机制之前,我们首先需要理解JavaScript是一种单线程语言。单线程就意味着所有的任务需要按照顺序一次执行,如果前一个任务没有完成,后一个任务就无法开始。这个特性在执行大量或耗时任务时可能会导致阻塞或者界面卡死,这显然是不可取的。
|
11月前
|
前端开发
前端学习笔记202306学习笔记第四十二天-为什么需要promise之1
前端学习笔记202306学习笔记第四十二天-为什么需要promise之1
33 0
|
11月前
|
前端开发
前端学习笔记202306学习笔记第四十二天-promise-then的返回值3
前端学习笔记202306学习笔记第四十二天-promise-then的返回值3
29 0
|
2月前
|
前端开发 JavaScript
No101.精选前端面试题,享受每天的挑战和学习(Promise)
No101.精选前端面试题,享受每天的挑战和学习(Promise)
|
2月前
|
前端开发 JavaScript 开发者
【面试题】前端人70%以上 不了解的promise/async await
【面试题】前端人70%以上 不了解的promise/async await
|
2月前
|
存储 移动开发 前端开发
前端知识笔记(二十五)———JS中的异步编程与Promise
前端知识笔记(二十五)———JS中的异步编程与Promise
25 0
|
2月前
|
前端开发
【前端学习】—Promise基本知识(十六)
【前端学习】—Promise基本知识(十六)