关于前端:🔥2022最全Promise合集

前言

Promise作为异步编程的一种解决方案,无论什么阶段的前端都是须要牢牢把握,在面试中也是属于必问的。

一、高频概念问答

1、你了解的Promise?

<details>

<summary><font color=blue>参考</font></summary> 

Promise是ES6中异步编程的一种解决方案;它是为了解决异步链式调用呈现的回调天堂问题;有三种状态pending进行中、fulfilled胜利、rejected失败,且状态一旦扭转不可逆;promise.then()是微工作
</details>

2、Promise罕用办法?

<details>

<summary><font color=blue>参考</font></summary> 

Promise.all、Promise.allSettled、Promise.any、Promise.race、Promise.resolve、Promise.reject
</details>

3、你了解的async和await?

<details>

<summary><font color=blue>参考</font></summary> 

async是ES7中对于异步操作的解决方案,它是Generator函数的语法糖,解决了promise链式调用的问题,用同步的形式去执行异步;
</details>

4、Promise.all,Promise.race区别

<details>

<summary><font color=blue>参考</font></summary> 

Promise.all() 全副promise胜利才算胜利,一个promise就算失败,返回胜利的数据数组,失败抛出最先失败的promise的reason。 Promise.race() 最先的promise实现则返回,promise后果和最先实现的promise统一
</details>

5、执行程序?

难度 ⭐⭐⭐

    1. 执行宏工作的过程中,遇到微工作,顺次退出微工作队列;
    1. 当某个宏工作执行完后,会查看是否有微工作队列;
    2. 有,执行微工作队列中的所有工作;
    3. 没有,读取宏工作队列中最后面工作;
    1. 栈空后,再次读取微工作队列里的工作,顺次类推
async function async1() {
    console.log('async1 start');
    await async2();
    console.log('async1 end');
}

async function async2() {
    console.log('async2');
}

console.log('script start');

setTimeout(function() {
    console.log('setTimeout');
}, 0)

async1();

new Promise(function(resolve) {
    console.log('promise1');
    resolve();
}).then(function() {
    console.log('promise2');
});

console.log('script end');

// 输入后果

script start
async1 start
async2
promise1
script end
async1 end
promise2
setTimeout

难度 ⭐⭐⭐⭐

// 在上题中做了一点改变

async function async1() {
    console.log('async1 start');
    await async2();
    console.log('async1 end');
}
async function async2() {
    //async2做出如下更改:
    new Promise(function(resolve) {
    console.log('promise1');
    resolve();
}).then(function() {
    console.log('promise2');
    });
}
console.log('script start');

setTimeout(function() {
    console.log('setTimeout');
}, 0)
async1();

new Promise(function(resolve) {
    console.log('promise3');
    resolve();
}).then(function() {
    console.log('promise4');
});

console.log('script end');

// 输入后果
script start
async1 start
promise1
promise3
script end
promise2
async1 end
promis4
setTimeout

难度 ⭐⭐⭐⭐

console.log('start')
 setTimeout(()=>{
    console.log("children2")
    Promise.resolve().then(()=>{
        console.log("children3")
    })
 },0)
 
 new Promise(function(resolve,reject){
     console.log('children4')
     setTimeout(()=>{ //重点
        console.log("children5")
        resolve("children6")
     },0 )
 }).then(res=>{
     console.log("children7")
     setTimeout(()=>{
        console.log(res)
     },0)
 })
 
 // 输入后果
 start
 children4
 //第一轮宏工作完结 尝试清空微工作队列 没有微工作
 children2
 //第二轮宏工作完结 尝试清空微工作队列 
 children3
 //第三轮
 children5
 children7
 children6

二、手撕代码

手写 Promise 和 Promise.all 是面试频率最高的;

1、Promise.all 难度⭐⭐⭐

