【面试题】说说 Promise是什么?如何使用

简介: 【面试题】说说 Promise是什么?如何使用

大厂面试题分享 面试题库

前端面试题库 (面试必备)   推荐:★★★★★

地址:前端面试题库

前言

本文主要介绍和总结Promise的作用、使用方式和其对应的一些方法,供大家参考学习,如有写的不准确的地方欢迎大家指出,相互学习,共同进步!

一. 什么是Promise?

JavaScript的世界中,所有代码都是单线程执行的。由于这个“缺陷”,导致JavaScript的所有网络操作,浏览器事件,都必须是异步执行。异步执行可以用回调函数实现

function requestData(url, successCallback, failtureCallback) {
  // 模拟网络请求
  setTimeout(() => {
    // 拿到请求的结果
    // url传入的是localhost, 请求成功
    if (url === "localhost") {
      // 成功
      successCallback('success')
    } else { // 否则请求失败
      // 失败
      failtureCallback("error")
    }
  }, 3000);
}
//执行请求
requestData("kobe", (res) => {
  console.log(res)
}, (err) => {
  console.log(err)
})
复制代码

但实际开发过程中有些情况需要多次调用服务器API,就会形成一个链式调用,比如为了完成一个功能,我们需要调用API1、API2、API3,依次按照顺序进行调用,这个时候就会出现回调地狱的问题,即嵌套层次深,不好维护,可读性差。这时候就需要用到Promise

二. Promise使用方式

Promise 对象的构造器(constructor)语法如下:

// 传入的这个函数, 被称之为 executor
// > resolve: 回调函数, 在成功时, 回调resolve函数
// > reject: 回调函数, 在失败时, 回调reject函数
let promise = new Promise(function(resolve, reject) { // executor });
复制代码

executor 最终将 promise 移至以下状态之一:

executor 只能调用一个 resolve 或一个 reject。一旦状态被确定下来,Promise的状态会被锁死,该Promise的状态是不可更改的。

上方代码改写为Promise:

// request.js
function requestData(url,) {
  // 异步请求的代码会被放入到executor中
  return new Promise((resolve, reject) => {
    // 模拟网络请求
    setTimeout(() => {
      // 拿到请求的结果
      // url传入的是localhost, 请求成功
      if (url === "localhost") {
        // 成功
        resolve(success)
      } else { // 否则请求失败
        // 失败
        reject('error')
      }
    }, 3000);
  })
}
const promise = requestData("localhost")
//then方法是Promise对象上的一个方法:它其实是放在Promise的原型上的 Promise.prototype.then
promise.then((res) => {
  console.log("请求成功:", res)
}, (err) => { 
   console.log("请求失败:", err)
})
//等价于
promise.then((res) => {
  console.log("请求成功:", res)
}).catch(err => {//catch方法也是Promise对象上的一个方法:它也是放在Promise的原型上的 Promise.prototype.catch
console.log("请求失败:", err)
})
复制代码

当传入resolve不同的值的区别:

情况一:如果resolve传入一个普通的值或者对象,那么这个值会作为then回调的参数;

情况二:如果resolve中传入的是另外一个Promise,那么这个新Promise会决定原Promise的状态;

举例:

new Promise((resolve, reject) => {
  // pending -> fulfilled
  resolve(new Promise((resolve,reject)=>{
    setTimeout(()=>{resolve(111)},1000)
  }))
}).then(res => {
  console.log("res:", res) //111
}, err => {
  console.log("err:", err)
})
复制代码

情况三:如果resolve中传入的是一个对象,并且这个对象有实现then方法,那么会执行该then方法,并且根据 then方法的结果来决定Promise的状态;

举例:

// 2.传入一个对象, 这个兑现有then方法
new Promise((resolve, reject) => {
  // pending -> fulfilled
  const obj = {
    then: function(resolve, reject) {
      // resolve("resolve message")
      reject("reject message")
    }
  }
  resolve(obj)
}).then(res => {
  console.log("res:", res)
}, err => {
  console.log("err:", err)//reject message
})
复制代码

三. Promise实例方法

1. then方法

Promise的状态变成fulfilled的时候,then方法可以多次调用(同理状态变成reject的时候,catch也可以被多次调用) :

onst promise = new Promise((resolve, reject) => {
  resolve("hahaha")
})
promise.then(res => {
  console.log("res1:", res)
})
promise.then(res => {
  console.log("res2:", res)
})
promise.then(res => {
  console.log("res3:", res)
})
复制代码

then方法本身也是有返回值的, 它的返回值是Promise,我们可以进行链式调用。

promise.then(res => {
  return "aaaaaa"
}).then(res => {
  console.log("res:", res) //aaaaaa
  return "bbbbbb"
})
复制代码

then方法返回的Promise到底处于什么样的状态呢?

then方法中的回调函数本身在执行的时候,那么它处于pending状态;

then方法中的回调函数返回一个结果时,那么它处于fulfilled状态,并且会将结果作为resolve的参数;

then方法抛出一个异常时,那么它处于reject状态;

then传入不同值区别的同上方resolve相同,这边就不举例了,大家自己动手写一下。

2.catch 方法

catch方法也是会返回一个Promise对象的,所以catch方法后面可以继续调用then方法或者catch方法:

const promise = new Promise((resolve, reject) => {
  reject("111111")
})
promise.then(res => {
  console.log("res:", res)
}).catch(err => {
  console.log("err:", err)//111111
  // throw new Error('hhhhhh')
  return "catch return value"
}).then(res => {
  console.log("res result:", res) //catch return value
}).catch(err => {
  console.log("err result:", err)  
})
复制代码

 

提示:把上方注释的throw方法打开,方法会取下方catch部分

3.finally 方法

finally是在ES9(ES2018)中新增的一个特性:表示无论Promise对象无论变成fulfilled还是reject状态,最终都会被执行的代码。

finally方法是不接收参数的,因为无论前面是fulfilled状态,还是reject状态,它都会执行

const promise = new Promise((resolve, reject) => {
  // resolve("resolve message")
  reject("reject message")
})
promise.then(res => {
  console.log("res:", res)
}).catch(err => {
  console.log("err:", err)
}).finally(() => {
  console.log("finally code execute")
})
复制代码

四. Promise类方法

1.Promise.resolve

用法相当于new Promise,并且执行resolve操作:

// 1.普通的值
 const promise = Promise.resolve({ name: "why" })
// 相当于
 const promise2 = new Promise((resolve, reject) => {
   resolve({ name: "why" })
 })
复制代码

2.Promise.reject

用法相当于new Promise,只是会调用reject:

const promise = Promise.reject("rejected message")
//相当于
const promise2 = new Promsie((resolve, reject) => {
  reject("rejected message")
})
复制代码

3.Promise.all

作用是将多个Promise包裹在一起形成一个新的Promise,新的Promise状态由包裹的所有Promise共同决定:

当所有的Promise状态变成fulfilled状态时,新的Promise状态为fulfilled,并且会将所有Promise的返回值 组成一个数组;

当有一个Promise状态为reject时,新的Promise状态为reject,并且会将第一个reject的返回值作为参数;

// 创建多个Promise
const p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve(11111)
  }, 1000);
})
const p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject(22222)
  }, 2000);
})
const p3 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve(33333)
  }, 3000);
})
// 需求: 所有的Promise都变成fulfilled时, 再拿到结果
// 意外: 在拿到所有结果之前, 有一个promise变成了rejected, 那么整个promise是rejected
Promise.all([p2, p1, p3, "aaaa"]).then(res => {
  console.log(res)
}).catch(err => {
  console.log("err:", err)
})
复制代码

