奇怪的知识又又又增加了 大多數知識,文檔都能學到。遇到困惑,先看文檔。 文档怎么看? 有好多的是过时的,即使是官网的。 就像 rollup + ts + babel npm上找到对应的插件,然后看插件文档,babel的话直接去官网看

内存泄露

内存回收机制有 标记清楚,引用计数(由于存在循环引用等,现在不用这个方法了
项目崩溃,发现项目里内存泄露了 —

  • settimeout,setInterval (蚊子腿 记得清除
  • 闭包 (目前来说ES6语法很少涉及到
  • 脱离DOM的引用(vue等类似框架,很少直接操作dom
  • 全局变量!
  • createObjectURL生成的地址->资源的映射 也会造成内存泄漏(及时用 revokeObjectURL清除
  • createElement,cleateDocumentFragment,创建元素之后,未将变量置空

造成的原因就是全局变量,有个数组在被一直推入变量,永远不会调用清除方法

css

用rem布局,圆形或者圆环会变形

  1. // 思路 先用两倍的宽高属性设置css样式,然后按照0.5倍缩放
  2. div {
  3. width: .4rem;
  4. height: .4rem;
  5. background-color: #C40000;
  6. border-radius: 50%;
  7. transform: scale(0.5);
  8. }

flex布局的时候文本溢出无效

  1. // 对flex的元素增加最小宽度
  2. .flex {
  3. min-width: 0;
  4. }

JS

promise

全局变量覆盖

  1. test = function () {
  2. let c = Math.random() * 10
  3. let promise = new Promise ((resolve, reject) => {
  4. window.doSomething = function (data) {
  5. setTimeout(() => {
  6. console.log('before resolve', data)
  7. resolve(data)
  8. }, c * 1000)
  9. }
  10. })
  11. return promise
  12. }
  13. // 情况1
  14. test().then(res => {
  15. console.log(res)
  16. })
  17. test().then(res => {
  18. console.log(res)
  19. })
  20. window.doSomething('12313')
  21. window.doSomething('hhhhh')
  22. // before resolve 12313
  23. // 12313
  24. // before resolve hhhhh
  25. // 情况2
  26. test().then(res => {
  27. console.log(res)
  28. })
  29. window.doSomething('12313')
  30. test().then(res => {
  31. console.log(res)
  32. })
  33. window.doSomething('hhhhh')
  34. // before resolve 12313
  35. // 12313
  36. // before resolve hhhhh
  37. // hhhhh

第二次调用 test 的时候, window.doSomething 被重写了,导致里面的 resolve 丢失,然后后面调用两次的时候,执行的都是后面一次赋值的方法。 这个时候使用下面的方法,就可以进行控制,以免window上的变量被覆盖。

Promise 执行列队,按照推入循序执行

  1. class PromiseQueue {
  2. constructor () {
  3. this._queue = []
  4. // 当前队列有无promise在执行的标记
  5. this._flag = false
  6. }
  7. add (fn) {
  8. this._queue.push(fn)
  9. if (!this._flag) this.exce()
  10. }
  11. async exce () {
  12. this._flag = true
  13. while (this._queue.length > 0) {
  14. let tmp = this._queue.shift()
  15. try {
  16. await tmp()
  17. } catch (e) {
  18. console.log('err:', e)
  19. }
  20. }
  21. this._flag = false
  22. }
  23. }
  24. // usage
  25. const q = new PromiseQueue()
  26. let callSdk = (params) => new Promise((rs, rj) => {
  27. let tmp = () => new Promise((resolve, reject) => {
  28. setTimeout((res) => {
  29. resolve()
  30. rs(params)
  31. }, Math.random() * 5000)
  32. })
  33. q.add(tmp)
  34. })
  35. callSdk(1).then(res => {
  36. console.log('res::', res)
  37. })
  38. callSdk(2).then(res => {
  39. console.log('res::', res)
  40. })
  41. callSdk(3).then(res => {
  42. console.log('res::', res)
  43. })
  44. 可以用promise.race()判断是否有promise完成,不需要再嵌套一层promise

一个对象转换方法

  1. var obj1 = {
  2. "user.name.firstname": "foo",
  3. "user.age": 10
  4. }
  5. obj = {}
  6. Object.entries(obj1).forEach((item) => {
  7. let tempArr = item[0].split('.')
  8. tempArr.reduce((acc, cur, index) => {
  9. if(index === tempArr.length - 1) return acc[cur] = item[1]
  10. return acc[cur] = acc[cur] ? acc[cur] : {}
  11. }, obj)
  12. })
  13. console.log(obj)
  14. // 结果
  15. {
  16. user: {
  17. name: {
  18. firstname: 'foo'
  19. },
  20. age: 10
  21. }
  22. }

BigInt

**BigInt** 是一种内置对象,它提供了一种方法来表示大于 253 - 1 的整数。这原本是 Javascript中可以用 [Number](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Number) 表示的最大数字。**BigInt** 可以表示任意大的整数 — mdn

遇到一个接口,返回值为

  1. // 后端实际返回(在postman 和 浏览器直接输入地址
  2. let res = {
  3. key: 1212124121545233223
  4. }
  5. // 前端接收到的 (包括在控制台network看到的
  6. {
  7. key: 1212124121545233200
  8. }
  9. // 开始以为接口出错了,后面在控制台测试发现
  10. let c = 1212124121545233223
  11. c
  12. // 1212124121545233200
  13. // 原来是 bigint,js对大于2^53的整数显示和处理有限制
  14. // 然后就在请求中加入
  15. const JSONbig = require('json-bigint')
  16. axios({
  17. url: '***',
  18. transformResponse: function (data) { return JSONbig.parse(data) },
  19. params
  20. })
  21. // 使用的时候直接
  22. res.key.toString()

浏览器相关

忽略证书报错,加载service worker

  1. // 生成证书,文件夹目录里运行,注意:common name 要设置为 localhost
  2. openssl req -newkey rsa:2048 -new -nodes -x509 -days 3650 -keyout key.pem -out cert.pem
  3. // http-server 启动https 本地服务
  4. http-server -S -C cert.pem
  5. // 进入chrome 应用的文件夹,空格要用反斜杠转译
  6. cd /Applications/Google\ Chrome.app/Contents/MacOS
  7. // 启动忽略证书模式
  8. ./Google\ Chrome --user-data-dir=/Users/buer/play/pwa --ignore-certificate-errors --unsafely-treat-insecure-origin-as-secure=https://localhost

vue自带 prefetch

vue-cli 路由懒加载,cli默认 prefetch 了其他懒加载路由。

请求相关

Referrer Policy

最新版 chrome 为了保证用户访问安全,出了一个新的功能
当你的 General 中没有设置 Referrer Policy 的时候,系统会默认设置为 strict-origin-when-cross-origin
也就是说,在请求头中,Referer 会只有域名,如下,导致 JsonP 类型的请求,后端不作处理返回 403

  1. Referrer Policy: strict-origin-when-cross-origin
  2. Referer: https://ts.hundsun.com/
  3. 当设置 Referrer Policy no-referrer-when-downgrade 的时候,
  4. Referrer Policy: no-referrer-when-downgrade
  5. 此时,Referrer 字段会显示为全部,如下
  6. Referer: https://ts.hundsun.com/se/portal/SupportPortal.htm

Content-Type(常用的)

form-data 类型的请求体

**application/x-www-form-urlencoded** 此类型不适合传输大型的二进制数据
**multipart/form-data** 此类型用于传输文件

json 类型的请求体

**application/json** 此类型适合后端要求接受 json

使用

  1. data = {
  2. name: 'buer',
  3. age: 25
  4. }
  5. // application/x-www-form-urlencoded
  6. config.data = Qs.stringify(data)
  7. // application/json
  8. config.data = JSON.stringify(data)
  9. // multipart/form-data
  10. config.data = data

封装axios

token一般会有一个过期时间,然后后端也会给一个过期时间,但是判断是否过期用的是系统时间,如果系统时间被修改,则造成token实际过期,依然发送请求,造成请求失败 不过刷新token这种最好方案还是后端解决!!!

思路

在axios 响应中判断是否无权限

  • 无权限 - 请求token 再重新发送请求
  • 有权限 - 正常进行

若同时有多个请求则用一个数组保存请求,等待获取到token后,再一并发送

响应拦截器修改

  1. let isRefreshing = false // 是否在刷新的flag
  2. let requests = [] // 保存请求数组
  3. instance.interceptors.response.use(response => {
  4. return response
  5. }, error => {
  6. if (!error.response) return Promise.reject(error)
  7. // 判断是否是无权限需要刷新token
  8. if (error.response.status === 401) {
  9. const { config } = error
  10. // 如果这是第一个请求 isRefreshing 为false
  11. if (!isRefreshing) {
  12. isRefreshing = true
  13. return getToken().then(res => {
  14. const { token } = res.data
  15. // 存入缓存
  16. setToken(token)
  17. config.headers.Authorization = `Bearer ${access_token}`
  18. // 执行数组里所有保存起来的请求
  19. requests.forEach((cb) => cb(token))
  20. requests = []
  21. // 第一个请求通过这个地方返回
  22. return instance(config)
  23. })
  24. } else {
  25. // 未获取到token的时候
  26. return new Promise(resolve => {
  27. // 除第一个之外的请求保存在数组中
  28. request.push(token => {
  29. config.headers.Authorization = `Bearer ${access_token}`
  30. resolve(instance(config))
  31. })
  32. })
  33. }
  34. }
  35. return Promise.reject()
  36. })

git相关

HTTP2报错

  1. Fix error : RPC failed; curl 92 HTTP/2 stream 0 was not closed cleanly: PROTOCOL_ERROR

解决方案

设置git使用 http/1.1

  1. git config --global http.version HTTP/1.1

工具

VS Code

格式化两次问题

一般vscode中的格式化顺序为 prettier > default > eslint
意味着 通常情况下 prettier 最后执行完毕。代码样式就由prettier决定了(所以其他程序格式化好后,再prettier格式化可能会闪烁)。同样的,如果同时开启 defalut和 eslint ,eslint格式化之后,也会闪烁一下,保存为最终的vscode默认格式化代码样式。

  1. // 保存时使用VSCode 自身格式化程序格式化
  2. "editor.formatOnSave": true,
  3. // 保存时用eslint格式化
  4. "editor.codeActionsOnSave": {
  5. "source.fixAll.eslint": true
  6. // 解决:
  7. // 1. 两者会在格式化js时冲突,所以需要关闭默认js格式化程序,即添加下面的
  8. "javascript.format.enable": false
  9. // 2. 或者是关闭掉vscode默认的格式化工具
  10. "editor.formatOnSave": false

npm包发布相关

npm login

  1. Conflict - PUT https://registry.npm.taobao.org/-/user/org.couchdb.user:buera - [conflict] User buera already exists

设置正确的镜像源即可

  1. npm config set registry https://registry.npmjs.org/

包依赖类型

dependencies

项目运行需要的包

devDependencies

开发环境或者测试中使用的包

peerDenpendencies

如果有一些依赖包即使安装失败,项目仍然能够运行或者希望npm继续运行,就可以使用optionalDependencies。另外optionalDependencies会覆盖dependencies中的同名依赖包,所以不要在两个地方都写。

bundledDependencies

在发布的时候,希望一些依赖也出现在最终包里的话,可以将包名写在里面

  1. {
  2. "name": "@buera/native-bridge-securities",
  3. "bundledDependencies": [
  4. "@buera/native-bridge-core"
  5. ]
  6. }

这样在安装 @buera/native-bridge-securities 这个包的时候,发现 @buera/native-bridge-core 这个包也会一起被安装

package.json 字段

module

pkg.main字段指向的应该是编译后生成的 ES5 版本的代码,而 module 字段会指向一个基于ES6模块规范的文件 这样在使用包的时候可以享受 TreeShaking 带来的好处,而ES5的好处是用户在大包的时候可以放心屏蔽掉 node_modules 目录
使用的时候,如果我们使用

  1. // 使用 esmodule 模块,默认引用 module 字段指向的文件
  2. import { cc } from '@buera/native-bridge-securities'
  3. // 使用 AMD规范,RequireJS,默认饮用 main 字段指向的文件
  4. let cc = require('@buera/native-bridge-securities')