Apollo-Client 文件上传

使用apollo-client上传文件 apollo 文件上传 依赖 apollo-client apollo-link apollo-upload-client apollo-cache-inmemory 客户端创建 apolloClient.js import { ApolloClient } from 'apollo-client' import { createUploadLink } from 'apollo-upload-client' import { ApolloLink, from } from 'apollo-link' import { InMemoryCache } from 'apollo-cache-inmemory' const authLink = new ApolloLink((operation: Operation, forward) => { operation.setContext({ headers: { Authorization: getToken(), }, }) return forward(operation) }) const uploadLink = createUploadLink({ uri: `${API_URL}`, }) export const apolloClient = new ApolloClient({ link: from([authLink, uploadLink]), // uploadLink一定要放最后 cache: new InMemoryCache(), }) 使用 uploadFile....

September 19, 2019 · 1 min · 117 words · Johnson

闭包与防抖函数

最近在开发过程中频繁用到防抖函数(提交表单、页面滚动等),比较 low 的解决方案一般都是定义一个全局变量作为控制函数执行的锁,这样的确能解决问题,但是一点都不优雅。于是仔细琢磨了一下防抖函数,其中涉及到了闭包,顺便复习一下。 什么是闭包 简单的讲闭包就是在函数里面定义的函数。在开发过程中我们经常会写。 function a() { let i = 0 console.log(i) function b() { i++ console.log(i) } return b } let fb = a() fb() // 0 // 1 上面代码中,函数 b 就是一个闭包。根据执行结果我们可以验证闭包的一个特性,即闭包中引用了父级作用域中的变量,当父级函数执行完毕之后,被引用的内部变量不会被回收。很容易理解,将上面的执行过程拆开来看: let fb = a() // a函数中声明变量i = 0,并且将i的值打印出来 // a函数中声明b函数,在b函数中将i的值增加1 // 将b函数返回,a函数执行完毕 fb() // i的值增加1,并将其打印出来 神奇的地方就在与,我们通过将 b 函数返回,实现了在 a 函数执行完毕后对其内部的局部变量进行访问和修改。因此闭包也被看作是连接一个函数内部和外部的桥梁。 防抖函数 从另一个角度思考闭包,可以看作父级函数为闭包创建了一个临时的作用域,其中的变量可以和外部隔绝。这样的话我们就可以把一些在特定位置才会使用的全局变量通过闭包的方式使用,使代码更加优雅。 以防抖函数为例,前面提到的解决方案是定义一个全局变量来控制函数的执行: let lock = false function submit() { if (!lock) { lock = true setTimeout(() => { console....

September 18, 2019 · 2 min · 253 words · Johnson

优雅的解决axios超时

在vue中经常使用axios发起网络请求,与服务器进行数据交互。在使用过程中会有许多问题存在,比如由于网络不稳定导致请求超时/失败,通常有两种解决方案,一种是提示用户重新提交请求,另一种是进行相关提示并自动重新发送请求。第二种方式用户体验明显高于第一种方式。本文就针对第二种方式设计一个解决方案。 DEMO(https://yes-lee.github.io/axios-tutorial/) 拦截器 基本所有的网络请求库都有拦截器接口,包括请求拦截器和响应拦截器。axios设置拦截器的接口为axios.interceptor.request.use(cb, errCb)和axios.intercepter.response.use(cb, errCb),拦截器可以设置多个,按照设置的顺序执行。 请求失败 请求失败无论是网络异常还是其他原因,都会走到响应拦截器里,因此对于请求结果的相关处理,重点放在响应拦截器上,而请求异常的处理则放在响应拦截器的第二个回调函数里面。 解决方案 思路很简单,在响应拦截器中拦截到异常信息,通过分析异常信息来直接从拦截器中重新发送请求。整个过程对于调用请求的业务代码中来说是毫无感知的,只需等待resolve结果即可。 实现 首先,经过测试得到请求超时的错误代码是ECONNABORTED,网络连接异常没有错误代码,可以直接通过error.message === 'Network Error'进行判断。 const httpClient = Axios.create(defaultConfig) httpClient.interceptors.response.use(null, err => { // 异常处理 const { config, code, message } = err if (code === 'ECONNABORTED' || message === 'Network Error') { // 请求超时 console.warn(`请求超时,将在${defaultConfig.retryDelay / 1000}秒后重试`) return new Promise(resolve => { setTimeout(async _ => { resolve(await httpClient.request(config)) }, defaultConfig.retryDelay) // 设置发送间隔 }) } // 可以进行相关提示等处理 return Promise.reject(err) }) 经过错误代码判断,需要进行重新发送的时候,将请求的 config 直接传入httpClient....

September 18, 2019 · 1 min · 76 words · Johnson

一篇文章彻底解决图片 404 问题

在前端工程打包部署过程中,经常会有同学遇到图片等静态资源 404 的问题,这些问题都是于打包后资源路径不正确导致的。本文就从基础开始,讲解如何分析并解决此类问题。 绝对路径于相对路径 首先先搞清楚绝对路径和相对路径的区别。绝对定位就是从根目录开始,二相对路径是以当前路径为参考,从标记上来看,绝对路径是以/开头的路径,而相对路径是以./或者文件(文件夹)名称开头的路径。 web 中的路径 前面简单的讲了绝对路径和相对路径的定义和区别,下面,开始重点讲在 web 中的资源路径。 在浏览器中访问 web 有两种方式,一种是直接在浏览器中打开.html文件,另一种是通过一个 IP 或域名访问部署在静态资源服务器(web 服务器)中的网页。分别来分析两种情况。 直接打开.html文件 在文件系统中,绝对路径以根目录或盘符开始,比如:/Users/Johnson/Document(Linux/Unix)和C:\Users\Johnson\Document(windows)。如果我们直接从浏览器加载index.html页面,那么浏览器中的地址是该文件在系统中的绝对路径。 在 unix 或类 unix(如 macOS)系统中,以file://开头,在 windows 中以盘符开头。我们先看一下这个图片的路径 可以看到,写的是相对路径,浏览器从文件系统中也通过相对路径加载图片。然后,换成绝对路径试试。 图片也能正常加载,但是我们平时在web开发过程中通过绝对路径应用资源并没有写文件在磁盘中的真实路径,而是像这样写 然后再打开,会发现图片无法显示了,从调试工具中可以看到,浏览器直接从系统根目录查找文件 因此,如果我们的 web 应用需要打包成桌面应用/移动 app,那么一般情况只能使用以./开头的相对路径,除非打包的应用中集成了静态资源服务。 从 web 服务器访问 Web 服务器会给每一个 web 应用的目录分配一个域,我们可以直接通过 IP 地址或者域名来访问。当在浏览器中访问该 web 应用时,会将绝对路径的根目录代理到项目所在目录。看一个 vue 实例:将项目打包后,使用http-server为 dist 目录开启一个代理 同样适用绝对路径,通过网络调试器看到资源从http://localhost:8081/images/logo.png请求来的,服务器将http://localhost:8081/部分映射到了/Users/liyongsheng/Documents/path-problem/dist路径下,这样就能正确获取到绝对路径标记的资源。同样的,我们也可以使用以./开头的相对路径。 webpack 打包静态资源路径 在webpack打包过程中,使用相应的插件可以将静态资源打包到模块化的代码中。这里重点讲在标签中的src资源。以vue项目为例,如果src写的是以/开头的绝对路径,则不做任何处理,如果是以.,~,@开头,则会被webpack当作模块打包,具体参考vue-cli官方文档。 因此,如果不希望静态资源被打包到模块化代码中,我们可以使用绝对路径来引入资源,如下图所示: 也可以使用相对路径,但是使用相对路径会被webpack打包,编译的时候就会报错 要避免这个问题,可以使用数据绑定 publicPath pablicPath是 webpack 的一个配置项,用于指定资源根目录,默认为/。大多数图片 404 问题都是因为网站部署到二级目录下,比如域名为www.a.com,那么如果网站部署到www.a.com/b/下面,就会导致图片 404 问题,调试可以发现浏览器是从www.a.com下面请求资源,但是实际上应该是www.a.com/b/下面亲求,一般只用修改publicPath为/b/就可以解决,这样浏览器会从www.a.com/b/下面去请求资源。 打包 app 的情况 将 web 项目打包为 app 的时候,一般都是通过 webview 直接从文件系统中加载页面,这里由于没有 web 服务器,绝对路径就会被解析到系统根目录下。因此publicPath需要设置为相对路径publicPath: ''或publicPath: '....

September 18, 2019 · 1 min · 84 words · Johnson

设计模式六大原则

软件开发过程中常用的六大设计原则 单一职责原则(Single Responsibility Principle) 定义 不要存在多余一个导致类变更的原因 解释 一个类只负责一项职责 作用 根据业务功能分离代码模块 分析 单一职责原则非常简单,稍微拥有编程经验的人都会去遵守单一职责原则,即使不知道该原则的存在。但是在实践过程中,单一职责原则会面临最大的敌人——职责扩散 所谓职责扩散,指的是由于某些原因,职责 P 被划分为粒度更细的职责 P1, P2, …等,这种情况,我们需要根据实际情况来决定遵循单一职责原则的粒度。 如果一个职责的扩散不可控,那么必须在职责扩散失控前,重构代码 里氏替换原则(Liskov Substitution Principle) 定义 如果对每一个类型为 T1 的对象 o1,都有类型为 T2 的对象 o2,使得以 T1 定义的所有程序 P 在所有的对象 o1 都代换成 o2 时,程序 P 的行为没有发生变化,那么类型 T2 是类型 T1 的子类型 所有引用基类的地方必须能透明地使用其子类的对象 解释 子类要能够完成父类所有的职责,在这样的一个系统中,基类(祖先类)的对象,被其子类对象替换后,整个系统工作不会受到影响。 ::子类可以扩展父类,但是不能修改(重写)父类的方法:: 作用 提高系统稳定性、可扩展性 分析 在面向对象编程过程中,里氏替换原则要求我们,在子类里面不要重写/修改父类中已经实现的方法(抽象方法除外) 子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法。 子类中可以增加自己特有的方法。 当子类的方法重载父类的方法时,方法的前置条件(即方法的形参)要比父类方法的输入参数更宽松。 当子类的方法实现父类的抽象方法时,方法的后置条件(即方法的返回值)要比父类更严格。 接口隔离原则(Interface Segregation Principle) 定义 客户端不应该依赖它不需要的接口;一个类对另一个类的依赖应该建立在最小的接口上 解释 类 A 所依赖的接口,应该只包含类 A 用到的方法 作用 避免无用代码,防止类过于臃肿 分析 接口隔离原则,在于控制接口的粒度,如果一个接口中包含过多的方法,那么在实现类中就需要实现所有方法,就会导致代码非常臃肿。这个时候就需要将接口拆分为粒度更细的多个接口。...

September 18, 2019 · 1 min · 116 words · Johnson