列举几个关键点:

  • 1.return Promise 返回也是Promise
  • 2.参数类型判断,传入的参数必须是数组;
  • 3.数组元素类型,判断传入的值是否是promise,应用Promise.resolve 办法会把参数转化为promise;
  • 4.返回后果程序问题;

    function PromiseAll(promiseArray){
      return new Promise((resolve,reject)=>{
          // !!! 考点1
          if(!Array.isArray(promiseArray)){
              return reject(new Error('传入的参数必须是数组'))
          }
          const result = []
          let counter = 0
          const promisenNums = promiseArray.length
          
          // !!! 考点2 判断传入的值是否是promise
          //Object.prototype.toString.call==='[object Promise]'
          
          for(let i = 0 ;i < promisenNums ; i++){
              //Promise.resolve 办法会把参数转化为promise
              Promise.resolve(promiseArray[i]).then(value=>{
                  // push会造成数据错乱 用count计数,不必长度判断
                  // result.push(value)
                  // if(result.length === promisenNums){
                  //     resolve(result)
                  // }
                  //!!! 考点3 promise的程序问题下面的形式疏忽了promise的程序问题
                  
                  counter++;
                  result[i] = value;
                  if(counter === promisenNums){
                      resolve(result)
                  }
              }).catch(e=>reject(e))
          }
      })
    }

    2、Promise 难度⭐⭐⭐⭐

    举荐文章 硬核! 手把手教你写A+标准的Promise

    class Promose {
      constructor(executor){
          this.status = 'pending'
          this.value = null 
          this.reason = null
          
          this.onResolvedCallbacks = [] //寄存胜利的回调函数 新加
          this.onRejectedCallbacks = [] //寄存失败的回调函数 新加
    
    
          //reslove函数
          const resolve = (value) => {
              if(this.status === 'pending'){
                   this.status = 'fulfilled'
                   this.value = value 
    
                   //执行所有的订阅的fulfilled函数 新加
                  this.onResolvedCallbacks.forEach(fn=>fn())
              }
          }
          //reject函数
          const reject = (reason) => {
              if(this.status === 'pending'){
                  this.status = 'rejected'
                  this.reason = reason
    
                  //执行所有的订阅的rejected函数
                  this.onRejectedCallbacks.forEach(fn=>fn())
              }
          }
          try{
              executor(resolve,reject)
          }catch(err){
              reject(err)
          }
      }
    
      then(onFulfilled,onRejected){
          //胜利的回调
          if(this.status = 'fulfilled'){
              onFulfilled(this.value)
          }
          //失败的回调
          if(this.status = 'rejected'){
              onRejected(this.reason)
          }
    
          //如果是期待状态,就把res,rej的解决回调函数放入对应的队列 新加
          if(this.status ==='pending'){
              //放入胜利回调队列
              this.onResolvedCallbacks.push(()=>{
                  //写额定的逻辑
                  onFulfilled(this.value)
              })
    
              //放入失败回调队列
              this.onRejectedCallbacks.push(()=>{
                  //写额定的逻辑
                  onRejected(this.reason)
              })
          }
      }
    }

    3、其余手撕 难度⭐⭐⭐

    掘金有看到其余大佬的文章,就不反复造车,间接上链接

    看了就会,手写 Promise 全副 API 教程

三、大厂真题

1、应用Promise实现每隔1秒输入1,2,3,4?

const arr = [1, 2, 3 , 4]
arr.reduce((p, x) => {
  return p.then(() => {
    return new Promise(r => {
      setTimeout(() => r(console.log(x)), 1000)
    })
  })
}, Promise.resolve())

2、Promise做缓存?

场景:一个频繁调用接口的办法在多处应用


const cacheMap = new Map(); //用一个Map来存

function enableCache(target, name, descriptor) {
    const oldValue = descriptor.value; //拿到原来的办法

    descriptor.value = function(...args) { //重写这个办法
        //因为申请的参数必定会不一样,所以要定义一个的key
        const cacheKey = name + JSON.stringify(args);
        if (!cacheMap.get(cacheKey)) {
            //为什么要加catch 因为你的申请有可能会报错
            const cacheValue = Promise.resolve(oldValue.apply(this, args)).catch(_ => {
                cacheMap.set(cacheKey, null) //报错了,设置成null
            })
            cacheMap.set(cacheKey, cacheValue)
        }
        return cacheMap.get(cacheKey); //把缓存拿进去即可,无须再去http申请,无须再去申请服务端
    }
    return descriptor;
}

class PromiseClass {
   //装璜器
   @enableCache
   static async getInfo() {}
}

// 应用
PromiseClass.getInfo()
PromiseClass.getInfo()
PromiseClass.getInfo()

未完 继续补充欠缺

❤️感激浏览

  1. 如果本文对你有帮忙,不要悭吝你的赞哟,你的「赞」是我前行的能源;
  2. 欢送关注公众号  【冥想侃前端】  一起学习提高。

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理