日记

日记

  • Diary
  • GitHub

›All Blog Posts

All Blog Posts

  • 再看高程3
  • 面试
  • 个人简历
  • react的高性能
  • webpack源码学习
  • 树莓派
  • 布局
  • 模块化
  • 攻击与安全
  • 异步
  • TODO
  • React状态管理比较
  • 性能优化
  • HTTP缓存
  • (译)JS中数据的改变与发现
  • CSS杂记
  • XML与SVG
  • 个人简历
  • Workspaces是什么
  • NPM包测试之低高级策略
  • 谈谈version
  • 减肥之道
  • 问题汇总
  • 一个nginx配置
  • 好用的工具
  • 好用的npm包
  • 流行框架学习对比

再看高程3

January 13, 2019

什么是执行环境

执行环境定义了变量或者函数有权访问的其他数据,决定了各自的行为。

全局执行环境是最外围的一个执行环境

每个函数都有一个执行环境

当代码在一个环境中执行时,会创建一个作用域链。保证执行环境有权访问的所有变量和函数

作用域链示意

代码

var color = 'blue';
function changeColor() {
  var anotherColor = 'red';

  function swapColor() {
    var tempColor = anotherColor;
    anotherColor = color;
    color = tempColor;
  }

  swapColor();
}

changeColor();

图示

window
 |
 +--- color
 |
 +--- changeColor()
        |
        +--- anotherColor
        |
        +--- swapColor()
                |
                +--- tempColor

this指向问题

window.color = 'red';
var o = {color: 'blue'};
function sayColor(){
  console.log(this.color);
}
sayColor(); //'red'
o.sayColor = sayColor;
o.sayColor(); // 'blue'

由于在函数调用之前,this的值并不确定,因此this可能在执行代码的过程中引用不同的对象

  • 在全局调用,this指向window
  • 把函数赋值给o,并调用o.sayColor(),this指向o

函数属性和方法

  • 每个函数都包含两个属性lenght和prototype
  • 每个函数都包含两个非继承来的方法apply和call
function sum(a, b) {
  return a + b;
}
function sum1(a, b) {
  return sum.call(this, a, b);
}

sum1(10, 20) //30

事实上,传递参数并非call和apply的用武之地;他们真正强大的地方在于能够扩充函数赖以运行的作用域。

var a = [1,2,3];
var b = [5,6,7];
a.push.apply(a, b); // a= [1,2,3,4,5,6]; a.push(b)是达不到这种效果的,用concat也不行

原型模式

当调用一个构造函数创建一个实例后,该实例的内部将包含一个指针,指向构造函数的原型对象

function Person(){
}

Person.prototype.name = 'a';
Person.prototype.say = function() {
  console.log(this.name);
}

person1 = new Person();
    +-----<---------------------------------------+ 
    |         + --+----> Person Prototype         |
Person        |   |      constructor----------->--+
prototype-->--+   |      name
                  |      say()
                  |
person1           |
[[prototype]]--->-+

闭包

function create(propertyName) {
  return function(obj1, obj2) {
    var value1 = obj1[propertyName];
    var value2 = obj2[propertyName];
  }
}

函数第一次被调用,会创建执行环境和一个作用域链,并使用this,arguments等初始化活动对象

在匿名函数从create返回后,他的作用于链被初始化为包含create的活动对象和全局变量。在create执行完毕后其活动对象也不会被销毁,因为匿名函数的作用域链仍在引用这个活动对象。但是create的执行环境会被销毁。直到匿名函数被销毁后,create的活动对象才会被销毁。

闭包的作用

  • 模范块级作用域
  • 创建私有变量

跨浏览器

  • css
  • dom
  • ajax

Ajax

跨域请求的方法

  • 图像ping
  • jsonp
  • cors

ajax的进一步扩展

  • comet
  • sse
  • websocket

面试

January 7, 2019

智保科技

  • functionComponent、component、pureComponent、高阶component
    • pureComponent
    • functionComponent
  • React Fiber
  • http协商缓存VS强缓存
  • 面试总结

京东面试

  • redux的几个概念
  • redux思想
  • connect的原理,源码 - TODO
  • redux thunk的原理,源码 - TODO
  • 原型和原型链 - TODO
  • grid布局指南
  • flex布局指南
  • 一行 CSS 代码实现响应式布局
  • 理解CSS布局和BFC

