Git Product home page Git Product logo

learnnotes's Introduction

learnnotes's People

Contributors

liujinhuan avatar

Watchers

James Cloos avatar  avatar

learnnotes's Issues

AMD、CMD、CommonJS、ES6模块化

概述

  1. AMD、CMD、CommonJS、ES6模块化都用于模块化的定义中
  2. AMD、CMD、ES6用于浏览器中,CommonJS用于Node端

AMD

  1. AMD是ES5中异步模块的规范、实现该规范的是RequireJS
  2. 依赖前置、异步定义
<!-- 依赖的模块,提前定义引用;在异步回调中使用依赖 -->
define(['/package/lib'],function(lib){
    function foo(){
        lib.log("foo")
    }
    return {
        foo
    }
})

CMD

  1. CMD是ES5中同步模块的规范、实现该规范的是SeaJS
  2. 依赖就近、同步定义
define(function(require,exports,module){
    <!-- 用到依赖的时候再引用;同步使用 -->
    var $ = require('jquery')
    $('#div').html("hello world")
})

CommonJS

  1. CommonJS是ES5中node端的模块化规范、通过module.exports定义
  2. 两种导出方式:默认输出module export和带有名字的输出exports.XXX
exports.hello = function(){
    console.log("hello")
}

exports default function (){
    console.log("hello")
}

ES6特性

  1. ES6特性,通过export/import对模块进行导出导入的
export default {
    data:{

    },
    mouted:function(){

    }
}

JavaScript专题

debounce防抖

解决事件的频繁触发,两种解决方案:debounce 防抖、throttle 节流

  • 防抖的原理就是:你尽管触发事件,但是我一定在事件触发 n 秒后才执行,如果你在一个事件触发的 n 秒内又触发了这个事件,那我就以新的事件的时间为准,n 秒后才执行,总之,就是要等你触发完事件 n 秒内不再触发事件,我才执行,

第一版本

function debounce(func, wait, immediate) {

    var timeout, result;

    var debounced = function () {
        var context = this;
        var args = arguments;

        if (timeout) clearTimeout(timeout);
        // 是否立即执行
        if (immediate) {
            // 如果已经执行过,不再执行
            var callNow = !timeout;
            timeout = setTimeout(function(){
                timeout = null;
            }, wait)
            // 返回值的情况、处理this、处理参数event
            if (callNow) {
                result = func.apply(context, args)
            }
        } else {
            timeout = setTimeout(function(){
                func.apply(context, args)
            }, wait);
        }
        return result;
    };
    // 取消
    debounced.cancel = function() {
        clearTimeout(timeout);
        timeout = null;
    };

    return debounced;
}

throttle 节流

  • 节流的原理很简单:

如果你持续触发事件,每隔一段时间,只执行一次事件。
根据首次是否执行以及结束后是否执行,效果有所不同,实现的方式也有所不同。
我们用 leading 代表首次是否执行,trailing 代表结束后是否再执行一次。

  • 关于节流的实现,有两种主流的实现方式,一种是使用时间戳,一种是设置定时器。
// 使用时间戳
function throttle(func, wait) {
    var context,args;
    var previous = 0;
    return function(){
        var now = +Date()
        context = this;
        args = arguments
        if(now-previous>wait){
            func.apply(context,arg)
            previous = now
        }
    }
}
// 使用定时器
function throttle(func, wait) {
    var context,args,timeout;
    return function(){
        context = this;
        args = arguments
        if(!timeout){
            timeout = setTimeout(function(){
                timeout = null
                func.apply(context,arg)
            },wait)
        }
    }
}

所以比较两个方法:

第一种事件会立刻执行,第二种事件会在 n 秒后第一次执行
第一种事件停止触发后没有办法再执行事件,第二种事件停止触发后依然会再执行一次事件

双剑合璧

