Git Product home page Git Product logo

notes's Issues

DevTools

通过coverage查看未使用的css

  1. ctrl + shift + p(win), cmd + shift + p(mac)打开命令行;
  2. 输入coverage选择Show Coverage打开标签;
  3. 点击标签重载查看资源使用情况。

互联网垄断的产生

基本概念:

  1. 网络外部性:一个网络里面,网络节点越多,这个网络的价值也就越大;
    贝尔实验室,推广电话,一个用户的价值(用户之间联系的可能性)是0,两个用户价值是2,三个用户价值是6,推导出网络的价值=n*(n-1)
  2. 梅特卡夫公式(Metcalfe law):网络的成本与网络价值的关系:
    硬件成本与用户成本在某段期间内是线性的,而网络价值是指数的,中科院模拟Tencent/Facebook的月活x(十亿)与营收y(十亿美元)的关系函数;

行业分析

  1. 直接外部性:价值直接取决于一个群体的价值V∝n^2,比如即时通信工具;
  2. 间接外部性:价值取决于多个群体的价值V∝m*n,比如生产者与消费者共存的领域,淘宝,美团,滴滴,信用卡,同样传统行业的产业聚集,商家与其它店铺的竞争问题的前提下首先是给大的环境创造更大的价值,以超越其他的环境,用户会选择商家更多的环境,同样反向吸引更多的商家;
  3. 互联网平台:互联网平台为什么会让商家二选一,基于间接外部性,在用户量大于商家量的情况下,增加商家的量是更能快提升平台价值的,同时在用户量很大的情况下,商家流失导致的价值损失也更大,在竞争的情况下,虹吸效应可能会导致平台价值极速的压缩;

举例非绝对

virtual DOM

虚拟DOM到真实DOM

概念

真实DOM

首先,什么是真实DOM,就是HTML文件中真实的元素,有样式,属性,方法

html:

<div id="app"></div>
var dom = document.getElementById('app');
dom.innerHTML  // ""

虚拟DOM

虚拟DOM就是能用抽象后对象来描述真实DOM, 在实际操作下,描述真实DOM只是虚拟DOM需要满足的一个最主要的需求

下面就是满足上面html的虚拟DOM

var vApp = {
    tagName: "div",
    attrs: {
        id: "app"
    },
    childrens: []
}

Vue的虚拟节点接口定义

export interface VNode {
  tag?: string;
  data?: VNodeData;
  children?: VNode[];
  text?: string;
  elm?: Node;
  ns?: string;
  context?: Vue;
  key?: string | number;
  componentOptions?: VNodeComponentOptions;
  componentInstance?: Vue;
  parent?: VNode;
  raw?: boolean;
  isStatic?: boolean;
  isRootInsert: boolean;
  isComment: boolean;
}

虚拟DOM的好处:

  1. 抽象:渲染过程抽象化后,增加代码可维护性;
  2. 跨平台:不同平台最终的渲染有不同的实现,比如服务端渲染,小程序,基于虚拟DOM兼容多个平台的渲染就容易多了。

注意:vDOM性能不一定高,参考:尤雨溪关于虚拟DOM性能的回答

下面内容都是基于Web的处理

转换过程

创建虚拟DOM的方法,这里有前置条件,我们写的vue和小程序,都是需要通过解析成AST(抽象语法树)、AST转换、生成可执行代码,才能生成我们需要的虚拟DOM,有机会再展开;

render

生成真实DOM,真实DOM节点有8种,我们只实现其中的元素节点和文字节点。

// render.js
function createElement(vNode) {
	const $el = document.createElement(vNode.tagName);
	
	// 处理属性
	for (const [k, v] of Object.entries(vNode.attrs)) {
		$el.setAttribute(k, v);
	}
	
	// 处理子元素
	for (const child of vNode.childrens) {
		$el.appendChild(render(child));
	}
	
	return $el;
}

const render = (vNode) => {
	// 生成文字节点
	if (typeof vNode === "string") {
		return document.createText(vNode);
	}
	
	// 生成元素节点
	return createElement(vNode);
};