常见的FC有BFC、IFC(行级格式化上下文),还有GFC(网格布局格式化上下文)和FFC(自适应格式化上下文),这里就不再展开了。

  • 前端面试
  • 前端范式化
    • 前端范式化
    • 范式化工具normalizr
    • twitter前端架构
  • 展示组件和容器组件

泡米文化面试

  • 从输入url到浏览器显示页面发生了什么
  • 浏览器兼容性
  • box-sizing
  • 组件的生命周期
  • 8 大前端安全问题(上)
  • 8 大前端安全问题(下)

安恒信息

  • 用户认证
  • 理解Cookie和Session机制
  • 为什么用Object.prototype.toString.call(obj)检测对象类型?
  • javascript中判断数据类型的四种方法及typeof、instanceof、constructor、toString
  • 图片懒加载

tap4fun

  • HTML5 history API,创造更好的浏览体验
  • window.postMessage
  • location.hash
  • react diff算法
  • 网上都说操作真实 DOM 慢,但测试结果却比 React 更快,为什么?

中建电子

  • js小数计算精度问题
  • 十进制转化为二进制
  • 揭秘context
  • getDerivedStateFromProps

G7

  • Promise细节
    • Promise.prototype.then(onFulfilled, onRejected)
      • 添加解决(fulfillment)和拒绝(rejection)回调到当前 promise, 返回一个新的 promise, 将以回调的返回值来resolve.
  • 无限调用函数

      var sum = 0;
      function add(a){
        sum += a;
        console.log(sum)
        return add;
      }
    
  • codeSplit
  • 按需加载

快牛金科

  • webpack代码分离 ensure 看了还不懂,你打我
  • Webpack的Code Splitting实现按需加载

个人简历

January 6, 2019

尹士勇

尹士勇(男)

求职意向:前端工程师
期望薪资:20K~25k
电话:(0)188-1096-1061
邮箱:braveyin168@outlook.com

工作经历

2018.07~2018.11
货车帮·大客户
前端工程师(TL)
成都

货车帮是中国最大的公路物流互联网信息平台

公铁项目救急
入职后,组员告知一个项目需要3天后上线。经了解后发现开发工作量大,开发人员少,很难按时交付。当即向产品经理和项目经理风险报告,一边他们向第三方要时间,一边我安排人手开发项目并自己参与到开发中,最终按照新的上线时间点按时顺利上线。
通用公告系统
一次未和运营方充分确认的上线,对运营造成了一定的影响。我在思考除了严格遵守上线发邮件确认的流程,还需要有一个通用的公告系统来解决这个问题,甚至取代发邮件确认。这个系统应该是一个react组件并且封装了后端处理,它的后端服务端应该是一个独立的基础服务。这样其他系统仅仅引入一个react组件,便有了一个公告系统。前端老大对我的这个想法高度赞同。
甩挂项目攻坚
甩挂项目第一版本联调中发现组员做的配载这里经常出问题(配载模块计算全部放在前端进行,涉及到了重量、体积、价格、已配载量、剩余量、添加物品和删除物品等诸多逻辑,复杂度比较高,是整个系统的核心与难点)。跟其交流后发现他对这里的计算逻辑并没有彻底理清楚就开始了编码,且其代码耦合度非常高。帮助其理清了思路且重构了代码后一切就迎刃而解了。
2014.07~2018.07
去哪儿·大住宿
前端工程师
北京

去哪儿是中国领先的旅游搜索引擎,去哪儿是目前全球最大的中文在线旅行网站

业务上

  • 参与4个web网站、1个公众号、1个H5和2个RN项目的开发
  • 主导1个web网站的开发
  • 酒店业务华为对接,协调团结10多个小组近30人,推动项目的发展,按时交付

技术上

  • 设计开发任务模板系统,提高运营效率100%,省50%成本,获年度优秀项目奖(10,000元)
  • 设计开发npm包q-antd,提高项目开发效率30%,提高项目易维护性30%
  • 优化去哪儿前端构建工具packing,新建页面错误率降为0,新建页面节省50%时间
  • 设计开发grunt-i19n插件,准确率提高到100%,节省50%工作时间

教育背景

2010.09~2014.07
西南科技大学
计算机科学与技术/本科

工作技能

  • 掌握JavaScript(ES6)、React、React Native、Vue
  • 熟悉mobx、rxjs、redux、dva
  • 熟悉iview、antd
  • 熟悉github、travis、jest、enzyme、eslint、prettier
  • 熟悉node、socket.io、packing、webpack、bash、python、django
  • 熟悉ajax、CORS、http、websocket
  • 熟悉jquery、html、pug、css