// leading:false 表示禁用第一次执行
// trailing: false 表示禁用停止触发的回调
// 二者不可同时设置
function throttle(func, wait, options) {
    var timeout, context, args, result;
    var previous = 0;
    if (!options) options = {};

    var later = function() {
        previous = options.leading === false ? 0 : new Date().getTime();
        timeout = null;
        func.apply(context, args);
        if (!timeout) context = args = null;
    };

    var throttled = function() {
        var now = new Date().getTime();
        // 禁用第一次的话,上一个的时间就设置为此时
        if (!previous && options.leading === false) previous = now;
        // 下次触发 func 剩余的时间
        var remaining = wait - (now - previous);
        context = this;
        args = arguments;
        // 如果没有剩余的时间了或者你改了系统时间
        if (remaining <= 0 || remaining > wait) {
            // 清空定时器
            if (timeout) {
                clearTimeout(timeout);
                timeout = null;
            }
            // 上一个的时间就设置为此时
            previous = now;
            // 立即执行
            func.apply(context, args);
            if (!timeout) context = args = null;
        } else if (!timeout && options.trailing !== false) {// 禁用停止触发的回调
            timeout = setTimeout(later, remaining);
        }
    };
    throttled.cancel = function() {
        clearTimeout(timeout);
        previous = 0;
        timeout = null;
    }
    return throttled;
}

数组去重

// array:表示要去重的数组,必填
// isSorted:表示函数传入的数组是否已排过序,如果为 true,将会采用更快的方法进行去重
// iteratee:传入一个函数,可以对每个元素进行重新的计算,然后根据处理的结果进行去重
var array3 = [1, 1, 'a', 'A', 2, 2];

// 第二版
// iteratee 英文释义:迭代 重复
function unique(array, isSorted, iteratee) {
    var res = [];
    var seen = [];

    for (var i = 0, len = array.length; i < len; i++) {
        var value = array[i];
        var computed = iteratee ? iteratee(value, i, array) : value;
        if (isSorted) {
            if (!i || seen !== computed) {
                res.push(value)
            }
            seen = computed;
        }
        else if (iteratee) {
            if (seen.indexOf(computed) === -1) {
                seen.push(computed);
                res.push(value);
            }
        }
        else if (res.indexOf(value) === -1) {
            res.push(value);
        }        
    }
    return res;
}

console.log(unique(array3, false, function(item){
    return typeof item == 'string' ? item.toLowerCase() : item
})); // [1, "a", 2]

类型判断

  • typeof

    • 在 ES6 前,JavaScript 共六种数据类型,分别是:Undefined、Null、Boolean、Number、String、Object
    • typeof 对这些数据类型的值进行操作,结果分别是:undefined、object、boolean、number、string、object
    • Null 和 Object 类型都返回了 object 字符串。
    • 但是 typeof 却能检测出函数类型。
    • 但是 Object 下还有很多细分的类型呐,如 Array、Function、Date、RegExp、Error ,所以有没有更好的方法呢?
    • 是的,当然有!这就是 Object.prototype.toString!
  • Object.prototype.toString!可以识别至少 14 种类型

  • 写一个 type 函数能检测各种类型的值,如果是基本类型,就使用 typeof,引用类型就使用 toString。此外鉴于 typeof 的结果是小写,我也希望所有的结果都是小写。

// 第二版
var class2type = {};

// 生成class2type映射
"Boolean Number String Function Array Date RegExp Object Error".split(" ").map(function(item, index) {
    class2type["[object " + item + "]"] = item.toLowerCase();
})

function type(obj) {
    // 一箭双雕
    if (obj == null) {
        return obj + "";
    }
    return typeof obj === "object" || typeof obj === "function" ?
        class2type[Object.prototype.toString.call(obj)] || "object" :
        typeof obj;
}

深浅拷贝

  • 复制引用的拷贝方法称之为浅拷贝,与之对应的就是深拷贝,深拷贝就是指完全的拷贝一个对象,即使嵌套了对象,两者也相互分离,修改一个对象的属性,也不会影响另一个
  • concat 和 slice 是一种浅拷贝
  • JSON.parse( JSON.stringify(arr) )可以实现数组的深拷贝,但是不能拷贝函数
  • 如何实现一个对象或者数组的浅拷贝
