经常遇到的问题

一个前端经常会遇到的问题
  • 例如,我想要在一个项目里,监听所有的fetch请求,应该怎么办?又或者说,我想用别人封装好的方法,但是在它之前,需要经过一层处理、判断,然后再看情况是否调用别人封装好的方法

  • 这种需求,大都是相似的,记得我之前讲解过koa洋葱圈、redux中间件等源码是我们前端的一种核心解决问题的思维方式

从如何监听fetch请求说起
  • 例如,fetch的使用,一般是:

    fetch(url).then((res)=>{...})

  • 那么对于一个已经使用过很多次的项目,我需要监听这个fetch请求。应该怎么办呢?很简单,我们"重写"fetch

    const myFetch = window.fetch;
    window.fetch = function (...arg) {
    console.log("此时调用了fetch,参数是:", arg);
    return myFetch(arguments);
    };
    fetch("www.baidu.com").then((res) => {
    console.log(res, "res");
    });

  • 简单的几行代码,就实现了监听所有的fetch请求。而且不会对原有的功能有入侵,不过问题来了

  • 这样做,其实相当于去修改原型链上的方法,导致纯净的原有方法被污染。真正操作时候,建议新写一个方法,然后全局替换即可,这样能保证底层的fetch方法是正常的,不会影响那些不需要log的地方,那么我们今天顺便讲讲类似的源码实现
到redux最精髓的中间件源码compose函数
  • 比如说我们有这样几个函数:

    function add1(str) {
    return str + 1
    }

    function add2(str) {
    return str + 2
    }

    function add3(str) {
    return str + 3
    }

  • 我们想依次执行函数,并把执行结果传到下一层就要像下面一样一层套一层的去写:

    let newstr = add3(add2(add1("abc"))) //"abc123"]

  • 这只是3个,如果数量多了或者数量不固定处理起来就很麻烦,但是我们用compose写起来就很优雅:

    let newaddfun = compose(add3, add2, add1);
    let newstr = newaddfun("abc") //"abc123"

那compose内部是如何实现的呢?
复制代码
function compose(...funcs) {
    return funcs.reduce((a, b) => (...args) => a(b(...args)));
}
  • 其实核心代码就一句,这句代码使用了reduce方法巧妙地将一系列函数转为了add3(add2(add1(...args)))这种形式,我们使用上面的例子一步一步地拆分看一下

  • 当调用compose(add3, add2, add1)funcs是add3, add2, add1,第一次进入时a是add3b是add2,展开就是这样子:(add3, add2)=>(...args)=>add3(add2(...args)),传入了add3, add2,返回一个这样的函数(...args)=>add3(add2(...args)),然后reduce继续进行,第二次进入时a是上一步返回的函数(...args)=>add3(add2(...args))b是add1,于是执行到a(b(...args)))时,b(...args)作为a函数的参数传入,变成了这种形式:(...args)=>add3(add2(add1(...args))),是不是很巧妙。

如果你这里理解不了,你今天不睡觉也要搞明白,拿纸去写下来实现调用过程,这就是前端里面最硬的干货了。

再到promise链式调用实现
  • Promise链式调用跟JQ的区别在于,promise.then每次返回的都是一个新的promise实例对象,这样实现了链式调用。

  • JQ链式,相当于一个函数内部永远都返回当前这个相同的this

    //这里我也忘了是不是这样用了
    $('#root').style(...).style(...)

  • Promise链式,最后打印结果是Peter老师666,每次.then返回的是一个新的Promise

    Promise.resolve("Peter老师666")
    .then((res) => {
    return res;
    })
    .then((res) => {
    console.log(res,'res')
    return res;
    });

再到express的next
  • 当我们在路由处理中调用next()时候,就会进入下一个匹配,例如当我们用get请求接口test时候,就会走到console.log("此时被触发")这行代码

    app.get('/test',(req,res,next)=>{
    next()

    })
    app.get('*',(req,res,next)=>{
    console.log("此时被触发")
    })

  • 原因是什么?实现express的next很简单

    复制代码
    handle(req, res, matchedList) {
      const next = () => {
        const midlleware = matchedList.shift();
        if (midlleware) {
          midlleware(req, res, next);
        }
      };
      next();
    }
  • 我们先找到所有匹配的请求方式和路由,然后首先处理第一个匹配中的路由,使用闭包方式传入next方法。当调用next方法时候,会执行下一个匹配中的路由回调函数。这样就实现了next

再到koa的中间件
  • 怎么使用koa的中间件?

    app.use(middlewaer1).use(middlewaer2).use(middlewaer3)

  • 是不是感觉跟JQ的链式调用很像,其实一样,都是统一返回this即可。如下所示:

    const obj = {
    print(arg) {
    console.log(arg);
    return this;
    },
    hello(arg) {
    console.log(arg);
    return this;
    },
    world(arg) {
    console.log(arg);
    return this;
    },
    };
    obj.print('Peter').print('hello').print('world');

  • 此时控制台就输出了Peter,hello,world。我们实现了最简单的链式调用

相关推荐
小二·3 小时前
Python Web 开发进阶实战 :AI 原生数字孪生 —— 在 Flask + Three.js 中构建物理世界实时仿真与优化平台
前端·人工智能·python
Amumu121384 小时前
Vue组件化编程
前端·javascript·vue.js
We་ct4 小时前
LeetCode 6. Z 字形变换:两种解法深度解析与优化
前端·算法·leetcode·typescript
小二·5 小时前
Python Web 开发进阶实战(终章):从单体应用到 AI 原生生态 —— 45 篇技术演进全景与未来开发者生存指南
前端·人工智能·python
m0_637256585 小时前
vue-baidu-map添加了类型组件导致非常卡顿的问题
前端·javascript·vue.js
挂机且五杀5 小时前
为什么在React地图组件里,memo 不是优化,而是生存?
前端·react.js·前端框架
RFCEO5 小时前
HTML编程 课程七、:HTML5 新增表单标签与属性
前端·html·html5·搜索框·手机号·邮箱验证·日期选择
刘一说6 小时前
Vue开发中的“v-model陷阱”:为什么它不能用于非表单元素?
前端·javascript·vue.js
利刃大大6 小时前
【Vue】组件生命周期 && 组件生命周期钩子
前端·javascript·vue.js·前端框架
建群新人小猿8 小时前
陀螺匠企业助手—个人简历
android·大数据·开发语言·前端·数据库