3.Promise.race

如果有一个Promise有了结果,我们就希望决定最终新Promise的状态,那么可以使用race方法

// 只要有一个Promise变成fulfilled状态, 那么就结束
// 意外: 
Promise.race([p1, p2, p3]).then(res => {
  console.log("res:", res)
}).catch(err => {
  console.log("err:", err)
})
复制代码

后记

大厂面试题分享 面试题库

前端面试题库 (面试必备)   推荐:★★★★★

地址:前端面试题库

相关文章
|
2月前
|
存储 前端开发 JavaScript
【面试题】Promise只会概念远远不够,还需这17道题目巩固!
【面试题】Promise只会概念远远不够,还需这17道题目巩固!
|
2月前
|
存储 前端开发 JavaScript
【面试题】面试官问:如果有100个请求,你如何使用Promise控制并发?
【面试题】面试官问:如果有100个请求,你如何使用Promise控制并发?
100 0
|
2月前
|
前端开发
【面试题】吃透Promise?先实现一个再说(包含所有方法)(二)
【面试题】吃透Promise?先实现一个再说(包含所有方法)(二)
|
2月前
|
存储 运维 前端开发
【面试题】吃透Promise?先实现一个再说(包含所有方法)(一)
【面试题】吃透Promise?先实现一个再说(包含所有方法)(一)
|
2月前
|
前端开发 JavaScript
【面试题】async/await、promise和setTimeout的执行顺序
【面试题】async/await、promise和setTimeout的执行顺序
|
2月前
|
存储 前端开发 JavaScript
面试官问:如果有100个请求,你如何使用Promise控制并发?
面试官问:如果有100个请求,你如何使用Promise控制并发?
115 0
|
2月前
|
前端开发 JavaScript
No101.精选前端面试题,享受每天的挑战和学习(Promise)
No101.精选前端面试题,享受每天的挑战和学习(Promise)
|
2月前
|
存储 前端开发 JavaScript
面试官:请手写一个Promise
面试官:请手写一个Promise
|
2月前
|
前端开发 JavaScript API
【面试题】面试官:为什么Promise中的错误不能被try/catch?
【面试题】面试官:为什么Promise中的错误不能被try/catch?
|
2月前
|
前端开发 JavaScript 开发者
【面试题】前端人70%以上 不了解的promise/async await
【面试题】前端人70%以上 不了解的promise/async await