export default render;

mount

挂载生成的DOM

export default ($node, $target) => {
	$target.replaceWith($node);
	return $node;
};

mount之后更新

$rootEl = mount(render(createVApp(count)), $rootEl);

如何只更新修改的节点,就需要diff来判断修改的节点了

diff

我们先讨论节点更新简单的三种情况

  1. 新的节点树是undefined, 那么直接销毁就行了
  2. 新旧节点有节点是文本类型,比较替换
  3. 新旧节点tagName不一致,直接替换
  if (newVTree === undefined) {
    return $node => {
      $node.remove();
      return undefined
    }
  }

  if (typeof newVTree === "string" || typeof oldVTree === "string") {
    if (newVTree !== oldVTree) {
      return $node => {
        const $newNode = render(newVTree)
        $node.replaceWith($newNode);
        return $node
      }
    } else {
      return $node => $node
    }
  }
  
  if (newVTree.tagName !== oldVTree.tagName) {
    return $node => {
      const $newNode = render(newVTree)
      $node.replaceWith($newNode);
      return $node
    }
  }

接下来的就是相同tagName的元素,可能属性、子节点的diff

  1. 属性
const diffAttrs = (oldAttrs, newAttrs) => {
  const patches = [];

  for (const [k, v] of Object.entries(newAttrs)) {
    if(!(k in oldAttrs)) {
      patches.push($node => {
        $node.setAttribute(k, v)
        return $node
      })
    }
  }

  for (const k in oldAttrs) {
    if (!(k in newAttrs)) {
      patches.push($node => {
        $node.removeAttribute(k);
        return $node;
      });
    }
  }

  return $node => {
    for (const patch of patches) {
      patch($node);
    }
    return $node;
  };
}
  1. 子节点
    就是对比

Parse URL

分为两个部分,协议与资源地址。
记录并不是完整的过程,甚至可能是不正确的
客户端和服务端只是方便描述数据流的方向

  1. 判断是否在本地HSTS (HTTP Strict Transport Security)中, 由此确定传输协议,也不一定非要在本地列表中才能通过HTTPS协议访问
  2. DNS查询
    1. 是否本地缓存有domin。
    2. gethostbyname 方法查询hosts文件。
    3. DNS server进行ARP process, 找到IP。
  3. 链接
    1. TCP协议:

      • 目标端口与进程端口进入传输层
      • 进入网络层,添加IP
      • 进入链接层,添加MAC地址
    2. TCP链接流

      1. 客户端设置SYN一个初始序列值(ISN),发送给服务端
      2. 服务端同样设置SYN一个初始序列值,并且将客户端的ISN+1设置到ACK,返回给客户端
      3. 客户端增加自己和服务端的序列值,设置ACK.
      4. 数据传输,增加相应的bytes到自己的序列值,当另一段接受到对应的包,会返回ACK值相等的包,这也就是TCP链接不丢包的重连的原因。
      5. 断开: 1.发送FIN包;2.另一段发送ACK, 并发送自己的FIN包;3. 请求端发送ACK结束请求.
    3. TLS(Transfer Layer Security)链接流

      1. 客户端发送ClientHello信息,TLS版本,可选的加密协议与压缩算法列表。
      2. 服务端发送ServerHello信息,TLS版本,选择的加密协议与压缩算法,另外马上发送一个Certificate``ServerKeyExchange信息,其中含有公钥签名证书。
      3. 客户端验证签名证书的可靠性,通过公钥加密随机数据(对称密钥)发送ClientKeyExchange给服务端, 服务端通过私钥解码加密数据得到对称密钥。。
      4. 客户端将公钥和对称密钥通过MD5-SHA生成HASH值发送给服务端,服务端同样生成HASH值进行对比,如果相同则建立连接。

Screenshot 2020-05-04 at 5 02 43 PM

