dljia
  • 前言
  • es6
    • promise
    • 箭头函数
  • http相关
    • ajax请求中contentType和dataType
    • async和defer的区别
    • cookie、session和token
    • http协议介绍
    • http缓存
    • 转发和重定向
  • js
    • 1-js深浅复制
    • 10-节流防抖
    • 11-Promise常见手写
    • 2-js函数值传递
    • 3-js原型链详解
    • 4-js基础讲解this篇
    • 5-call、apply和bind
    • 6-js中的继承
    • 7-闭包与立即执行函数
    • 8-js事件循环
    • 9-js模块化
  • react
    • React-diff
    • React-fiber
    • React组件设计规则
    • mvc与mvvm
    • react-router
    • react懒加载
    • redux
    • setState源码分析
    • webpack+react从0项目构建
  • ts
    • Typescript编程书籍导读
    • 体操基础
  • 其他
    • gitbook简易配置教程
    • gitbook转pdf电子书
  • 微前端
    • pnpm
    • qiankun
    • single-spa源码分析
    • 几种微前端架构的选型
  • 转载
    • interview-1
    • interview-2
    • interview-3
    • 经验好文
  • 项目经验
    • 23年总结
    • [Arkts 学习笔记](项目经验/Arkts 学习笔记.md)
    • Grafana插件
    • JSDoc
    • electron-builder构建的安装包,安装时通过nsis脚本自动导入注册表
    • overflow-yautohiddenscroll和overflow-xvisible组合渲染异常
    • webpack
    • 前端工程化
    • 前端性能优化思路
    • 前端性能监控工具
    • 前端架构
    • 前端登录流程
    • 前端监控原理
    • 团队管理
    • 基于node实现简单server
    • 如何对业务进行深挖
    • 如何拉齐横向
    • 如何画图
    • 如何记录
    • 组件库
Powered by GitBook
On this page

Was this helpful?

  1. js

11-Promise常见手写