自我评价

  • 做事细心,尽职尽责
  • 基础扎实,学习能力强
  • 好奇心强,打破砂锅问到底

react的高性能

January 5, 2019

  • 使用Immuttable优化性能
  • mobx自带性能优化

webpack源码学习

December 28, 2018

webpack的执行流程

webpack
 |
WebpackOptionsDefaulter
 |
Compiler(Tapalbe) --
          |
          this.hooks = {
            shouldEmit: new SyncBailHook(["compilation"]),
            done: new AsyncSeriesHook(["stats"]),
            additionalPass: new AsyncSeriesHook([]),
            beforeRun: new AsyncSeriesHook(["compiler"]),

            run: new AsyncSeriesHook(["compiler"]),
            emit: new AsyncSeriesHook(["compilation"]),
            afterEmit: new AsyncSeriesHook(["compilation"]),

            thisCompilation: new SyncHook(["compilation", "params"]),
            compilation: new SyncHook(["compilation", "params"]),
            normalModuleFactory: new SyncHook(["normalModuleFactory"]),
            contextModuleFactory: new SyncHook(["contextModulefactory"]),

            beforeCompile: new AsyncSeriesHook(["params"]),
            compile: new SyncHook(["params"]),
            make: new AsyncParallelHook(["compilation"]),
            afterCompile: new AsyncSeriesHook(["compilation"]),

            watchRun: new AsyncSeriesHook(["compiler"]),
            failed: new SyncHook(["error"]),
            invalid: new SyncHook(["filename", "changeTime"]),
            watchClose: new SyncHook([]),

            // TODO the following hooks are weirdly located here
            // TODO move them for webpack 5
            environment: new SyncHook([]),
            afterEnvironment: new SyncHook([]),
            afterPlugins: new SyncHook(["compiler"]),
            afterResolvers: new SyncHook(["compiler"]),
            entryOption: new SyncBailHook(["context", "entry"])
        };

树莓派

July 13, 2018

购物清单

  • 继电器 3
  • 二极管 3
  • 红外感应器 3
  • 面包板 1
  • 连接线 公母头 若干
  • 270欧姆的电阻(若干)
  • 光线传感器

配置pi

sudo raspi-config

这里的配置很丰富呢,比如网络配置,比如启动模式配置等等,都可以在这里设置

布局

June 26, 2018

固定布局

所有尺寸一律使用px

  • 优点:简单,无兼容性问题
  • 缺点:不能根据不同屏幕尺寸,有不同的表现

移动端也可采用固定布局

有两种方式

  1. viewport width 320 + initial-scale
    • 在viewport meta标签上设置width=320,页面的各个元素也采用px作为单位。
    • 通过用JS动态修改标签的initial-scale使得页面等比缩放,从而刚好占满整个屏幕。
  2. viewport width 640 + user-scale=no
    • 页面的各个元素也采用px作为单位
    • 由于640px超出了手机宽度,浏览器会自动缩小页面至刚好全屏

viewport

手机浏览器是把页面放在一个虚拟的"窗口"(viewport)中,通常这个虚拟的"窗口"(viewport)比屏幕宽,这样就不用把每个网页挤到很小的窗口中(这样会破坏没有针对手机浏览器优化的网页的布局),用户可以通过平移和缩放来看网页的不同部分。

<!DOCTYPE html>
<html>
  <head>
    <meta name="viewport" content="width=640, initial-scale=1.0, user-scale=no" />
  </head>
</html>
  • width 控制 viewport 的大小,可以指定的一个值,如 600,或者特殊的值,如 device-width 为设备的宽度(单位为缩放为 100% 时的 CSS 的像素)
  • height 和 width 相对应,指定高度
  • initial-scale 初始缩放比例,也即是当页面第一次 load 的时候缩放比例
  • maximum-scale 允许用户缩放到的最大比例
  • minimum-scale 允许用户缩放到的最小比例
  • user-scalable 用户是否可以手动缩放

流式布局

网页中主要的划分区域的尺寸使用百分数(搭配min-、max-属性使用),例如,设置网页主体的宽度为80%,min-width为960px

这种布局缺点明显:宽度使用百分比定义,但是高度和文字大小等大都是用px来固定,所以在大屏幕的手机下显示效果会变成有些页面元素宽度被拉的很长,但是高度、文字大小还是和原来一样(即,这些东西无法变得“流式”),显示非常不协调。

