Haoqi's blog-ish!

blah blah blah


  • 首页

  • 归档

vue computed watch

发表于 2019-04-01 | 分类于 vue计算属性

anchors

  • 定义computedwatcher
    • computedwatcher定义流程
    • computedwatcher更新流程
  • userwatcher
    • watcher创建
    • watcher四个options

题外

  • watcher定义后会立即执行一次getter(不是cb) this.value = this.lazy ? undefined : this.get();

  • defineReactive为在模型上的每个属性, 创建dep. 谁get那个属性就把target watcher添加到dep.subs里去.

  • render watcher执行一次get后, 让不再引用的的属性的dep取消订阅自己.

定义computedwatcher

computedwatcher定义流程

  • vm实例上定义_computedWatchers-
  • 创建watcher(传入选项{ lazy: true }), 创建watcher 时不调用get
  • 非组件实例getter将通过defineProperty挂在vm上, 组件的defineComputed, extend构造函数的时候就执行了, computed的get被挂到了vm.prototypes上进行复用
  • computed watcher的get在render vnode的时候通过get属性触发.
    • 先调用watcher.evaluate, 调用定义的computed.xx.getter, 让相关属性的dep添加这个computed watcher
    • 再调用watcher.depend, 让相关属性的dep添加render watcher
    • watcher在内部依赖的属性更新时触发, watcher在调用get后会触发render watcher的的get执行.
  • v2.5.17中的值不变不重新渲染,也只是昙花一现
阅读全文 »

snabbdom, jsx学习

发表于 2019-03-31 | 分类于 virtual-dom snabbdom

createVnode

  • snabbdom创建vnode比较简单, 就是遍历创建对象
  • 相当于Vue里的 vm.$createElement(自己写render的时候调用,alwaysNormalize是true)或vm._c
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    function h(sel, data, children) {
    // option adapter
    // ...
    if (is.array(children)) {
    for (i = 0; i < children.length; ++i) {
    if (is.primitive(children[i]))
    children[i] = vnode_1.vnode(undefined, undefined, undefined, children[i]);
    }
    }
    return vnode_1.vnode(sel, data, children, text, undefined);
    }
    function vnode(sel, data, children, text, elm) {
    var key = data === undefined ? undefined : data.key;
    return { sel: sel, data: data, children: children,
    text: text, elm: elm, key: key };
    }
阅读全文 »

vue reactivity

发表于 2019-03-28 | 分类于 vue源码 响应式

anchors

  • 定义响应式
    • 定义响应式流程
    • user-watcher响应式流程
  • 依赖收集
  • 派发更新
  • vue-nextTick
  • 手动设置响应式和数组响应式

题外

  • watcher定义后会立即执行一次getter(不是cb) this.value = this.lazy ? undefined : this.get();
  • Observe里面有dep, defineReactivity里也有dep.
  • defineReactive为在模型上的每个属性, 创建dep. 谁get那个属性就把target watcher添加到dep.subs里去.
  • render watcher执行一次get后, 让不再引用的的属性的dep取消订阅自己.

定义响应式

定义响应式流程

  • 遍历属性对象, 通过getter定义代理到vm上
  • 为属性对象添加observer, data.__ob__ = new Observer(data)
  • 关系为data有dep, dep里有watcher, watcher里有dep.循环依赖?
  • defineReactive内部又new dep去notify和depend, 那observer里的dep有什么用?
    • childOb.dep.depend();
      阅读全文 »

vue 组件化

发表于 2019-03-23 | 分类于 vue源码 组件化

anchors

  • render组件时创建vnode是个深度遍历过程
    • 创建组件占位符vnode
    • 关联父子关系vnode, vm
    • 子组件递归patch相关代码
  • merge-option
  • 生命周期
  • 异步组件