var shallowCopy = function(obj) {
    // 只拷贝对象
    if (typeof obj !== 'object') return;
    // 根据obj的类型判断是新建一个数组还是对象
    var newObj = obj instanceof Array ? [] : {};
    // 遍历obj,并且判断是obj的属性才拷贝
    for (var key in obj) {
        if (obj.hasOwnProperty(key)) {
            newObj[key] = obj[key];
        }
    }
    return newObj;
}
  • 如何实现一个深拷贝呢?我们在拷贝的时候判断一下属性值的类型,如果是对象,我们递归调用深拷贝函数不就好了~
var deepCopy = function(obj) {
    if (typeof obj !== 'object') return;
    var newObj = obj instanceof Array ? [] : {};
    for (var key in obj) {
        if (obj.hasOwnProperty(key)) {
            newObj[key] = typeof obj[key] === 'object' ? deepCopy(obj[key]) : obj[key];
        }
    }
    return newObj;
}

npm发布私有仓库

起因

最近面试的时候有被问过:你对npm了解多少?有发布过包吗? 当时我表示一脸懵逼、其实是有参与过npm包的代码维护,但未曾自己发布过包。。趁着热乎劲儿,在网上找下资料,简单的记录下吧

简介

主要从注册账号、到编写包代码、到发布、到删除的一系列操作吧

流程

  • 安装verdaccio
sudo npm install verdaccio -g
  • 安装完成后,命令行直接输入verdaccio命令即可运行

执行verdaccio

  • 这时候浏览器打开http://localhost:4873,如果未发布过包,则会见到如下所示的图

未发布包的服务

  • 将当前npm指向本地
npm set registry http://localhost:4873
  • 注册用户,按照提示输入userName 和 password 和 email,输入后就注册完成,一般注册完成后也算登录成功
npm adduser –registry http://localhost:4873
  • 接下来就是编写包内容
// 创建测试文件夹
mkdir npmtest
// 初始化项目,一路回车即可
npm init 
// 创建index.js文件,内容如下
!function(){
    console.log(`这是引入的包入口`)
}()
  • 准备好上述包内容之后,就是发布包了,发布成功就如下图所示
// 发布
npm publish
// 期间可能会遇到提示未登录的错误信息,重新登录下即可,输入userName 和 password 和 email
npm login –registry http://localhost:4873

发布成功

发布成功后服务器中显示的包

  • 如何使用呢?编写测试文件
// 创建测试目录
mkdir test
// 初始化项目,一路回车
npm init
// 安装我们自己的包依赖,可以在package.json文件中看到
npm install npmtest@1.0.0 --save-dev
// 编写测试文件index.js,内容如下
var f = require('npmtest')
// 执行测试文件,结果如下图所示就OK了
node index.js

测试成功

  • 至此一个包就发布成功啦。。。

参考

如何搭建一个私有 npm 服务器

一分钟教你发布npm包

游戏官网性能优化

常见的性能优化

  • 图片压缩
  • cdn资源
  • 代码压缩
  • 按需加载(这次的重点)

先来分析下

  1. 项目中慢的原因是什么?
  • webpack打包会将所有代码打包到一个bundle,然而随着项目额逐渐扩大,文件数量将急剧增加,不经意间使得打包文件过大而造成应用加载的缓慢。
  1. 解决的目标是什么?
  • 能否按需加载
  1. 采用的办法是什么?
  • Code Splitting(提倡的是将代码分块chunk,通过定义一些分割点来实现分块,从而实现按需加载。)

思考的过程中产生的几点疑问

1. 分析产生`慢`的原因
2. 知道为什么`慢`,但是如何解决呢?
3. 知道了解决办法,可是为什么这么做就能实现按需加载呢?

带着以上的几点疑问,我想要更深入的了解以下几个点