弹性布局

包裹文字的各元素的尺寸采用em做单位,而页面的主要划分区域的尺寸仍使用百分数或px做单位(同「流式布局」或「固定布局」)

CSS编写者常常把body元素的font-size设置为62.5%(浏览器默认字体大小16px*62.5%=10px),这样1em便是10px,方便了计算。

使用了rem单位的弹性布局在移动端也很受欢迎。

其实,使用vw、vh等后起之秀的单位,可以实现完美的流式布局(高度和文字大小都可以变得“流式”),弹性布局就不再必要了。

响应式布局

随着CSS3出现了媒体查询技术,又出现了响应式设计的概念。响应式设计的目标是确保一个页面在所有终端上(各种尺寸的PC、手机、手表、冰箱的Web浏览器等等)都能显示出令人满意的效果,对CSS编写者而言,在实现上不拘泥于具体手法,

但通常是糅合了流式布局+弹性布局,再搭配媒体查询技术使用。

模块化

June 25, 2018

Shiyong Yin

无模块化的时代

开始的开始,我们都是孩子。

最开始是没有模块化这一说的,都是script标签异步引入。

CommonJS

服务端的JavaScript——Nodejs使用了CommonJS并将其发扬光大,这标志着JavaScript模块化正式登上历史的舞台。

  1. 定义模块
    • 每个文件就是一个模块,每个模块都是一个单独的作用域
  2. 模块输出
    • 模块只有一个出口module.exports
  3. 加载模块
    • require('lodash')

我们发现require是同步的。模块系统需要同步读取模块文件内容,并编译执行以得到模块接口。 这在服务器端实现很简单,也很自然,然而, 想在浏览器端实现问题却很多。

AMD

Asynchronous Module Definition

AMD规范的代表作就是requirejs。

requirejs解决了两个问题:

  1. 多依赖问题——多个js文件可能有依赖关系,被依赖的文件需要早于依赖它的文件加载到浏览器
  2. 阻塞问题——js加载的时候浏览器会停止页面渲染,加载文件越多,页面失去响应时间越长
// 定义模块 myModule.js
define(['dependency'], function(){
    var name = 'Byron';
    function printName(){
        console.log(name);
    }

    return {
        printName: printName
    };
});

// 加载模块
require(['myModule'], function (my){
  my.printName();
});

require()函数在加载依赖的函数的时候是异步加载的,这样浏览器不会失去响应,它指定的回调函数,只有前面的模块都加载成功后,才会运行,解决了依赖性的问题。

CMD

Common Module Definition

CMD规范的代表作就是seajs。

seajs解决的问题和requirejs是一样的。多依赖问题和阻塞问题。

// 定义模块  myModule.js
define(function(require, exports, module) {
  var $ = require('jquery.js')
  $('div').addClass('active');
});

// 加载模块
seajs.use(['myModule.js'], function(my){

});

seajs原理参阅:

  • https://www.cnblogs.com/ada-zheng/p/4330506.html
  • https://www.cnblogs.com/jfmblog/p/5650979.html

AMD与CMD区别

下面的例子一目了然

/** AMD写法 **/
define(["a", "b", "c", "d", "e", "f"], function(a, b, c, d, e, f) { 
     // 等于在最前面声明并初始化了要用到的所有模块
    a.doSomething();
    if (false) {
        // 即便没用到某个模块 b,但 b 还是提前执行了
        b.doSomething()
    } 
});

/** CMD写法 **/
define(function(require, exports, module) {
    var a = require('./a'); //在需要时申明
    a.doSomething();
    if (false) {
        var b = require('./b');
        b.doSomething();
    }
});

最明显的区别是

  • AMD依赖前置
  • CMD依赖就近

AMD在模块加载完成后就会执行该模块,所有模块加载完成进入回调函数,执行主逻辑。 这个就导致了,依赖执行的顺序和加载的顺序不一致。完全取决于哪个先下载下来。

CMD加载摸个依赖后并不执行,只是下载而已。所有依赖加载完成后进入主逻辑,遇到require才执行 对应的模块,这样模块的执行顺序和书写顺序完全一致。

ES6 Module

这个其实就是类似CommonJS了,同步的。

攻击与安全

June 25, 2018

Shiyong Yin

XSS

SQL注入

CSRF

Cross—Site Request Forgery(伪造) 跨站点请求伪造 优秀博文 https://www.cnblogs.com/shytong/p/5308667.html