题外

  • 组件在render的时候就调用了那些响应式属性的getter了,也就收集了依赖.
  • 哪个vm调用update,就是activeInstance, vm.$vnode是占位vnode, vm._vnode的渲染vnode
  • new组件的Vue之前做option合并, 原型继承返回新constructor
  • merge(Vue.options, vm.options)
  • 声明的component都是Vue的孙子构造函数, 在什么时候new呢? createComponentInstanceForVnode里执行了return new vnode.componentOptions.Ctor(options)
  • 挂载点就是父vm里template出现的位置

render组件时创建vnode是个深度遍历过程

创建组件占位符vnode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
function createComponent (
Ctor, // 组件的constructor
data,
context, // 父vm
children,
tag
) {
var baseCtor = context.$options._base;
// plain options object: turn it into a constructor
if (isObject(Ctor)) {
Ctor = baseCtor.extend(Ctor);
}
if (typeof Ctor !== 'function') {
return
}
// async component mixin, v-model省略
// install component management hooks onto the placeholder node
installComponentHooks(data);
// return a placeholder vnode
var name = Ctor.options.name || tag;
var vnode = new VNode(
("vue-component-" + (Ctor.cid) + (name ? ("-" + name) : '')),
data, undefined, undefined, undefined, context,
{ Ctor: Ctor, propsData: propsData, listeners: listeners, tag: tag, children: children },
asyncFactory
);
return vnode
}
阅读全文 »

事件循环

发表于 2019-03-03 | 分类于 interview event-loop

简介

事件循环在浏览器和node环境机制不同, 一个是h5规范的实现, 一个集成libuv库的功能. 理解事件循环对js异步非阻塞的理解有会有所帮助.
在浏览器里每个web worker都有自己的事件循环系统.

概念

  • js只有一个线程:避免DOM渲染冲突.
    • 浏览器需要渲染DOM
    • JS可以修改DOM结构
    • JS执行的时候,浏览器DOM渲染会暂停
    • 两端JS也不能同时执行(都修改DOM就冲突了)
    • webworker支持多线程,但是不能访问DOM
  • js运行时包含call stack(回调要执行了就放入栈里), heap, task queue.
  • 事件队列,分为
    • micro taskqueue: Promise的then, MutationObserver, process.nextTick
    • macro taskqueue: setInterval, setTimeout, setImmediate(ie), MessageChannel, dispatching event(js执行node.click()方法不算)
阅读全文 »

webpack under-the-hood

发表于 2019-02-27 | 分类于 webpack optimization webpack3

webpack优化

webpack构建流程

  • 初始化:启动构建,读取与合并配置参数,加载 Plugin,实例化 Compiler。
  • 编译:从 Entry 发出,针对每个 Module 串行调用对应的 Loader 去翻译文件内容,再找到该 Module 依赖的 Module,递归地进行编译处理。
  • 输出:对编译后的 Module 组合成 Chunk,把 Chunk 转换成文件,输出到本地。

  • _addModuleChain,其完成的第二件事构建模块又可以分为三部分:

    • 调用loader处理模块之间的依赖
    • 将loader处理后的文件通过acorn抽象成抽象语法树AST
    • 遍历AST,构建该模块的所有依赖

流程细节