TypeScript

  1. 编译上下文
    通过tsconfig.json定义ts编译选项
{
  "compilerOptions": {

    /* 基本选项 */
    "target": "es5",                       // 指定 ECMAScript 目标版本: 'ES3' (default), 'ES5', 'ES6'/'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'
    "module": "commonjs",                  // 指定使用模块: 'commonjs', 'amd', 'system', 'umd' or 'es2015'
    "lib": [],                             // 指定要包含在编译中的库文件
    "allowJs": true,                       // 允许编译 javascript 文件
    "checkJs": true,                       // 报告 javascript 文件中的错误
    "jsx": "preserve",                     // 指定 jsx 代码的生成: 'preserve', 'react-native', or 'react'
    "declaration": true,                   // 生成相应的 '.d.ts' 文件
    "sourceMap": true,                     // 生成相应的 '.map' 文件
    "outFile": "./",                       // 将输出文件合并为一个文件
    "outDir": "./",                        // 指定输出目录
    "rootDir": "./",                       // 用来控制输出目录结构 --outDir.
    "removeComments": true,                // 删除编译后的所有的注释
    "noEmit": true,                        // 不生成输出文件
    "importHelpers": true,                 // 从 tslib 导入辅助工具函数
    "isolatedModules": true,               // 将每个文件作为单独的模块 (与 'ts.transpileModule' 类似).

    /* 严格的类型检查选项 */
    "strict": true,                        // 启用所有严格类型检查选项
    "noImplicitAny": true,                 // 在表达式和声明上有隐含的 any类型时报错
    "strictNullChecks": true,              // 启用严格的 null 检查
    "noImplicitThis": true,                // 当 this 表达式值为 any 类型的时候,生成一个错误
    "alwaysStrict": true,                  // 以严格模式检查每个模块,并在每个文件里加入 'use strict'

    /* 额外的检查 */
    "noUnusedLocals": true,                // 有未使用的变量时,抛出错误
    "noUnusedParameters": true,            // 有未使用的参数时,抛出错误
    "noImplicitReturns": true,             // 并不是所有函数里的代码都有返回值时,抛出错误
    "noFallthroughCasesInSwitch": true,    // 报告 switch 语句的 fallthrough 错误。(即,不允许 switch 的 case 语句贯穿)

    /* 模块解析选项 */
    "moduleResolution": "node",            // 选择模块解析策略: 'node' (Node.js) or 'classic' (TypeScript pre-1.6)
    "baseUrl": "./",                       // 用于解析非相对模块名称的基目录
    "paths": {},                           // 模块名到基于 baseUrl 的路径映射的列表
    "rootDirs": [],                        // 根文件夹列表,其组合内容表示项目运行时的结构内容
    "typeRoots": [],                       // 包含类型声明的文件列表
    "types": [],                           // 需要包含的类型声明文件名列表
    "allowSyntheticDefaultImports": true,  // 允许从没有设置默认导出的模块中默认导入。

    /* Source Map Options */
    "sourceRoot": "./",                    // 指定调试器应该找到 TypeScript 文件而不是源文件的位置
    "mapRoot": "./",                       // 指定调试器应该找到映射文件而不是生成文件的位置
    "inlineSourceMap": true,               // 生成单个 soucemaps 文件,而不是将 sourcemaps 生成不同的文件
    "inlineSources": true,                 // 将代码与 sourcemaps 生成到一个文件中,要求同时设置了 --inlineSourceMap 或 --sourceMap 属性

    /* 其他选项 */
    "experimentalDecorators": true,        // 启用装饰器
    "emitDecoratorMetadata": true          // 为装饰器提供元数据的支持
  }
}

computed

export function computed<T>(
  getterOrOptions: ComputedGetter<T> | WritableComputedOptions<T>,
  debugOptions?: DebuggerOptions
) {
  let getter: ComputedGetter<T>
  let setter: ComputedSetter<T>
 // 1. 函数初始化
  const onlyGetter = isFunction(getterOrOptions)
  if (onlyGetter) {
    getter = getterOrOptions
    setter = __DEV__
      ? () => {
          console.warn('Write operation failed: computed value is readonly')
        }
      : NOOP
  } else {
    getter = getterOrOptions.get
    setter = getterOrOptions.set
  }
 // 2. computed对象
  const cRef = new ComputedRefImpl(getter, setter, onlyGetter || !setter)

  if (__DEV__ && debugOptions) {
    cRef.effect.onTrack = debugOptions.onTrack
    cRef.effect.onTrigger = debugOptions.onTrigger
  }

  return cRef as any
}
class ComputedRefImpl<T> {
  public dep?: Dep = undefined