1. ES6的import()函数为什么可以实现动态导入
2. ES6的模块加载机制
3. webpack模块化原理
<!-- 甚至还要了解更多相关的信息 -->

解决疑问

  • 主要参考的是es6官网、webpack官网、react官网等;

  • 针对上述的问题1,可以参考另一篇《ECMAScript 6 入门》学习笔记

    • 对比
    引擎处理时机 参数 加载方式 说明
    import语句 编译时 模块位置 静态加载 利于编译器提高效率、但不能条件加载
    import()函数 运行时 模块位置 动态加载 可以运行时、条件加载
    • import()返回一个 Promise 对象
    • import()函数可以用在任何地方,什么时候运行到这一句,就会加载指定的模块
    • 适用场合
      1. 按需加载。import()可以在需要的时候,再加载某个模块。
      2. 条件加载。import()可以放在if代码块,根据不同的情况,加载不同的模块。
      3. 动态的模块路径。import()允许模块路径动态生成。
  • 针对上述的问题2,可以参考另一篇《ECMAScript 6 入门》学习笔记

  • 问题3还在学习中[囧]

最后附上实现方案

  • 依赖的有react-router、webpack、ES6的import()、webpack打包分析插件webpack-bundle-analyzer等
  • Bundle.js
import React from 'react';

export default class Bundle extends React.Component {
    state = {
      mod: null
    }
    componentWillMount() {
      console.log("Bundle---,",this.props)
      this.load(this.props);
    }
    componentWillReceiveProps(nextProps) {
      if (nextProps.load !== this.props.load) {
        this.load(nextProps);
      }
    }
    // 更改 load 方法为异步函数
    async load(props) {
      this.setState({
        mod: null
      });
      /*
        使用 props.load() 返回的是一个 promise
        */
      const mod = await props.load();

      this.setState({
        mod: mod.default ? mod.default : mod
      });
    }

    render() {
      return this.state.mod ? this.props.children(this.state.mod) : null;
    }
}

  • lazyLoad.js
import React from 'react';
import Bundle from './Bundle';

// 默认加载组件,可以直接返回 null
const Loading = () => <div>Loading...</div>;

/*
    包装方法,第一次调用后会返回一个组件(函数式组件)
    由于要将其作为路由下的组件,所以需要将 props 传入
*/
const lazyLoad = loadComponent => props => (
  <Bundle load={loadComponent}>
    {Comp => (Comp ? <Comp {...props} /> : <Loading />)}
  </Bundle>
);

export default lazyLoad;

  • 使用router配置的入口文件
import React from 'react'
import { Route } from 'react-router-dom'
import lazyLoad from '../lazyLoad';
<!--静态加载方式-->
// import GameNetwork from '../containers/gameNetwork'
<!--动态加载方式-->
const GameNetwork = lazyLoad(() => import('../containers/gameNetwork'));
<!--N多其他路由定义-->

export default class Routes extends React.Component {
  render() {
    let routes = (
        <div className="view">
            <!--N多其他路由配置-->
            <Route path="/gameNetwork.html" component={GameNetwork}/>
        </div>
    )
    return routes
  }
}

  • webpack配置
<!-- 省略了详细配置 -->
module.exports = {
  entry: [
    './src/index.js'
  ],
  output: {
    path: resolve('output'),
    filename: 'js/[name].[chunkhash:5].js' ,
    publicPath: '',
    chunkFilename: 'js/[name].[chunkhash:5].chunk.js'
  },
}

module.exports.plugins.push(
    // webpack打包分析图、需要的时候可以打开注释
    new BundleAnalyzerPlugin({ analyzerPort: 8919 })
)

优化后的效果

  • 分包之前:main.js中包含的是所有的js文件、而优化后则只包含了当前路由需要的js文件、
  • 分包之后:main从原来的一个1.8M文件变成了90多K的main和84k的chunk

优化前
优化后

参考文件

webpack代码分离

react code-splitting

ES6 import()函数

webpack 模块方法

有赞 webpack模块化原理-commonjs

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.