首先做个总结,凡是跟promise相关的手写,返回值一定是个promise

  1. 重试

    思路: 重试和all基本是最简单的了。随便网上抄了一个

    Promise.retry = (fn, options = {}) => {
    
      if (!isFunction(fn)) throw new Error('fn is not a function')
      
      const { max = 3, delay = 0 } = options
      let curMax = max
      const delayExec = () => delay && new Promise(resolve => setTimeout(resolve, delay))
    
      return new Promise(async (resolve, reject) => {
        while (curMax > 0) {
          try {
            const res = await fn()
            resolve(res)
            return
          } catch (error) {
            await delayExec()
            curMax--
            console.warn(`剩余次数${curMax}`)
            if (!curMax) reject(error)
          }
        }
      })
    }
    
  2. promise 实现一个最大并发

    思路:这个东西乍一看还不太好在面试当中写出来,写法思路可能有很多,说下我的思路

    • 注意返回值仍然是个promise 用来处理异步错误异常捕获以及回调

    • 用变量记录当前pending队列 每次执行请求时向pending队列中加入一个等待执行函数

    • 用变量记录当前执行中的函数数量,如果请求数没超过当前限制,触发请求,每次执行请求时+1

    • 实现一个迭代执行函数,实现就是从pending队列中取一个出来执行,执行后判断队列中是否还有没执行的,有的话继续调用。

    function asyncPool(promiseFn, limit) {
      // 记录当前请求数
      let currentRunFnNum = 0;
      // 记录当前pending队列
      let pendingList = [];
      
      function run() {
          const [runTask,resolve, reject, ...params] = pendingList.shift();
          runTask(...params).then(resolve).catch(reject).finnal(()=>{
              currentRunFnNum -= 1;
              if(pendingList.length >0) {
                  run(t)
              }
          });
      }
    
      return (...params) => new Promise((resolve, reject) => {
           pendingList.push([
               promiseFn,
               resolve, reject,
               ...params,
           ]);
           if(currentRunFnNum < limit) {
               currentRunFnNum +=1;
               run()
           }
          
      });
    
    }
    
  3. 多次请求结果按照顺序返回

    思路: 考这个就有点变态了其实,至今没遇到。这个是我在实际工作中写的代码 直接粘过来了 思路的话就是每次请求时记录一个自增的请求ID 以及当前的返回状态 默认为false 请求结束后,向前遍历是否有没有请求回结果的函数。如果有,那么说明你要等待,将你的状态改为请求结束,同时保存响应结果以及resolve;如果你的id小于 状态记录长度,说明你后面有请求了,向后访问一个,执行其回调

    interface asyncOpHistoryItem {
        fetchId: number;
        isResolve: boolean;
        result?: any;
        next?: (res: any) => void;
    }
    
    type PromiseFunction = (...props: any[]) => Promise<unknown>;
    
    function asyncOrderWrapper<T extends PromiseFunction>(fetch: T): T {
        const asyncOpHistory: asyncOpHistoryItem[] = [];
        const result = (...props: any[]) => {
            const fetchId = asyncOpHistory.length + 1;
            asyncOpHistory.push({
                fetchId,
                isResolve: false,
            });
            const resultUtil = (res: any, resolve: any) => {
                // 请求结束判断数组前是否有没有resolve的Promise
                for (let i = 0; i < fetchId - 1; i += 1) {
                    if (asyncOpHistory[i].isResolve === false) {
                        // 说明有那么带着返回结果等待执行
                        asyncOpHistory[fetchId - 1] = {
                            fetchId,
                            isResolve: true,
                            result: res,
                            next: resolve,
                        };
                        return;
                    }
                }
    
                // 没有 那么就直接resolve
                asyncOpHistory[fetchId - 1] = {
                    fetchId,
                    isResolve: true,
                };
                resolve(res);
                // 如果当前id 小于数组长度 说明后面有请求请求完了等你呢。
                let loopIndex = fetchId;
                let needLoop = true;
                while (loopIndex < asyncOpHistory.length && needLoop) {
                    loopIndex += 1;
                    const tempObj = asyncOpHistory[loopIndex - 1];
                    if (tempObj.isResolve && tempObj.next) {
                        tempObj.next(tempObj.result);
                        asyncOpHistory[loopIndex - 1] = {
                            fetchId: loopIndex,
                            isResolve: true,
                        };
                    } else {
                        needLoop = false;
                    }
                }
            };
            // console.log(asyncOpHistory)
            return new Promise((resolve, reject) => {
                fetch(...props).then((res: any) => {
                    resultUtil(res, resolve);
                }).catch((res: any) => {
                    resultUtil(res, reject);
                });
            });
        };
        return result as T;
    }
  4. Promise.all

    
    Promise.myAll = (PromiseFnList: (...params: any)=>Promise) => {
      let returnData = [];
      return new Promise((resolve, reject)=>{
        PromiseList.map((i, index) => {
      
          Pomise.resolve(i).then((res)=>{
            returnData[index] = res;
    
            // 每次请求结束后校验是否所有结果都返回了
            let canResolve = true;
            for(i=0;i<PromiseList.length;i+=1) {
                if(!returnData[i]) {
                  canResolve = false
                }
            }
            if(canResolve) resolve(returnData);
          }).catch(reject)
        })
      })
    }
    

    all 的话还有个类似于2的变种,限制同时并发请求数,比2简单

    思路通

    function asyncPool(promiseFnList, limit) {
    
      return new Promise((resolve, reject) =>{ 
            let returnValue = [];
            let currentRunIndex = -1;
            function run() {
                currentRunIndex+=1
                promiseFnList[currentRunIndex]().then(res=>{
                    returnValue[currentRunIndex] = res;
                    if(returnValue.length === promiseFnList && !returnValue.find(n=>!!n)){
                        // 说明所有的请求运行完毕 结果都在请求中
                        resolve(returnValue)
                    }
                    if(currentRunIndex < promiseFnList.length) {
                        // 此时说明有一个函数执行结束,但是仍有请求没执行完
                        run()
                    }
                }).catch(reject)
            }
            promiseFnList.slice(0, limit).map(i=>{
                run()
            })
      });
    
    }
  5. Promise.race

    Promise.myRace = (PromiseFnList: (...params: any)=>Promise) => {
      return new Promise((resolve, reject)=>{
        // done 用来销毁二次返回
        let done = false;
        PromiseFnList.forEach(item => {
            //如果不是MyPromise对象,需要转换
            Promise.resolve(item).then(res => {
                if (!done) {
                    resolve(res);
                    done = true;
                };
            }, err => {
                if (!done) {
                    reject(err);
                    done = true;
                };
            });
        })
      })
    }
    
  6. Promise 实现一个sleep函数

    let sleep = (time) => {
        return new Promise((res)=>{
            setTimeout(()=>{
                console.log('执行成功', tiem);
                res();
            }, time)
        })
    };
Previous10-节流防抖Next2-js函数值传递

Last updated 11 months ago

Was this helpful?