  private _value!: T
  private _dirty = true
  public readonly effect: ReactiveEffect<T>

  public readonly __v_isRef = true
  public readonly [ReactiveFlags.IS_READONLY]: boolean

  constructor(
    getter: ComputedGetter<T>,
    private readonly _setter: ComputedSetter<T>,
    isReadonly: boolean
  ) {
    this.effect = new ReactiveEffect(getter, () => {
      if (!this._dirty) {
        this._dirty = true
        triggerRefValue(this)
      }
    })
    this[ReactiveFlags.IS_READONLY] = isReadonly
  }

  get value() {
    // the computed ref may get wrapped by other proxies e.g. readonly() #3376
    const self = toRaw(this)
    trackRefValue(self)
    if (self._dirty) {
      self._dirty = false
      self._value = self.effect.run()!
    }
    return self._value
  }

  set value(newValue: T) {
    this._setter(newValue)
  }
}

computed函数第一个参数可能是函数或者是对象,第一步进行判断对computed进行初始化处理;

传入getter, setter, 和是否只读(只有getter)初始化computed对象;

computed对象重要属性:

_value: 值

dirty: 是否是脏的,判断是否需要再次计算

effect: 响应式回调

再看回构造函数,初始化了effect,如果数据不是脏的,就将dirty修改为true,并 triggerRefValue

    this.effect = new ReactiveEffect(getter, () => {
      if (!this._dirty) {
        this._dirty = true
        triggerRefValue(this)
      }
    })

ReactiveEffect:

export class ReactiveEffect<T = any> {
  active = true
  deps: Dep[] = []

  // can be attached after creation
  computed?: boolean
  allowRecurse?: boolean
  onStop?: () => void

  // ...


  constructor(
    public fn: () => T,
    public scheduler: EffectScheduler | null = null,
    scope?: EffectScope | null
  ) {
    recordEffectScope(this, scope)
  }

  run() {
	// ...
  }

  stop() {
    if (this.active) {
      cleanupEffect(this)
      if (this.onStop) {
        this.onStop()
      }
      this.active = false
    }
  }
}

构造函数传入fn, scheduler, 域

