x
x
100.24.46.*

最新文章 Latest Blogs

2019-01-14 YHSPY 共  1185 个不明生物围观

《重新定义团队:谷歌如何工作》读书笔记(5/20)。最近花了一些时间来读《重新定义团队:谷歌如何工作》这本书,在这里记录一下书中提出的关键点。怎样才能发挥团队的最大效能,同时让团队中的成员保持高涨的激情,这些都是在团队管理中会经常遇到的问题。

2019-01-08 YHSPY 共  24 个不明生物围观

《阿米巴经营》读书笔记(4/20)。这里记录了一些在读书过程中提炼出我觉得有价值的观点,仅供参考。

2019-01-07 YHSPY 共  55 个不明生物围观

《零售的哲学》读书笔记(3/20)。这里记录了一些在读书过程中提炼出我觉得有价值的观点,仅供参考。读下来铃木先生以其自身的经历为线索介绍了7-11这40年来发展的重点历程。整个创业经验总结出一句话就是“以人为本,学会改变”。相信这样的态度可以让冰冷的“商业”与消费者走的更近,从而获得用户的信任和支持。但这样的创业信条是否适用于处在发展中国家的我们呢?这还是个疑问,持保留态度。

2019-01-05 YHSPY 共  47 个不明生物围观

《增长黑客:创业公司的用户与收入增长秘籍》读书笔记(2/20)。这里记录了一些在读书过程中提炼出我觉得有价值的观点,仅供参考。与其说本书是介绍“增长黑客”不如说是以“增长黑客”为视角来介绍针对创业中几个关键节点(AARRR)的案例和分析。前半部分干货还是有一些的,后半部分稍显不足。书中的案例主观分析只能用做参考,有一些营销技巧和产品准则倒是值得学习和借鉴。

2018-11-29 YHSPY 共  95 个不明生物围观

Git是一款免费、开源的分布式版本控制系统,相比于之前的CVS、SVN等版本控制系统,Git的优势大大凸显。Git是分布式的版本控制系统,相比之前的集中式系统,分布式版本控制系统的安全性要高很多。因为每个人电脑里都有完整的版本库,使得整个版本库不会轻易的丢失。

2018-08-29 YHSPY 共  275 个不明生物围观

鉴于网站的博客发布系统过于老旧,现将内容提交系统重构并增加支持对 Markdown 格式的内容转换。该文章为测试内容,用于测试网站对 MD 转换文本的支持效果。两套渲染模式将兼容存在,网站并无计划进行技术上的整体重构。

2018-01-08 YHSPY 共  1450 个不明生物围观

今天听了银奎老师分享的最近火热技术圈的 Meltdown 漏洞的基本原理,才知道原来底层系统的世界是如此的丰富多彩。Meltdown 漏洞的 POC 实现基于了一种名为 “Flush & Reload” 的黑客攻击技术,这项技术的基本原理是利用 Memory 和 Cache 之间的关系,同时利用统计学的置信程度来筛选关键信息的。

2017-12-24 YHSPY 共  943 个不明生物围观

最近在读《重新定义团队:谷歌如何工作》,学习谷歌在技术团队管理上的一些思考和方式。同时上周也刚刚从杭州 D2 前端技术论坛回来。在会上,来在360和阿里的技术主管也分享了各自在团队管理上的多年经验,特此整理一下会上和自己对技术团队管理的一些思考。

2017-12-17 YHSPY 共  881 个不明生物围观

一般来说,一项新技术是否会随着时代的推进而被快速地迭代和发展,要看这项技术所应用在的实际业务场景中是否有相应的技术需求,毕竟没有任何技术是会被凭空创造出来的。技术决定了业务需求的多样性,而业务需求的多样性又推动着技术不断向前发展,两者相辅相成最终才能推动行业整体的发展和进步。

2017-11-12 YHSPY 共  773 个不明生物围观