1. 参数处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// bin/webpack.js入口
require("./config-yargs")(yargs);
yargs.parse(process.argv.slice(2), (err, argv, output) => {
// ....
var options = require("./convert-argv")(yargs, argv);
var webpack = require("../lib/webpack.js"); // node_modules/webpack/bin/webpack.js:329
compiler = webpack(options);
if(firstOptions.watch || options.watch) {
compiler.watch(watchOptions, compilerCallback);
} else {
compiler.run(compilerCallback);
}
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// lib/webpack.js入口
// `lib/webpack(options, (err, stats) => {})` 在node后面执行, 没有cb就只是创建compiler. 有cb就会顺带执行compiler.run
function webpack(options, callback) {
new WebpackOptionsDefaulter().process(options);
compiler = new Compiler();
compiler.context = options.context;
compiler.options = options;
new NodeEnvironmentPlugin().apply(compiler);
if(options.plugins && Array.isArray(options.plugins)) {
compiler.apply.apply(compiler, options.plugins);
}
compiler.applyPlugins("environment");
// node_modules/webpack/lib/webpack.js:36
compiler.applyPlugins("after-environment");
compiler.options = new WebpackOptionsApply().process(options, compiler);
// ...
if(callback) {
if(options.watch === true) {
return compiler.watch(watchOptions, callback);
}
compiler.run(callback);
}
return compiler;
}
  • WebpackOptionsApply.process根据选项apply对应的插件,如library/externals/devtool, 包括entry-option, 后面会调用addEntry
    1
    2
    3
    4
    5
    6
    7
    8
    9
    // webpack3写法
    //node_modules/webpack/lib/WebpackOptionsApply.js:234
    compiler.apply(new EntryOptionPlugin());
    compiler.applyPluginsBailResult("entry-option", options.context, options.entry);
    // webpack4写法
    //node_modules/webpack/lib/WebpackOptionsApply.js:306
    new EntryOptionPlugin().apply(compiler);
    compiler.hooks.entryOption.call(options.context, options.entry);

2. run 触发compile

  • 在run的过程中,会触发了一些钩子:beforeRun->run->beforeCompile->compile->make->seal
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// node_modules/webpack/lib/Compiler.js:270
// 方法继承自Tapable.prototype.applyPluginsAsync
this.applyPluginsAsync("before-run", this, err => {
if(err) return callback(err);
this.applyPluginsAsync("run", this, err => {
if(err) return callback(err);
this.readRecords(err => {
if(err) return callback(err);
this.compile(onCompiled);
});
});
});
  • 当 Webpack 以开发模式运行时,每当检测到文件变化,一次新的 Compilation 将被创建。
    • compiler.watch监视依赖文件的修改
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// node_modules/webpack/lib/Compiler.js:490
compile(callback) {
const params = this.newCompilationParams();
this.applyPluginsAsync("before-compile", params, err => {
if(err) return callback(err);
this.applyPlugins("compile", params);
const compilation = this.newCompilation(params);
this.applyPluginsParallel("make", compilation, err => {
if(err) return callback(err);
compilation.finish();
compilation.seal(err => {
if(err) return callback(err);
this.applyPluginsAsync("after-compile", compilation, err => {
if(err) return callback(err);
return callback(null, compilation);
});
});
});
});
}

3. 参数处理

4. 参数处理

5. 参数处理

6. 参数处理

阅读全文 »

frontend interview

发表于 2019-02-22 | 分类于 frontend interview

笔记年羹

前端基础

  • JS 原型链机制的理解
  • 作用域和this
    • 代码在一个环境中执行时,会创建变量对象的一个作用域链
    • 每个函数都有自己的作用域(函数作用域, let引入块作用域), 作用域可以层层嵌套, 子作用域变量覆盖父级作用域
    • 声明提前: js函数里所有变量声明(var)都被提前至函数体顶部.
    • es6: temporal dead zone, let代码段(if/for/switch)变量声明前引用会报ReferenceError
    • JS专题之严格模式
    • this四种绑定
      • 默认绑定全局window
      • 隐式绑定,最近的一个调用该函数的上下文对象(context object)
        • 在函数上下文中,也就是在任何函数体内部,this 指代调用函数的那个对象。严格模式下,this禁止指向window
      • 显式绑定(call/apply/bind), bind在定义函数时候就绑定this,call和apply在调用函数时候才绑定this
        • call、apply和bind的实现
      • new绑定
        • 一个全新的对象会凭空创建(就是被构建)
        • 这个新构建的对象会被接入原形链([[Prototype]]-linked)
        • 这个新构建的对象被设置为函数调用的this绑定
        • 除非函数返回一个它自己的其他 对象,这个被new调用的函数将 自动返回这个新构建的对象
  • 闭包: 只有函数内部的子函数才能读取函数的局部变量. 闭包内的变量因为引用计数, 不会在函数调用完后清除.
    • 闭包做对象缓存, 模块化代码. 闭包会使得函数中的变量都被保存在内存中.滥用导致内测泄露.
    • 调用 f.bind(someObject) 会创建一个与 f 具有相同函数体和作用域的函数,但是在这个新函数中,this 将永久地被绑定到了 bind 的第一个参数,无论这个函数是如何被
  • 对象:

    • 基础类型string,number,boolean,null,undefined,object, build-in对象类型String,Number,Boolean,Object,Function,Array,Date,RegExp,Error
    • defineProperties:
      • [[Configurable]]:表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为数据属性。默认值为true。
      • [[Enumerable]]:表示能否通过for…in…循环遍历到该属性,默认值为true。
      • 访问器属性 [[Get]]:在读取属性时调用的函数。默认值为undefined。
      • 访问器属性 [[Set]]:在写入属性时调用的函数。默认值为undefined。
      • 数据属性 [[Writable]]:表示能否修改属性的值,默认为true。
      • 数据属性 [[Value]]:该属性的数值。
    • ...,assign都是浅拷贝
  • 设计模式:了解基本的前端设计模式,单例、适配器、工厂、观察者、迭代器、发布/订阅。

    • es6实现工厂/单例模式
  • 跨域的方式、同源策
    略、为什么有同源策略、如何做安全防范:新=的- H5的跨域方式(cors、postmessage)。

  • 安全,对攻击方式、安全的防范上的了解 。
  • http、TCP 协议的知识,如:什么是无状态,http 状态码的分类。
    • CDN的域名不要和主站的域名一样,这样会防止访问CDN时还携带主站cookie的问题。
  • 知晓 CSS 布局原理,什么是BFC,如何实现垂直居中,绝对定位相对位置。
  • 如何做自适应布局,怎么计算 REM
  • websocket, WebRTC, EventSource 的区别

框架、组件化

  • 架构分层
  • 模块解耦:理解接口、事件通讯的两种方式。
  • 组件化趋势: shadow dom,react和vue 。
  • Virtual DOM 的优势以及缺陷
    • 减少dom的增删开支, 增加js计算消耗.
    • 未命中sameNode, 还是一样的dom增删消耗, 同级修改, 添加key.
    • dom结构越庞大, 优化的效果越明显.
    • snabbdom的怕patch算法和vue的一致.
  • 实践中如何解耦 UI 状态和领域状态
  • 目录结构如何规划

前端构建方案

  • 工程化的理解以及解决的问题如 gulp。
  • 如何拆分 SPA 中的大型代码
  • 有没有写过 webpack loader/ plugin, 以及这个 loader 是为了解决什么问题
  • 做过什么打包优化, 分离全家桶, 脚本构建npm/yarn
  • ts项目搭建
  • 性能优化

  • webview的优化:对静态资源缓存到native的原理和流程 ,- webview缓存、版本号管理、线下调试。

  • 如何加快首屏加载速度,Server Render 的实践。
  • 网页渲染性能优化,layout, paint, compose 三步骤的理解。
  • css 动画、SVG、canvas 的运用
  • 针对前端框架的性能优化,如 showComponentUpdate 的使用
  • 如何带领团队优化:制定量化指标,寻找性能瓶颈,集中优化。
  • 浏览器资源加载, 解析, 渲染.
  • 事件循环, 异步promise理解
  • 案例:

    1. Vue 应用性能优化指南
      阅读全文 »

vue-mechanism

发表于 2018-02-05 | 分类于 vue

vue reactivity

How Changes Are Tracked

  • Walk through data properties and convert them to getter/setter using Object.defineProperty.
  • Every component instance has a corresponding watcher instance, which records any properties “touched” during the component’s render as dependencies. Later on when a dependency’s setter is triggered, it notifies the watcher, which in turn causes the component to re-render.

    Add properties to an already created instance.

  1. Vue.set(vm.someObject, 'b', 2) or this.$set(this.someObject, 'b', 2)
  2. this.someObject = Object.assign({}, this.someObject, { a: 1, b: 2 })
阅读全文 »
123…6

浩齐

some kind of blog

44 日志
33 分类
61 标签
© 2019 浩齐
由 Hexo 强力驱动
|
主题 — NexT.Muse v5.1.4