执行函数run

  run() {
    if (!this.active) {
      return this.fn()
    }
    if (!effectStack.includes(this)) {
      try {
        effectStack.push((activeEffect = this))
        enableTracking()

        trackOpBit = 1 << ++effectTrackDepth

        if (effectTrackDepth <= maxMarkerBits) {
          initDepMarkers(this)
        } else {
          cleanupEffect(this)
        }
        return this.fn()
      } finally {
        if (effectTrackDepth <= maxMarkerBits) {
          finalizeDepMarkers(this)
        }

        trackOpBit = 1 << --effectTrackDepth

        resetTracking()
        effectStack.pop()
        const n = effectStack.length
        activeEffect = n > 0 ? effectStack[n - 1] : undefined
      }
    }

get函数:

  get value() {
    // the computed ref may get wrapped by other proxies e.g. readonly() #3376
    const self = toRaw(this)
    trackRefValue(self)
    if (self._dirty) {
      self._dirty = false
      self._value = self.effect.run()!
    }
    return self._value
  }

组件渲染阶段触发get函数, 如果数据是脏的就修改为true, 然后调用effect的执行函数run修改value

Eslint

eslint [options] file.js [file.js] [dir]
--no-eslintrc:不使用.eslintrc.*的配置
-c, --config path::string: 使用指定配置覆盖.eslintrc.*的配置
--cache: 只检测修改的文件
--fix: 自动修改
--fix-dry-run: 自动修改但不保存

Vue 3.0

  1. 项目结构改变,变为monorepo,模块拆分, 依赖更加明确。
  2. vue2静态类型定义从flow换为ts
  3. 性能优化:1. 移除冷门feature,比如filter, inline-template;2.引入 tree-shaking(基于ES6的import, export), 减少打包体积(?之前webpack编译不会处理吗)
  4. 数据劫持:Object.defineproperty如名称所言,处理的是对象的属性,如果需要监听深层对象,还需要需要递归遍历所有属性,Proxy劫持整个对象,虽然也不能深层监听,但是通过getter中递归可以实现使用到才进行监听。
  5. 编译优化: 2.0 diff的最小单位是组件,连非动态节点也会进行diff, 导致vnode性能跟组件大小相关,3.0生成block tree, 更新性能提升为只与动态节点相关。
  6. composition API: 2.0 组件逻辑全混在一起,解决方案一般是用mixins抽离,但是mixin会有命名冲突和来源不明的问题,composition可以将逻辑抽离,并且避免命名重复,类型推断也容易。

小程序Scheme URL

URL scheme查询指南
使用小程序URL scheme一键直达页面
通过小程序[账号原始ID]与在小程序后台工具生成小程序码添加小程序名称->获取更多页面路径->添加开发者微信号->进入小程序右上角功能->复制页面路径可获取到指定小程序当前页面路径地址
URL Schemeweixin://app/wx5aa333606550dfd5/jumpWxa/? + 原始ID userName=gh_3cf62f4f1d52 + 页面地址 path=xxxxx即可在ios下拉起小程序特定页面

智能推荐

目标是全面、精准的用户画像体系?

  1. 这是方法子目标还是主要目标;
  2. 是否是可衡量的
    目标是推荐的用户体验,建用户画像,推荐系统,建模预估;
    如何找到目标:
    层次合理(是否能指导具体工作),可衡量
    靠谱的评估方法:
    经验判断:短视频内容质量评估问题,
    非a/b测试数据:
    a/b测试数据:

Modules

1. 为什么需要模块化

如何管理变量,变量拆分成单独的模块,let有静态作用域,但又让变量无法在另一个function 中引用,一般来说都是在外层声明变量,那此时你就需要注意script的顺序了,不能提前引用

并且脚本之间的相互依赖变得模糊,你不知道哪段脚本使用了哪个变量
第二个就是因为变量暴露,导致代码不稳定性变高

引入模块化后代码的引用依赖变得清晰,能够将代码分解为独立的模块

2. 目前的模块化方案

CJS, AMD, UMD, ESM,语法,目的,模块行为

  • CJS: CommonJS
// import
const doSomething = require("./doSomething.js")

// export
module.exports = function doSomething() {}

node就是使用CJS
引入模块是同步的,引入的是副本
不能在browser执行,需要编译打包, node端

  • AMD: Asynchronous Module Definition 异步模块定义
define(['dep1', 'dep2'], function (dep1, dep2) {
    //Define the module value by returning a value.
    return function () {};
});
// or
define(function (require) {
    var dep1 = require('dep1'),
        dep2 = require('dep2');
    return function () {};
});

引入模块是异步的
在前端执行

  • UMD: Universal Module Definition
(function (root, factory) {
    if (typeof define === "function" && define.amd) {
        define(["jquery", "underscore"], factory);
    } else if (typeof exports === "object") {
        module.exports = factory(require("jquery"), require("underscore"));
    } else {
        root.Requester = factory(root.$, root._);
    }
}(this, function ($, _) {
    // this is where I defined my module implementation

    var Requester = { // ... };

    return Requester;
}));

如名,可以处理前后端模块
被打包工具用来作为ESM使用不了时兼容处理不同的环境

  • ESM: ECMAScript Module
    �JS模块化提议
// import
import someThing from "./something.js"
import { a, b } from "./someModule.js"

// export
export default function doSomething () {}

在现代浏览器中支持
同步和异步语法都支持
支持摇树
能直接在HTML中使用

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.