如今,软件通常会作为一种服务来交付,它们被称为网络应用程序,或软件即服务(SaaS)。12-Factor 为构建如下的 SaaS 应用提供了方法论。这套理论适用于任意语言和后端服务(数据库、消息队列、缓存等)开发的应用程序。

    文章日期索引 Date Index

    文章类别索引 Type Index

    文章主体 Detail

    PureRenderMixin + immutable.js 提高 VDOM 渲染效率

    用了一段时间的 Reactjs,其实大部分的框架原理和 Vuejs 都很相似,包括响应式、足够轻量级、基于 Virtual-DOM 等特性。从整体上来看,Vuejs 是基于模版进行应用构建的,在中小型应用中有一定的优势。而 Reactjs 则需要我们在 JS 中使用 JSX 手动的来创建 DOM。

    开始一个新的 Reactjs 项目,我们通过自动化的脚手架创建工具 create-react-app 来创建一个初始化的 Reactjs 工程。

    Reactjs 本身通过计算 Virtual DOM 之间的差异(Diff)来更新 UI 组件。每当 props 或者 state 改变时,Reactjs 会重新计算生成一个 Virtual DOM 对象,并且通过比较两个 VM 对象之间的差异来找出数据改变引起对应在 UI 上的差异,最后采用最小的成本来更新 UI。 在纯函数组件(同样的数据对应同样的 UI)下,对于相同的 propsstate,其对应的 UI 显示应该是相同的。因此,当传递给组件的 props 或者 state 的改变与之前相同时,Reactjs 可以完全省略掉此时对组件 VM 的 Diff 计算,这在某种程度上可以提高 Reactjs 组件的渲染性能。为此,Reactjs 为我们提供了扩展的插件(Addon)“PureRenderMixin” 来解决这个问题。

    
    import PureRenderMixin from 'react-addons-pure-render-mixin';
    class FooComponent extends React.Component {
        constructor(props) {
            super(props);
            this.shouldComponentUpdate = PureRenderMixin.shouldComponentUpdate.bind(this);
        }
    
        render() {
            return <div className={this.props.className}>foo</div>;
        }
    }
    

    “PureRenderMixin” 的原理就是它实现了 shouldComponentUpdate,在 shouldComponentUpdate 内它比较当前的 propsstate 和接下来的 props 以及 state,当两者相等的时候返回 false,这样组件就不会进行 Virtual DOM 的 Diff 计算了。但 “PureRenderMixin” 仅进行简单的浅比较,对简单数据类型有效,如果需要对复杂数据类型进行比较来决定是否需要更新 UI,则需要从另一方面来考虑比较两个复杂数据结构所花费的成本和构建 VM 计算 Diff 所花费的成本哪个更大了。如果一定需要对复杂结构的数据来进行差异比较,也可以使用 immutable.js 来帮助我们提高性能。

    总的来说,immutable.js 可以帮助我们提高深拷贝的性能,也即在深度比较两个复杂数据类型时会有更高的性能。immutable.js 提供了7种数据结构,并且这些数据结构均是“不可变数据”,即操作改变这些元素的值时会返回一个新的元素,而原先元素的值不受影响。不仅如此,immutable.js 基于“哈希映射树”和“向量映射书”,在克隆一个数据结构时只会克隆改变的节点以及该节点的所有子节点,因此对于其上层的父节点可以得到完全的复用,这样也可以大大提高“深拷贝”的效率。

    
    shouldComponentUpdate: function(nextProps, nextState) {
        return deepCompare(this, nextProps, nextState);
    },
      
    function deepCompare(instance, nextProps, nextState) {
        return !Immutable.is(instance.props, nextProps) || !Immutable.is(instance.state, nextState);
    }
    
    

    但使用 immutable.js 也有相对应的缺点和不足:1、导致最后打包编译的源码体积增大;2、immutable.js 的数据类型在与服务器进行交互时需要转换成基础的 JavaScript 数据类型;

    发布时间 : 2017-05-18 16:04:49 作者 : YHSPY 类别 : WEB前端 JavaScript
    查看评论
    点击已评论用户的用户名可以@他

    一语浏览 Detail

    语言 C/C++
    
    // 智能指针的错误用法;
    shared_ptr<int> p(new int(42));
    int *q = p.get();
    {
      shared_ptr<int> p(q);
    }
    int foo = *p // 未定义行为,动态内存已被释放;
    
    
    服务器 Linux

    修改用户所属组:

    sudo usermod -G <group> <username>

    语言 C/C++

    inline functions

    优点:

    1、通过避免函数调用开销来加速程序。

    2、当函数调用发生时,它可以节省堆栈上变量调用的开销。

    3、它节省了函数返回的开销。

    4、它利用指令缓存增加了引用的局部性。

    5、通过将其标记为内联,可以将函数定义放在头文件中。

    缺点:

    1、由于代码扩展,它增加了可执行文件的大小。

    2、C++ 内联在编译时解决。这意味着如果更改内联函数的代码,则需要使用它重新编译所有代码以确保它将更新

    3、在头文件中使用时,会使头文件体积增大,进而应用体积增大。

    4、在某些嵌入式系统中无效。因为存储器限制,编译器不希望增大可执行文件大小。

    何时使用:

    1、需要性能时使用内联函数。

    2、在宏上使用内联函数。

    3、喜欢在类外部使用带有函数定义的内联关键字来隐藏实现细节。

    关键点:

    1、是否内联完全取决于编译器的判断。

    2、内联基于编译器控制,这与宏完全不同:宏将被强制内联,将污染所有命名空间和代码,将不容易调试。

    3、默认情况下,在类中声明和定义的所有成员函数都是内联的。所以不需要明确指定。

    4、虚函数不应该是被内联的。有时候,当编译器可以确切地知道对象的类型时,甚至虚函数也会被内联,因为编译器确切地知道了对象的类型。

    5、模板方法并不总是内联的。

    语言 C/C++
    
    // 拷贝构造函数与赋值运算符重载函数;
    #include 
    
    using namespace std;
    
    struct T {
        int x;
    
        T() = default;
    
        T (int x) : x(x) {};
    
        T (const T& t) {
            this->x = t.x;
            cout << "Copy Constructors: " << this->x << endl;
        }
    
        T& operator=(T& t) {
            if (this != &t) {
                this->x = t.x;
                cout << "Overload Function: " << this->x << endl;
            }
            return *this;
        }
    };
    
    int main (int argc, char **argv) {
        T x(10), t3;
        T* t = new T(20);
    
        /*************************/
        // Copy Constructors: 10 //
        /*************************/
        T t1(x); 
        T t2 = x;
    
        /*************************/
        // Overload Function: 10 //
        /*************************/
        t3 = x; 
        
        delete(t);
        return 0;
    }
    
    
    语言 C/C++

    dynamic_cast 可以用于沿继承层级向上、向下及侧向转换到类的指针和引用。但在确保待转换指针的子类型时,可以使用 static_cast 来进行,以避免检查时的开销(可能不安全,但高效)。

    其他 Others

    JWT(JSON WEB TOKEN)

    可用作分布式系统的单点登录验证系统(SSO)。由于 Token 中的 Signature 部分是由前两个字段和一个密钥一起进行加密后得出来的,因此前端无法擅自修改 Token 中的信息,得以保证信息的获取不会被滥用。同时由于 JWT 的 “self-contained“ 特性,原始 Session 中的信息被全部放到了 Token 中,后端不需要存储任何信息,保证了服务的无状态化,提高了可扩展性。

    数据结构:

    交互模式:

    前端 Javascript

    this 实例:

    1、非 ES5 严格模式下,函数调用的默认 this 指向 window,严格模式下指向 undefined

    2、对象中函数的 this 指向调用方;

    
    var person = {  
      name: "Jason",
      say: function(thing) {
        console.log(this.name + " says hello " + thing);
      }
    }
    person.say("world"); // "Jason says hello world"
    
    var iSay = person.say;
    iSay("world"); // "undefined says hello world"
    

    3、使用 bind 来固化 this

    
    var boundSay = person.say.bind(person);  
    boundSay("world") // "Jason says hello world"
    
    前端工程化

    GitFlow 工作流:

    1、主分支只用于 Hotfix 和发布后的发布分支合并;

    2、专门的 Develop 分支用于 Feature 分支的合并;

    3、从 Develop 分支拷贝的发布分支,发布分支只有 Hotfix 合并,发布后合并回主分支和 Develop 分支;

    4、Hotfix 分支合并回主分支和 Develop 分支;

    5、每一次到主分支的合并都需要打 Tag 以便追踪记录;

    前端 HTTP

    HTTPS 通信流程:

    前端 HTTP

    浏览器常用缓存策略流程:

    代码库 Code Depot

    React 实例 - 单一数据源原则
    
    const scaleNames = {
      c: 'Celsius',
      f: 'Fahrenheit'
    };
    
    function toCelsius(fahrenheit) {
      return (fahrenheit - 32) * 5 / 9;
    }
    
    function toFahrenheit(celsius) {
      return (celsius * 9 / 5) + 32;
    }
    
    function tryConvert(temperature, convert) {
      const input = parseFloat(temperature);
      if (Number.isNaN(input)) {
        return '';
      }
      const output = convert(input);
      const rounded = Math.round(output * 1000) / 1000;
      return rounded.toString();
    }
    
    function BoilingVerdict(props) {
      if (props.celsius >= 100) {
        return <p>The water would boil.</p>;
      }
      return <p>The water would not boil.</p>;
    }
    
    class TemperatureInput extends React.Component {
      constructor(props) {
        super(props);
        this.handleChange = this.handleChange.bind(this);
      }
    
      handleChange(e) {
        this.props.onTemperatureChange(e.target.value);
      }
    
      render() {
        const temperature = this.props.temperature;
        const scale = this.props.scale;
        return (
          <fieldset>
            <legend>Enter temperature in {scaleNames[scale]}:</legend>
            <input value={temperature}
                   onChange={this.handleChange} />
          </fieldset>
        );
      }
    }
    
    class Calculator extends React.Component {
      constructor(props) {
        super(props);
        this.handleCelsiusChange = this.handleCelsiusChange.bind(this);
        this.handleFahrenheitChange = this.handleFahrenheitChange.bind(this);
        this.state = {temperature: '', scale: 'c'};
      }
    
      handleCelsiusChange(temperature) {
        this.setState({scale: 'c', temperature});
      }
    
      handleFahrenheitChange(temperature) {
        this.setState({scale: 'f', temperature});
      }
    
      render() {
        const scale = this.state.scale;
        const temperature = this.state.temperature;
        const celsius = scale === 'f' ? tryConvert(temperature, toCelsius) : temperature;
        const fahrenheit = scale === 'c' ? tryConvert(temperature, toFahrenheit) : temperature;
    
        return (
          <div>
            <TemperatureInput
              scale="c"
              temperature={celsius}
              onTemperatureChange={this.handleCelsiusChange} />
            <TemperatureInput
              scale="f"
              temperature={fahrenheit}
              onTemperatureChange={this.handleFahrenheitChange} />
            <BoilingVerdict
              celsius={parseFloat(celsius)} />
          </div>
        );
      }
    }
    
    ReactDOM.render(
      <Calculator />,
      document.getElementById('root')
    );
    

    使用方法:浏览器。

    代码说明:完整的 Reactjs 代码片段。

    一个完整的 React 实例
    
    // sub-component
    function ListItem(props) {
      // Correct! There is no need to specify the key here:
      return <li>{props.value}</li>;
    }
    
    function NumberList(props) {
      const numbers = props.numbers;
      const listItems = numbers.map((number) =>
        // Correct! Key should be specified inside the array.
        <ListItem key={number.toString()}
                  value={number} />
    
      );
      return (
        <ul>
          {listItems}
        </ul>
      );
    }
    
    class Clock extends React.Component {
      constructor(props) {
        // 确保 props 能够正确传入;
        super(props);
        // Bind this
        this.handler = this.handler.bind(this);
        this.state = {
          date: new Date(),
          counter: 0,
          showWarning: true
        };
      }
      // 生命周期 Hook 函数;
      componentDidMount() {
        // 不需要在 View 中显示的属性不需要放到 State 中;
        this.timerID = setInterval(
          () => this.tick(),
          1000
        );
      }
    
      componentWillUnmount() {
        clearInterval(this.timerID);
      }
    
      tick() {
        this.setState({
          date: new Date()
        });
      }
      
      handler() {
        this.setState({
          counter: this.state.counter + 1
        });
      }
    
      render() {
        const numbers = [1, 2, 3, 4, 5];
        // JSX 中的 Callback 函数需要在构造函数中绑定 this 指针;
        return (
          <div>
            <NumberList numbers={numbers} />
            <h1 onClick={this.handler}>Hello, {this.props.user.toString()}!</h1>
            <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
            <h2>Counter: {this.state.counter}</h2>
            <p>{this.state.counter > 2 && <WarningBanner warn={this.state.counter} />}

    </div> ); } } ReactDOM.render( <Clock user="YHSPY"/>, document.getElementById('root') );

    使用方法:浏览器。

    代码说明:完整的 Reactjs 代码片段。

    Node8 之 Util.promisify 常见用法
    
    var util = require('util')
    
    const wait = (delay, callback) => {
      const id = setInterval(() => {
        const rand = Math.random()
        if (rand > 0.95) {
          callback('Got data successfully!', null)
          clearInterval(id)
        } else if (rand < 0.1) {
          callback(null, 'Sorry, something wrong!') 
          clearInterval(id)
        } else {
          console.log("Waiting...")
        }
      }, Number(delay))
    }
    
    /*
      wait(1000, (data, err) => {
        if (err) {
          throw new Error(err)
        }
        console.log(data)
      })
    */
    
    // Use util.promisify
    util.promisify(wait)(1000).then(data => {
      console.log(data);
    }).catch(err => {
      console.error(err);
    })
    
    // Use async/await instead
    waitAsync = util.promisify(wait)
    let asyncFunc = async () => {
      let result;
      try {
        result = await waitAsync(1000);
      } catch (err) {
        return console.error(err);
      }
      return console.log(result);
    };
    asyncFunc().then(data => {
      // undefined
      console.log(data)
    })
    

    使用方法:Node8 命令行下直接运行。

    代码说明:Node8 新增的函数可以直接 Promise 化一个特定格式的函数,函数的回调函数需要符合 Node 的标准回调函数格式 。

    Leetcode - 169.Majority Element HashMap基础解法
    
    public static int majorityElement(int[] nums) {
        if (nums.length == 0)  // 如果数组长度为0则返回-1
        	return -1;
        
        int arrLen = nums.length;
        Map<Integer, Integer> map = new HashMap<>();
        for (int i = 0;i < arrLen; i ++) {
        	int currentVal = 0;
        	if (map.containsKey(nums[i]))  // 如果HashMap中存在该值对应的元素则使用该值
        		currentVal = map.get(nums[i]);
    
        	if (currentVal > arrLen / 2) {  // 如果满足条件则返回该元素
        		return nums[i];
        	} else {
        		map.put(nums[i], currentVal + 1);  // 否则对应元素值加一
        	}
        }
        
        return -1;
    }
    

    使用方法:Eclipse新建工程,直接复制到主类里,通过类名静态调用即可。

    代码说明:本段代码为Leetcode题目“169.Majority Element”的实现代码,算法类代码建议先做题,再参考。题目详情请参考文章《Leetcode每日一题 - 169.Majority Element》。

    Leetcode - 219.Contains Duplicate II 窗口检测解法代码片段
    
    public static boolean containsDuplicateOptimizeFurther(int[] nums) {
        Set<Integer> set = new HashSet<Integer>();  
        int start = 0, end = 0;  // 定义窗口的首尾指针
        for(int i = 0; i < nums.length; i++) {   // 开始遍历
            if(!set.contains(nums[i])) {    
                set.add(nums[i]);   
                end++;   // 如果Set中没有此元素则加入,尾指针后移
            } else { 
                return true;   // 有则返回True
            }
            
            if(end - start  > k) {  // 保持首尾指针距离不大于k  
                set.remove(nums[start]);    //如果大于则移除首指针元素
                start++;   // 移除后首指针后移
            }  
        }  
        return false;
    }
    

    使用方法:Eclipse新建工程,直接复制到主类里,通过类名静态调用即可。

    代码说明:本段代码为Leetcode题目“219.Contains Duplicate II”的实现代码,算法类代码建议先做题,再参考。题目详情请参考文章《Leetcode每日一题 - 219.Contains Duplicate II》。