攻击过程

  1. A访问站点B,并登陆
  2. B将cookie存于A的浏览器中
  3. A在B站点登陆的情况下,访问站点C
  4. 站点C利用A在B站点登陆的状态,向A站点发送伪造请求,实施攻击

防御方法

  1. HTTP Referer

    根据 HTTP 协议,在 HTTP 头中有一个字段叫 Referer,它记录了该 HTTP 请求的来源地址。在通常情况下,访问一个安全受限页面的请求来自于同一个网站,比如需要访问 http://bank.example/withdraw?account=bob&amount=1000000&for=Mallory,用户必须先登陆 bank.example,然后通过点击页面上的按钮来触发转账事件。这时,该转帐请求的 Referer 值就会是转账按钮所在的页面的 URL,通常是以 bank.example 域名开头的地址。而如果黑客要对银行网站实施 CSRF 攻击,他只能在他自己的网站构造请求,当用户通过黑客的网站发送请求到银行时,该请求的 Referer 是指向黑客自己的网站。

    然而,这种方法并非万无一失。Referer 的值是由浏览器提供的,虽然 HTTP 协议上有明确的要求,但是每个浏览器对于 Referer 的具体实现可能有差别,并不能保证浏览器自身没有安全漏洞。

  2. token

    CSRF 攻击之所以能够成功,是因为黑客可以完全伪造用户的请求,该请求中所有的用户验证信息都是存在于 cookie 中,因此黑客可以在不知道这些验证信息的情况下直接利用用户自己的 cookie 来通过安全验证。

    要抵御 CSRF,关键在于在请求中放入黑客所不能伪造的信息,并且该信息不存在于 cookie 之中。可以在 HTTP 请求中以参数的形式加入一个随机产生的 token,并在服务器端建立一个拦截器来验证这个 token,如果请求中没有 token 或者 token 内容不正确,则认为可能是 CSRF 攻击而拒绝该请求。

异步

June 25, 2018

Shiyong Yin

异步方式

  • 回调
  • 监听函数
  • 发布/订阅
  • Promise
  • generator
  • async

async与generator区别

async函数就是将 Generator 函数的星号(*)替换成async,将yield替换成await,仅此而已。 async函数对 Generator 函数的改进,体现在以下四点。

(1)内置执行器。

Generator 函数的执行必须靠执行器,所以才有了co模块,而async函数自带执行器。也就是说,async函数的执行,与普通函数一模一样,只要一行。

asyncReadFile(); 上面的代码调用了asyncReadFile函数,然后它就会自动执行,输出最后结果。这完全不像 Generator 函数,需要调用next方法,或者用co模块,才能真正执行,得到最后结果。

(2)更好的语义。

async和await,比起星号和yield,语义更清楚了。async表示函数里有异步操作,await表示紧跟在后面的表达式需要等待结果。

(3)更广的适用性。

co模块约定,yield命令后面只能是 Thunk 函数或 Promise 对象,而async函数的await命令后面,可以是 Promise 对象和原始类型的值(数值、字符串和布尔值,但这时会自动转成立即 resolved 的 Promise 对象)。

(4)返回值是 Promise。

async函数的返回值是 Promise 对象,这比 Generator 函数的返回值是 Iterator 对象方便多了。你可以用then方法指定下一步的操作。

进一步说,async函数完全可以看作多个异步操作,包装成的一个 Promise 对象,而await命令就是内部then命令的语法糖。

神视频

loupe

Promise

异步习题

为什么最后打印a end ? await会一直阻塞下去,直到线程中所有代码执行完毕?!


async function a() {
  console.log('a start');
  let c = await b();
  console.log('a end');
}

async function b() {
  console.log('b start');
  return 12;
}
async function c() {
  console.log('c start');
  let c = await d();
  console.log('c end');
}

async function d() {
  console.log('d start');
  return 12;
}
// a start
// b start
// c start
// d start
// script start
// promies1
// script end
// promise2
// promise3
// promise4
// a end
// c end
// timeout

a(); 
c();
setTimeout(function () {
  console.log('tiemout');
}, 0);
console.log('script start');
new Promise(function (resolve) {
  console.log('promise1');
  resolve();
}).then(function () {
  console.log('promise2');
  new Promise(function (resolve) {
    console.log('promise3');
    resolve();
  }).then(function () {
    console.log('promise4');
  });
});

console.log('script end');

Next →
Copyright © 2018-2019 Shiyong Yin