VueJS 之 “组件篇“(二)

| 全局、局部组件
| 数据传递(props、组件通信、slot)
| props、sync双向绑定、once单次绑定
| 组件之间通信,$dispatch() 派发事件、 $broadcast() 广播事件,事件向下传导给所有后代
| slot 内容分发
| 组件是Vue的最强大功能之一,组件可以扩展html元素,封装可复用代码

全局组件

全局组件在任何组件内都可以调用,无需引用或通过component加载

main.js

    // 定义一个全局的组件
    var myComponent = Vue.extend({
        template: '<div> 组件已经渲染出来 </div>'
    })

    // 全局注册
    Vue.component('crm-component', myComponent);

    let vm = new Vue({
        ...
    }}


main.vue 子组件

    <templte>
        <div class="welcome">
            <h1>视图列表页面</h1>
            <crm-component></crm-component>            <!-- 调用 -->
        </div>
    </template>

局部组件

必须使用components对象来引用组件

<div id="appA">
    <User></User>
</div>

<script>
    import User import './user';

    var vmA = new Vue({
        el: "#appA",
        components: {        // 局部的写法
            User
        }
    })
</script>

————— 父与子组件之间的数据传递 —————

props

父组件将数据传给子组件通过props,子组件通过自定义事件$on、$emit来挂参数传递给父组件

一、props

    <div id="app">
        <!-- 这里的两个属性值通过props传到组件中 -->
        <component-parent my-name="siguang" my-age='33'></component-parent>
    </div>

    <script>
        var componentCrm = Vue.extend({
            props: ['myName', 'myAge'],
            template: '<h2>{{ myName }} {{ myAge }}</h2>'
        })

        var vm = new Vue({
            el: '#app',
            components: {
                'component-parent': componentCrm
            }
        })
    </script>

    注意: my-name="siguang" 自定义属性以“-”分割

         props: ['myName', 'myAge']        // props 定义的必须以驼峰形势


二、props动态值

    parent.vue:

        <div id="app">
            <child-component :user-name="uname"></child-component>
        </div>

        <script>
            import childComponent from 'childComponent.vue';

            export default{
                data(): {
                    return{
                        uname: 'siguang'
                    }
                },
                components:{
                    childComponent
                }
            }
        </script>


    childComponent.vue:

        <div>
            {{ userName }}        <!-- siguang -->
        </div>

        <script>
            export default{
                propos: ['userName'],
            }
        </script>


三、once 将渲染的结果缓存

    不过当组件中包含大量静态内容时,可以考虑使用 v-once 将渲染结果缓存起来

    <div id="app">
        <component-parent></component-parent>
    </div>

    <script>

        var childrenComponent = Vue.extend({
            template: '<div v-once>'+
                '<h3>这里是子组件的内容: {{ myMsg }}</3>'+
                '<p>这里输入不会影响父组件: <input type="text" v-model="myMsg" /></p>'+
                '</div>',
            data: function(){
                return {
                    myMsg: ''
                }
            },
            props: ['myMsg']
        })

        var parentComponent = Vue.extend({
            template: '<div v-once>'+
                '<p><input text="text" v-model="msg"></p>'+
                '<p>父组件的值 {{ msg }}</p>'+
                '</div>'+
                '<childen-component v-bind:my-msg.once="msg"></childen-component>',
            data: function(){
                return {
                    msg: '这里值只传给子组件一次'
                }
            },
            components: {
                'childen-component': childrenComponent
            }
        })

        var vm = new Vue({
            el: '#app',
            components: {
                'component-parent': parentComponent
            }
        })
    </script>

组件之间通信

props是单向数据流父向子组件传递数据,子向父组件传递可以通过自定义事件来处理

$on(eventName) 监听事件    、$emit(eventName) 触发事件

一、子向父组件发消息

    parent.vue: 

        <template>
            <div class="login">
                <div class="parent-box">
                    <p>显示子组件数据: {{ childrenText }}</p>
                </div>
                <children-component ref="childrenRef" v-on:showChildrenVal="childrenVal"></children-component>
            </div>
        </template>

        <script>
            import ChildrenComponent from './children.vue'
            export default{
                data(){
                    return {
                        childrenText: ''
                    }
                },
                methods:{
                    childrenVal(val){
                        this.childrenText = val;
                    }
                },
                components:{
                    ChildrenComponent
                }
            }
        </script>

    children.vue:

        <template>
            <div class="children" style="padding-top: 50px; border-top: 1px #ccc solid">
                <p><input type="text" v-model="childrenInp" id=""></p>
                <p><input type="button" @click="toParentData" value="提交到父组件中"></p>
            </div>
        </template>

        <script>
            export default{
                data(){
                    return {
                        childrenInp: ''
                    }
                },
                methods:{
                    toParentData(){
                        this.$emit("showChildrenVal", this.childrenInp);
                    }
                }
            }
        </script>


二、父向子发消息

    parent.vue:

        <template>
            <div class="login">
                <div class="parent-box">
                    <p><input type="text" name="" v-model="inputParent" ><br></p>
                    <p><input type="button" value="值传给父组件" @click="sendChildren"><br></p>
                    <p>显示子组件数据: {{ childrenText }}</p>
                </div>

                <children-component ref="childrenRef"></children-component>
            </div>
        </template>

        <script>
            import ChildrenComponent from './children.vue'
            export default{
                data(){
                    return {
                        inputParent: '',
                        childrenText: ''
                    }
                },
                methods:{
                    sendChildren(){
                        this.$refs.childrenRef.$emit('showText', this.inputParent);        // 也可以用props
                    }
                },
                components:{
                    ChildrenComponent
                }
            }
        </script>


    children.vue:

        <template>
            <div class="children" style="padding-top: 50px; border-top: 1px #ccc solid">
                这里是父组件传递的值: {{transmitVal}}
            </div>
        </template>

        <script>
            export default{
                created(){
                    this.$on('showText', function(val){
                        this.transmitVal = val;
                    })
                },
                data(){
                    return {
                        transmitVal: ''
                    }
                }
            }
        </script>


三、v-ref 直接访问到组件

    <div id="app">
        <span ref="msg"> hello </span>
        <span ref="other-msg"> world </span>
    </div>

    <script>
        var vm = new Vue({
            el: "#app",
            data: {
                someProp: 'idName',
                otherProp: 'prop'
            }
        })

        console.log(vm.$refs.msg.textContent);        // hello
        console.log(vm.$refs.otherMsg.textContent);    // world
    </script>

slot 分发内容

parent.vue:
    <template>
        <div class="login">
            <children-component>
                <h1 slot="header">这里可能是一个页面标题</h1>
                <div class="tag">
                    这里是没有定义slot名称走的默认的slot
                    <div class="tag-til">标题</div>
                    <div class="tag-content">内容部分</div>
                </div>
            </children-component>
        </div>
    </template>

children.vue:
    <template>
        <div class="children">
            <slot name="header"></slot>
            <slot></slot>
        </div>
    </template>

组件化的css

可以通过scoped属性来控制样式是否是只在当前组件下使用

<style>
    /* 全局下的样式 */
</style>

<style scoped>
    /* 当前组件下使用的样式 */
</style>

VueJS 之 “基础篇“(一)

| style与class
| computed、directive、filter
| watch 侦听Data数据的变化
| 生命周期: beforeCreate、create、beforeMount、mounted、beforeUpdate、updated、destroyed
| this.$refs、$el、$data、$watch
| v-bind缩写:、v-on缩写@

Vue2.0

一、Vue的MVVM实现的原理

    ViewModel是Vue.js的核心,Vue实例是作用于某一个HTML元素上的,这个元素可以是HTML的body元素,也可以是指定了id的某个元素

    DOM Listeners 和 Data Bindings看作两个工具,它们是实现双向绑定的关键。

    从view层来看,ViewModel中的DOM Listeners工具会帮我们监测页面上DOM元素的变化,如果有变化,则更改Model中的数据;

    从Model层来看,当我们更新Model中的数据时,Data Bindings工具会帮我们更新页面中的DOM元素。


二、安装

    $ npm i vue --save-dev

    $ npm i vue-cli 脚手架

生命周期

一、构造器

    1、每个构造器都是通过创建一个Vue的实例启动的

        var vm = new Vue({
            // ...    
        })

    2、扩展构造器

        通过扩展构造器可以创建可复用的组件构造器

        var MyComponent = Vue.extend({
            // 扩展选项
        })


二、生命周期

    1、beforeCreate(): 实例初始化,数据观测(data observer)和事件(event/watcher)配置之前被调用

    2、created(): 实例创建完后被调用,完成了数据观测(data observer)和事件(event/watcher)回调,但还挂载还没开始$el属性不可见

    3、beforeMount(): 在挂载开始之前调用,render()函数被调用

    4、mounted(): el被创建的vm.$el替换,挂载到实例上调用钩子

    5、beforeUpdate(): 数据更新时调用,在虚拟DOM重新渲染

    6、updated(): 数据更改导致虚拟DOM重新渲染

    7、destroyed(): 卸载组件

数据绑定

一、文本绑定:  <p>{{ data.name }}</p>

二、html绑定:  <p v-html="data"></p>

三、绑定属性的值 

    <div id="item-{{id}}"></div>

    <div :id="userId"></div>

四、表达式:  {{ dat.num == 1 }}、 {{ num ? 'yes' : 'no' }}、 {{if(ok) {return message} }}

五、过滤器:  {{ message | capitalize }}

    连续过滤器:  {{ message | filterA | filterB }}

常用指令

指令: 以 v- 开头

    <div v-if="greeting == 1"></div>

    带参数: <a v-bind:href="url"></a>

一、v-if、v-else-if、v-else条件渲染:

    <div v-if="type === 'A'">A</div>
    <div v-else-if="type === 'B'">B</div>
    <div v-else>Not A/B/C</div>

二、v-show: 显示还是隐藏元素,用的display

三、v-for 循环

    $index: 索引        $key: 

    * 数组
        <li v-for="item in items" :key="item">{{ item.message }}</li>

    * 数组对象
        <li v-for="(val, index) in objList" :key="index">
            {{index}}. {{key}} : {{val.type}}
        </li>

        ** 注意:key,如果key没有改变不会重新渲染组件,问题在于子组件中存在于绑定

    * filterBy()、orderBy()过滤器

四、v-model: 绑定值,这也是MVVM的关键点

    可以对文本表单、单选框 、多选框、下拉菜单进行绑定值

        1、lazy: 不是输入时就进行同步而是在change的时候才对数据进行同步

            <input type="text" v-model="msg" lazy /> {{msg}}

        2、number: 将用户输入的转成Number型,如果返回NaN那就返回原值

        3、debounce: 设置一个最小延时,否则如果输入是ajax请求,每次敲击都会去请求

            <input type="text" debounce="500" v-model="msg">        // 按完键500毫秒后在进行

    获取checkbox值:

        <input type="checkbox" v-model="toggle" v-bind:true-value="a" v-bind:false-value="b">

        // 当选中时
        vm.toggle === vm.a

        // 当没有选中时
        vm.toggle === vm.b

五、v-bind: 绑定到HTML元素上,v-bind:class="active",缩写 ":" <a :href='url'></a>

六、v-on: 监听DOM事件 v-on缩写: "@" <div @click="doSomeing"></div>

七、ref: 访问子组件

    <div ref="box">xxxx</div>
    <el-button type="primary" slot="append" @click="getRefs">发送</el-button>
    </div>

    {
        methods:{
            getRefs(){
                console.log(this.$refs.box.innerHTML);        // 获取 $refs
            }
        }
    }

    如果绑定一个元素使用 :ref='item'
    <p v-for="item in items" :ref="item"></p>

八、v-pre: 跳过这个元素和它的子元素的编译过程,这样加快了编译的速度

    <div v-pre>{{ 这里不用框架来编译 }}</div>

九、v-cloak:

十、v-once: 只渲染元素和组件一次,之后的渲染都会跳过次元素

    <span v-once>xxxxx</span>

过滤器

过滤器,对绑定值进行处理

一、自定义过滤器

    在一个组件中定义过滤器:
        <span v-text="message | reverse 'addText' "></span>
        export default {
            filters: {
                capitalize: function (value) {
                    value = value.toString();
                    return value.charAt(0).toUpperCase() + value.slice(1)
                }
            }
        }

    定义全局过滤器:
        filters.js
        Vue.filter('datetime', function (value, format) {
            if (!value) {
                return 
            }
            return moment(value).format(format || 'YYYY-MM-DD HH:mm:ss');
        });

        main.js
        import './filters.js'        // 引用


二、内置过滤器

    1、uppercase: 字母转成大写

    2、lowercase: 字母转成小写

    3、capitalize: 首字母转成大写

    4、filterBy: 过滤内容

    5、limitBy: 过滤数据从开始到指定位置结束的内容

    6、orderBy: 过滤排序

    7、currency: 货币过滤

    8、debounce: 延迟过滤


三、双向过滤器

    模型的值显示在视图之前转换它

    <input v-mode="money | formatMoney">
    <div>{{ money | formatMoney }}</div>

    Vue.filter('formatMoney', {

        // model -> vlew过程  在更新<input> 元素之初化值
        read: function(val){
            return '$' + val.toFixed(2);
        },

        // vlew -> model过程 在写回数据之前格式化值
        write: function(val){
            var number = +val.replace(/[^\d.]/g, '');
            return isNaN(number) ? 0 : parseFloat(number.toFixed(2));
        }
    })


四、动态参数

    参数用空格格开
    <input type="text" v-model="userInput">
    <span>{{msg | concat userInput}}</span>

    Vue.filter('concat', function (value, input) {
        // `input` === `this.userInput`
        return value + input;
    })


五、filterBy过滤器

    <div id="app">
        <div>过滤数据里包含 蛋糕 字符 </div>
        <div class="box">
            <ul>
                <li v-for="user in users | filterBy '蛋糕' ">{{ user.name }}</li>
            </ul>
        </div>

        <div style="margin-top: 30px" >过滤出输入的字符</div>
        <input type="text" name="" v-model="searchKey" />
        <div class="box">
            <ul>
                <li v-for="user in users | filterBy searchKey in 'name'">{{ user.name }}</li>
            </ul>
        </div>
    </div>

    <script src="../../js/vue.js"></script>
    <script type="text/javascript">
        var vm = new Vue({
            el: '#app',
            data: {
                searchKey: '',
                users:[
                    {
                        name: '外卖',
                        tag: 1
                    },
                    {
                        name: '鲜花',
                        tag: 5
                    },
                    {
                        name: '蛋糕',
                        tag: 4
                    },
                    {
                        name: '水果',
                        tag: 2
                    },
                    {
                        name: '茶点',
                        tag: 3
                    }
                ]
            }
        })
    </script>


六、orderBy排序

    <div id="app">
        <input type="text" name="" v-model="searchKey" />
        <div class="box">
            <ul>
                <li v-for="user in users | orderBy 'tag'">{{ user.name }}</li>
            </ul>
        </div>
    </div>

    <script type="text/javascript">
        var vm = new Vue({
            el: '#app',
            data: {
                searchKey: '',
                users:[
                    {
                        name: '外卖',
                        tag: 1
                    },
                    {
                        name: '咖啡',
                        tag: 5
                    },
                    {
                        name: '餐厅订座',
                        tag: 4
                    },
                    {
                        name: '蛋糕',
                        tag: 2
                    },
                    {
                        name: '票务',
                        tag: 3
                    }
                ]
            }
        })
    </script>

指令

一、钩子函数

    el:指令所绑定的元素,可以用来直接操作 DOM 。
    binding:一个对象,包含以下属性:
    name:指令名,不包括 v- 前缀。
    value:指令的绑定值,例如:v-my-directive="1 + 1" 中,绑定值为 2。
    oldValue:指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用。无论值是否改变都可用。
    expression:字符串形式的指令表达式。例如 v-my-directive="1 + 1" 中,表达式为 "1 + 1"。
    arg:传给指令的参数,可选。例如 v-my-directive:foo 中,参数为 "foo"。
    modifiers:一个包含修饰符的对象。例如:v-my-directive.foo.bar 中,修饰符对象为 { foo: true, bar: true }。
    vnode:Vue 编译生成的虚拟节点。移步 VNode API 来了解更多详情。
    oldVnode:上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用。

二、对象字面量

    <div v-demoA="{ color: 'white', text: 'hello'}"></div>

    Vue.directive('demoA', function(el, value){
        console.log(value.color);
        console.log(value.text);
    })

三、元素指令,相当于angular的E指令

    Vue.elementDirective('my-directive', {
        bind: function(){
            // 操作this.el
        }
    })

    <my-directive></my-directive>            // 不能这么写<div v-my-directive></div>

四、高级选项

    params: 自动提取绑定元素的这些特性.

    <div v-example a="hi"></div>
    Vue.directive('example', {
        params: ['a'],
        bind: function () {
            console.log(this.params.a);         // -> "hi"
        }
    })

computed 计算属性

计算属性当依赖属性发生变化时,属性的值会自动更新,相关的DOM也会同步更新

一、计算属性的getter

    <div id="app">
        <p>user_inof={{ userInfo }}</p>
    </div>

    <script>
        var vm = new Vue({
            el: '#app',
            data: {
                "user_name": "lulu",
                "user_age": "20"
            },
            computed: {
                // 一个计算属性getter
                userInfo: function(){
                    return '姓名: '+ this.user_name +' 年龄: '+ this.user_age;
                }
            }
        })
    </script>

二、计算属性的setter

    var vm = new Vue({
        el: '#app',
        data: {
            "user_name": "lulu",
            "user_age": "20"
        },
        computed: {
            userInfo: function(){
                get: function(){
                    return '姓名: '+ this.user_name +' 年龄: '+ this.user_age;
                },
                set: function(newValue){        // 这里当
                    this.userInfo = newValue;
                }
            }
        }
    })

watch 侦听器

watch 侦听data下指定数据的变化 

watch:{
    message: function(newValue){
        return newValue + 1;        // 如果message变化值加1
    }
}

// 写在实例化下侦听数据变化
// vm.$watch('message', function(newVal, oldVal){
//    console.log(newVal, oldVal);
//    this.message = newVal.replace(/s|g/g, '*');
// })

class和style的绑定

一、class

    // 对象
    <div :class="{ 'active': isActive }"></div>
    var vm = new Vue({
        el: '#app',
        data: {
            isActive: true
        }
    })

    // 数组
    <div :class="[activeClass, errorClass]"></div>        // 三元 <div v-bind:class="[isActive ? activeClass : '', errorClass]"></div>
    data: {
        activeClass: 'active',
        errorClass: 'text-danger'
    }    

二、style

    <div :style="[crm, hk]"> 或 <div :style="{color: activeColor, fontSize: fontSize+'px'}">

    var vm = new Vue({
        el: '#app',
        data: {
            activeColor: 'red',
            fontSize: 30,
            crm: {
                color: '#000',
                fontSize: '16px'
            },
            hk: {
                color: '#fff',
                fontSize: '18px'
            }
        }
    })

事件

一、@click

    <div @click="say"></div>
    <div @click="say('hi')"></div>
    <div @click="content + 1"></div>

    <!-- 阻止单击事件冒泡 -->
    <a v-on:click.stop="doThis"></a>

    <!-- 提交事件不再重载页面 -->
    <form v-on:submit.prevent="onSubmit"></form>

    <!-- 修饰符可以串联  -->
    <a v-on:click.stop.prevent="doThat"></a>

    <!-- 只有修饰符 -->
    <form v-on:submit.prevent></form>

    <!-- 添加事件侦听器时使用事件捕获模式 -->
    <div v-on:click.capture="doThis">...</div>

    <!-- 只当事件在该元素本身(而不是子元素)触发时触发回调 -->
    <div v-on:click.self="doThat">...</div>

二、按键别名

    .enter、.tab、.delete (捕获 “删除” 和 “退格” 键)、.esc、.space、.up、.down、.left、.right、.ctrl、.alt、.shift、.meta

三、once: 只处理一次点击  <a v-on:click.once="doThis"></a>

四、修饰符 <input v-on:keyup.13="submit">

模板语法

Vue在底层将模板编译成虚拟DOM渲染函数,也可以不用模板直接写render函数,可选JSX语法

常见问题

一、props传值子元素不会接收

    问题1: 封装tab标签来加载不同子组件,当同一组件重新被打开时,应先消毁之前的相同组件在加载新的组件,但在子组件中destroyed()来侦听消毁缺没有回调

     // 打开新页面
    openTabPage(tabPage, cb) {
        // 先关闭存在的同名的,再打开
        if (this.pages.some(item => item.name === tabPage.name)) {
            this.handleRemove(tabPage.name);
        }
        this.$nextTick(()=>{                // 使用$nextTick 进行重新渲染
            this.pages.push(tabPage);
            this.activeName = tabPage.name;
        })

        if (cb && typeof cb === 'function') {
            cb(this.activeName)
        }

        if (this.tabCreate) {
            this.tabCreate(tabPage)
        }
    },

    问题2: 这种加了一层会对相同子组件进行消毁在重建

        <template slot="tabcreate">
    <create-data-config ref="createDataConfig" :create-prop="createProp"></create-data-config>
  </template>

        openTab(tabName, row){
            // this.createProp['detailInfo'] = row || '';            这种写法子组件watch不到createProp的变化 

            this.createProp = {
                detailInfo: row || ''
            }
  }

        子组件
        watch:{
            createProp: function(){
                debugger;
            }
        }


二、v-bind 内联字符串连接

    data(){
        return {
            addString: '加入内容'
        }
    }

    1.x版本 写法  <div attr="xxxx{{addString}}">
    2.x版本 写法  <div v-bind="'xxxx'+ addString">


三、checkbox动态创建绑定

    // v-model="item.check" 绑定的值要相同
    <p v-for="item in checkList">
        <input type="checkbox" name="cb" v-model="item.check" /> {{item.name}}
    </p>

    data(){
        return{
            checkList:[
                {check: false, name: 'aa'},
                {check: false, name: 'bb'},
                {check: false, name: 'cc'}
            ]
        }
    }


四、vue使用jxs语法

    new Vue({
        el: '#demo',
        render (h) {
            return (    // 使用这种jsx语法
                <AnchoredHeading level={1}>
                    <span>Hello</span> world!
                </AnchoredHeading>
            )
        }
    })

    安装插件
    $ npm install babel-plugin-syntax-jsx babel-plugin-transform-vue-jsx babel-helper-vue-jsx-merge-props babel-preset-en   --save-dev

    .babelrc:
        {
            "presets": ["env"],
            "plugins": ["transform-vue-jsx"]
        }

    https://github.com/vuejs/babel-plugin-transform-vue-jsx


五、vue键盘事件不起作用

    @keyup.enter.native="login"   // 如果不加.native是不起作用有


六、$nextTick 页面某一块数据渲染完成后在执行其它操作

    queryBindBank(){
        let that = this;

        common.ajax({
            url: '/business/web/v1/paytool/payCardList',
            method: 'post',
            data: {},
            dataType: 'json',
            success: function(res) {
                that.showLoading = false;
                if (res && res.data) {

                    // 渲染数据表
                    that.bindBankData = res.data.list;

                    // 需要数据表渲染完后在执行其它操作
                    that.$nextTick(function(){
                        cardList.forEach(function(item, idx, arr){                    
                            if(item.designAbled){
                                that.$refs.multipleTable.toggleRowSelection(item);
                            }
                        })
                    })

                    that.bindBankData.forEach((bank, idx, arr) => {
                        if(bank.designAbled){
                            that.selectedRadio = bank.bankCard;
                        }
                    })
                }
      }
        });
    }

| http://www.jianshu.com/p/95b2caf7e0da // vue-cli
| http://cn.vuejs.org/guide/ // Vue中文官网
| https://github.com/vuejs/vue // github
| http://vuefe.cn/guide/installation.html // 2.0
| http://router.vuejs.org/zh-cn/ // vue-router2.0
| https://github.com/vuejs // Vue组件列表
| http://www.cnblogs.com/dh-dh/p/5606596.html // binding原理,vue的数据
| https://github.com/vuejs/awesome-vue#libraries--plugins
| http://vuex.vuejs.org/zh-cn/ // Vuex 2.0文档
| https://github.com/vuejs/vuex/blob/1.0/docs/zh-cn/intro.md
| http://www.cnblogs.com/keepfool/category/845804.html
| http://www.jianshu.com/p/f8e21d87a572
| https://github.com/pablohpsilva/vuejs-component-style-guide/blob/master/README-CN.md#%E5%9F%BA%E4%BA%8E%E6%A8%A1%E5%9D%97%E5%BC%80%E5%8F%91 // Vue代码规范
| https://juejin.im/book/5a36661851882538e2259c0f/section/5a37bbb35188257d167a4d64 源码

HTTP详解

网络基础TCP/IP

一、TCP/IP分为4个层: 应用层、传输层、网络层、数据链路层

    应用层: 向用户提供应用服务FTP和DNS服务

    传输层: 两台计算机之间的数据传输,两种协议TCP和UDP

    网络层: 用来处理网络上的数据包

    链路层: 处理连接网络的硬件部分

IP、TCP和DNS

与HTTP关系的协议: 

    1、IP协议: 将把各种数据包传到指定位置,两种重要的条件就是IP地址和MAC地址

    2、TCP协议: 确保数据能到达目标,TCP协议采用了三次握手策略

    3、DNS服务: 负责将域名转换成IP地址之间的解析服务

URI和URL

URI: HTTP使用URI可以让客户端找到指定的资源 

URL: 服务器的

HTTP协议

HTTP超文本传输协议,是用于客户端和服务器端之间的通信,HTTP从客户端发起请求,最后服务器端响应请求并返回

一、请求方式的总类

    GET: 获取资源,不返回主体部分,GET方法要求服务器将URL定位的资源放在响应报文的数据部分,回送给客户端,向服务器请求通过 URL?id=100&user='siguang'来传递

    POST: 传输实体主体,客户端向服务器传输内容比较多时使用POST,

    PUT: 传输文件,象FTP的文件上传一样

    HEAD: 获取报文首部

    DELETE: 删除文件,与PUT相反

    OPTIONS: 用来查询针对请求资源的方法

    TRACE: 追踪路径

    CONNECT: 隧道协议连接代理

二、持久连接节省通信量 Kepp-alive

    每建立一次HTTP通信流程,建立一次TCP连接 -> HTTP请求 -> 服务器HTTP响应 -> 断开TCP连接

    持久连接也就是只要任意一端没断开,TCP连接状态就一直保持连接状态,这种好处就是减少TCP连接的重复建立和断开,增加的额外开销,减轻服务器端的负载

三、HTTP报头、报文

    客户端请求的HTTP报文叫请求报文,服务器端响应的叫响应报文

    报文分为: 报文首部 和 报文主体

四、Gzip压缩

    服务器将资源用zip压缩在发送给客户端,客户端接收后在进行解压缩

HTTP状态码

一、状态码由三位数字组成,第一个数字定义了响应的类别,共分五种类别:

    1xx:指示信息--表示请求已接收,继续处理

    2xx:成功--表示请求已被成功接收、理解、接受

    3xx:重定向--要完成请求必须进行更进一步的操作

    4xx:客户端错误--请求有语法错误或请求无法实现

    5xx:服务器端错误--服务器未能实现合法的请求


二、常见的状态码有如下几种:

    1xx:临时回应,表示客户端请继续

    200 OK 客户端请求成功

    301 Moved Permanently 请求永久重定向

    302 Moved Temporarily 请求临时重定向

    304 Not Modified 客户端已有本地缓存的版本

    400 Bad Request 由于客户端请求有语法错误,不能被服务器所理解

    401 Unauthorized 请求未经授权

    403 Forbidden 无权限

    404 Not Found 请求页面不存在

    500 Internal Server Error 服务端错误

    503 Service Unavailable 服务端暂时性错误,一会在再试

缓存Cache

缓存是指代理服务器或客户端本地磁盘内保存的资源副本,利用缓存减少对服务器的访问

一、缓存分类:          

    1、缓存服务器: 客户端请求资源先到缓存服务器查看是否到期,如果还在缓存期直接返回给客户端,否则去服务器取最新的资源

    2、客户端缓存: 浏览器将缓存资源存到磁盘的指定文件夹内

    3、数据库缓存: 

    4、CDN内容分发:

    另外两种客户端缓存: LocalStorage 和 SessionStroage

    LocalStorage: 在PC上的兼容性不太好,而且当网络速度快、协商缓存响应快时使用localStorage的速度比不上304并且不能缓存css文件而移动端由于网速慢,使用localStorage要快于304


二、缓存一般是GET请求,而POST一般不缓存,客户端缓存是否需要是在服务器端代码控制,那就是响应头,响应头告诉是否缓存

    注意,所有缓存如果强制刷新的话,所有的资源都会重新从服务器加载

# Expires: 缓存过期时间,用来指定资源到期的时间,Expires=max-age + 请求时间,需要和Last-modified结合使用但在上面我们提到过,cache-control的优先级更高 

# Cache-control: (单位 秒)指定设置缓存最大的有效时间,定义的是时间长短 
    Cache-control:max-age=2592000  缓存有效期为30天
    public        所有内容都将被缓存
    private        内容只缓存到私有缓存中
    no-cache    所有内容都不会被缓存
    no-store    绝对禁止缓存,一看就知道如果用了这个命令当然就是不会进行缓存啦~每次请求资源都要从服务器重新获取
    must-revalidation/proxy-revalidation    指定如果页面是过期的,则去服务器进行获取这个指令并不常用,就不做过多的讨论了
    max-age=xxx (xxx is numeric)    缓存的内容将在 xxx 秒后失效, 并如果和Last-Modified一起使用时, 优先级较高

# Last-Modified: 服务器端文件的最后修改时间,需要和cache-control共同使用,是检查服务器端资源是否更新的一种方式,当浏览器再次进行请求时,会向服务器传送If-Modified-Since报头,询问Last-Modified时间点之后资源是否被修改过如果没有修改,则返回码为304,使用缓存;如果修改过,则再次去服务器请求资源,返回码和首次请求相同为200,资源为服务器最新资源

# ETag: web服务器响应请求时,告诉浏览器当前资源在服务器的唯一标识(生成规则由服务器决定),生成算法的话,我测试etag效果的时候用的是MD5值,Apache可以配置对静态文件生成Etag

请求头 Request Header

HTTP协议的请求和响应报文中包含的HTTP首部

一、HTTP报文首部包括

    报文首部(客户端和服务器处理时需要的信息)、报文主体(资源信息)


二、HTTP通用头 General

    # Request URL: http://mjdcom/        请求的URL

    # Request Method: GET                 请求类型

    # Status Code: 200 OK                 请求状态码

    # Remote Address: 36110181152:80    服务器地址及端口号


三、请求头 Request Headers

    # Accept: 浏览器接收的格式,文本 text/html、图片 images/jpeg、视频 video/mp4、二进制 application/octet-stream

            Accept: text/html,application/xhtml+xml,application/xml;q=09,image/webp,*/*;q=08

    # Accept-Charset: 优先的字符集

    # Accept-Encoding: 浏览器接收的编码方式  Accept-Encoding:gzip, deflate, sdch

    # Accept-Language: 接收的语言  Accept-Language:zh-CN,zh;q=08

    # Host: HTTP访问的域名 Host:mjdcom

    # Cache-Control: 控制缓存的时效性 max-age=315360000、no-cache、max-age、

    # Connection: 连接方式,如果是keep-alive,则会复用连接

    # If-Modified-Since: 上次访问时的更改时间,如果服务端认为此时间没有更新,则会给出304响应

    # If-None-Match: 比较实体标记(与If-Match相反),如果与Etag不同相将资源更新给客户端
            If-None-Match:"57724c86-1232"

    # If-Match: If-xxx 条件请求,客户端的if-match值与服务器的Etag值相匹配,如果相同就返回

            If-Match: "57724c86-1232"、 ETag: "57724c86-1232"

    # User-Agent: 将浏览器和代理用户的信息传给服务器

            User-Agent:Mozilla/50 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/53736 (KHTML, like Gecko) Chrome/490262387 Safari/53736

    # If-Range: 如果If-Range与Etag相同,就作用范围请求处理

    # Range: 实体字节请求范围

    # Referer: http://mjdcom/ 告知服务器请求资源的原URI

响应头 Response Headers

# Expires: 将失效日期告诉客户端, Expires是HTTP10的内容,如果同时 Expires 和 Cache-control:max-age 存在的话,Expires会被覆盖

# Cache-control: 缓存控制,服务器设置Response Header中能看到,Cache-control:max-age=3600

    public        所有内容都将被缓存
    private        内容只缓存到私有缓存中
    no-cache    所有内容都不会被缓存
    no-store    所有内容都不会被缓存到缓存或 Internet 临时文件中
    must-revalidation/proxy-revalidation    如果缓存的内容失效,请求必须发送到服务器/代理以进行重新验证
    max-age=xxx (xxx is numeric)    缓存的内容将在 xxx 秒后失效, 并如果和Last-Modified一起使用时, 优先级较高

# Content-type: 内容类型

    application/json - JSON类型
    application/x-www-form-urlencoded - 默认
    multipart/form-data - 文件上传
    text/xml - xml文件

# Content-Length: 45783        表名实体部分的大小

# ETag: web服务器响应请求时,告诉浏览器当前资源在服务器的唯一标识(生成规则由服务器决定),生成算法的话,我测试Etag效果的时候用的是MD5值,
        Apache可以配置对静态文件生成Etag
        ETag:"57724c86-1232"
        If-None-Match:"57724c86-1232"

# Date: 首部字段Date表明创建HTTP报文的日期和时间    Date: Fri, 12 Aug 2016 16:25:13 GMT

# Server: apache  nginx  服务器类型

# Via: 是为了追踪客户端与服务器端之间请求和响应报文传输的路径
        Via: http/11 BJ-Y-JCS-204 ( [cRs f ]), http/11 BJ-GWBN-1-JCS-160 ( [cRs f ])

# Accept-Ranges: 用来告诉客户端,服务器是否能处理范围请求
        Accept-Ranges: 1000bytes, 或none

# Age: 告诉客户端,源服务器在多久前创建了响应,单位以秒
        Age: 600

# Last-Modified: 指名了资源最终修改的时间,
        Last-Modified:Mon, 14 Mar 2016 08:04:07 GMT

# Set-Cookie: 设置cookie

浏览器缓存

页面的浏览器缓存状态是由header决定的,header参数有四种:

一、Cache-Control: 

    1、max-age - 指定设置缓存的最大有效时间,当浏览器向服务器发送请求后,如果还在max-age有效期里就不会在向服务器发送请求

    2、public - 指定响应会被缓存,并且在多用户间共享

    3、private - 响应只作为私有缓存,不能在用户间共享,如果要求http认证,响应会自动设置为private

    4、no-cache - 指定不缓存响应

    5、no-store - 绝对禁止缓存,每次请求资源都要从服务器获取 

二、Expires - 设置缓存过期时间,用来指定资源的到期时间,是服务端的具体时间,Expires = max-age + 请求时间,需要和Last-modified结合使用

三、last-modified - 服务器端文件最后修改时间,需要和cache-control共同使用,是检查服务资源是否更新的一种方式,浏览器再次请求会向服务器传送if-Modified-Since报头,询问Last-Modified时间点之后的资源是否被修改,如果没有则返回304,使用缓存,如果修改过,在去服务器请求资源返回200

四、Etag - 根据实体内容生成一段hash字符串,由服务端产生,浏览器会将这字符串传回给服务器,验证资源是否已经被修改

使用缓存流程:

使用缓存流程

cache-control指令使用:

cache-control指令使用

200和304的产生

200 OK( from cache )不向服务器发送请求,直接使用本地缓存文件, Ctrl+F5 直接返回200
304 Not Modified则向服务器询问,若服务器认为浏览器的缓存版本还可用,那么便会返回304, F5 返回304

    200 OK( from cache ) 出现操作: 1.地址栏回车   2.页面链接跳转   3.前进、后退  

    304 Not Modified 出现操作: 1.F5刷新   2.新开窗口

缓存机制
缓存机制

前端安全

一、XSS 跨站脚本攻击

    通常指黑客通过“HTML注入”篡改了网页,插入了恶意的脚本,从而在用户浏览网页时,控制用户浏览器的一种攻击


二、SQL注入

    SQL 注入就是指在输入的字符串中注入 SQL 语句,如果应用相信用户的输入而对输入的字符串没进行任何的过滤处理,那么这些注入进去的 SQL 语句就会被数据库误认为是正常的 SQL 语句而被执行。

    1、以服务器为目标的主动攻击,SQL注入攻击和OS命令注入功击

    2、以服务器为目标的被动攻击,设计好一个陷阱来让用户打开网站,来获取用户的登录信息

    3、跨站脚本攻击 XSS: 

HTTPS

HTTPS的特点: 一是确定请求的目标服务端身份,二是保证传输的数据不会被网络中间节点窃听或者篡改

HTTPS协议需要到CA申请证书,一般免费证书很少,需要交费

HTTP协议运行在TCP之上,所有传输的内容都是明文,HTTPS运行在SSL/TLS之上,SSL/TLS运行在TCP之上,所有传输的内容都经过加密的

HTTP和HTTPS使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443

HTTPS

HTTP2

HTTP2特点: 一是支持服务端推送,二是支持TCP连接复用

1、服务端推送: 能够在客户端发送第一个请求到服务器,提前把一部分内容推荐给客户端,放入缓存中,避免客户端请求顺序带来的并行不够,导致性能问题

2、TCP连接复用: 则使用同一个 TCP 连接来传输多个 HTTP 请求,避免了 TCP 连接建立时的三次握手开销,和初建 TCP 连接时传输窗口小的问题。

| 参考资料
| http://www.alloyteam.com/2016/03/discussion-on-web-caching/
| http://www.alloyteam.com/2016/07/httphttp2-0spdyhttps-reading-this-is-enough/
| http://www.cnblogs.com/lovesong/p/5352973.html
| http://www.cnblogs.com/skynet/archive/2012/11/28/2792503.html

前端优化

前端优化

1、减少HTTP请求: 合并图片(如css sprites,内置图片使用数据)、合并CSS、JS    

2、CDN(内容分发网络): 尽可能避开互联网上有可能影响数据传输速度和稳定性的瓶颈和环节,使内容传输的更快、更稳定

    通过在各地放置节点服务器,CDN可以根据用户的连接距离、负载状况、响应时间等,来为用户选择一个最近的服务器

3、为文件头指定Expires或Cache-Control: 设置资源的缓存时间

4、避免空的src和href: 这两个属性的标签如link,script,img,iframe等    

5、Gzip压缩内容: 服务器对文件进行Gzip压缩,浏览器拿到资源对文件进行解压缩,来减少文件体积

6、CSS放到顶部: 在网速慢的情况会出现,DOM加载完成,没有渲染css,加载到样式的时候才进行重新渲染样式    

7、JS放到底部: 避免脚本阻塞文档的展示,document.wirte()可以阻止文档的展示

8、避免使用CSS表达式: CSS表达式的计算频率会影响前端的性能    

9、将CSS和JS使用外部文件引用: 减少请求数量、利用性、可被缓存,对代码的维护性

10、减少DNS查询: 一个网站有多域,如图片、css、js各存在不同域,这种访问的时候就会存在多域的DNS查询

    缓存常用域名的解析值,但是如果网站涉及多域名,在对每一个域名访问时都需要先解析出IP地址,可以对DNS先进行缓存 <link rel="dns-prefetch" href="http//t1.we.com">

11、对CSS和JS代码进行压缩合并: 目的是减少文件体积,gulp、webpack前端构建工具来进行压缩和合并    

12、避免重定向: 对搜索引擎不友好

    301: 永久重定向,访问文件A的资源的位置,服务器指向了另一个位置来找到A

    302: 临时重定向,请求文件被找到了,但不在这个位置,服务器会发给浏览器所在的位置,之后浏览器会重发取到位置的请求

13、移除重复的脚本: 

14、配置ETags: 服务器会产成一个MD5值,当请求服务器时,服务器的ETags与客户端的值相比较,如果相同说明文件没有被修改过使用缓存文件,返回304状态码

15、AJAX可缓存: jQuery有一个 cache参数,利用时间戳来绕开缓存,更精巧的实现响应可缓存与服务器数据同步更新。

        post请求不能被缓存,get可以缓存

其它优化

1、延迟加载: 确定页面运行正常后,再加载脚本来实现如拖放和动画,或者是隐藏部分的内容以及折叠内容等

2、预加载: 关注下无条件加载,有条件加载和有预期的加载

3、减少查询DOM元素个数: 使用更适合或者在语意是更贴切的标签,要考虑大量DOM元素中循环的性能开销    

4、尽量减少iframe的个数: 优点: 是脚本可以并行下载,适合加载外部广告,浏览器可以对其安全控制。  缺点: 即使内容为空,加载也需要时间,会阻止页面加载,没有语义不会被seo收录

5、减少Cookie的大小: 去除不必要的coockie,使coockie体积尽量小以减少对用户响应的影响,注意在适应级别的域名上设置coockie以便使子域名不受影响,设置合理的过期时间。较早地Expire时间和不要过早去清除coockie,都会改善用户的响应时间

6、使用无cookie的域: 确定对于静态内容的请求是无coockie的请求。创建一个子域名并用他来存放所有静态内容    

7、用<link>代替@import: 在IE中,页面底部@import和使用<link>作用是一样的,因此最好不要使用它    

8、避免使用滤镜: 完全避免使用AlphaImageLoader的最好方法就是使用PNG8格式来代替,这种格式能在IE中很好地工作。如果你确实需要使用 AlphaImageLoader,请使用下划线_filter又使之对IE7以上版本的用户无效。

9、优化图像: 尝试把GIF格式转换成PNG格式,看看是否节省空间。在所有的PNG图片上运行pngcrush(或者其它PNG优化工具)    

10、优化CSS Spirite: 在Spirite中水平排列你的图片,垂直排列会稍稍增加文件大小

  Spirite中把颜色较近的组合在一起可以降低颜色数,理想状况是低于256色以便适用PNG8格式

  便于移动,不要在Spirite的图像中间留有较大空隙。这虽然不大会增加文件大小但对于用户代理来说它需要更少的内存来把图片解压为像素地图。 100×100的图片为1万像素,而1000×1000就是100万像素    

11、不要在HTML中缩放图像: 不要为了在HTML中设置长宽而使用比实际需要大的图片。如果你需要: 

  <img width="100″ height="100″ src="mycat.jpg” alt="My Cat” />

  那么你的图片(mycat.jpg)就应该是100×100像素而不是把一个500×500像素的图片缩小使用。这里在下文有更有趣的分析

12、favicon.ico 需要缓存: favicon.ico是位于服务器根目录下的一个图片文件。浏览器会对它发出请求,因此最好不要返回一 个404 Not Found的响应

13、保持单个内容小于25K: 因为iPhone不能缓存大于25K的文件。注意这里指的是解压缩后的大小。由于单纯gizp压缩可能达不要求,因此精简文件就显得十分重 要

14、避免页面的重排、重绘: 

页面渲染优化

1、HTML文档结构层次尽量少,最好不深于六层

2、脚本尽量后放,放在</body>前即可

3、少量首屏样式内联放在标签内

4、样式结构层次尽量简单

5、在脚本中尽量减少DOM操作,尽量缓存访问DOM的样式信息,避免过度触发回流

6、减少通过JavaScript代码修改元素样式,尽量使用修改class名方式操作样式或动画

7、动画尽量使用在绝对定位或固定定位的元素上

8、隐藏在屏幕外,或在页面滚动时,尽量停止动画

9、尽量缓存DOM查找,查找器尽量简洁

10、涉及多域名的网站,可以开启域名预解析

页面中图片加载的两种效果

一种是回去加载先模糊然后清晰,另一种是很清晰但逐行加载显示,原因是他们的压缩算法不同

1、逐行加载

逐行

经验

一、浏览器加载时增加并行加载线程

    浏览器每次加载2-6个资源,增加并行加载解决方法是,需要实现域分片。也就是在应用上设置多个子域,以便提供资源

目录结构

CSS

| 
|– base/ 
|   |– reset.scss       # 重置样式
|   |– bass                            # 设置基础样式
|   |– functions.scss   # 自定义函数
|   |– mixins.scss      # 宏
|   |– variables.scss     # 变量
|   ...                  # Etc… 
| 
|– components/          # 组件样式
|   |– buttons.scss     # Buttons 
|   |– carousel.scss    # Carousel 
|   |– cover.scss       # Cover 
|   |– dropdown.scss    # Dropdown 
|   |– navigation.scss  # Navigation 
|   ...                  # Etc… 
| 
|– layout/                 
|   |– grid.scss        # 栅格
|   |– header.scss      # 公共头 
|   |– footer.scss      # 公共尾 
|   |– sidebar.scss     # 侧栏 
|   |– forms.scss       # Forms 
|   ...                  # Etc… 
| 
|– pages/ 
|   |– home.scss        # 主页
|   |– contact.scss     # 
|   ...                  # Etc… 
| 
|– themes/ 
|   |– theme.scss       # Default theme 
|   |– admin.scss       # Admin theme 
|   ...                  # Etc… 
| 
|– vendors/             # 存放第三方库
|   |– bootstrap.scss   # Bootstrap 
|   |– jquery-ui.scss   # jQuery UI 
|   ...                  # Etc… 
| 
`– main.scss             # primary Sass file 

JS

| 
|– dist/                                # 压缩目录
| 
|– public/                            # 公共目录    
| 
|– api/                         # 存放一些接口
| 
|– assets/                             # 公共资源
|   |– css
|   |– img
| 
|– components/                     # 公共组件
| 
|– resources/ 
|   |– theme.scss       # Default theme 
|   |– admin.scss       # Admin theme 
|   ...                  # Etc… 
| 
|– utils/                             # 工具类库
|   |– filter.js                
|   |– mock.js    
|   ...                  # Etc… 
|
|– views/                                # 业务组件
|   |– 404.vue
|   |– layout.vue
|
|- app.vue            
|- config.js                
|- main.js
`- router.js

浏览器内核

URL到页面加载发生了什么

1、用户输入网址,浏览器开发一个线程处理这个请求

2、DNS解析 - DNS解析该网站地址对应的IP

3、TCP连接 - 获取到IP后,浏览器向该IP所在的服务器建立TCP连接(三次握手)

4、发送HTTP请求 - 客户端向服务器发送报头和报文;

    后台服务如: Apache、Tomcat、Nginx、Node.js 等服务器

    常见的请求报头有: Accept, Accept-Charset, Accept-Encoding, Accept-Language, Content-Type, Authorization, Cookie, User-Agent等

    报文: Content-Type: application/json

5、服务端接收请求处理逻辑

6、服务端返回响应报文,浏览器接收到响应后,查看是否有缓存资源,status - 304、200

7、浏览器解析渲染页面 - 创建DOM树、渲染DOM树、JS引擎解析、重排重绘

8、连接结束

https://zhuanlan.zhihu.com/p/24913080
https://zhuanlan.zhihu.com/p/24944905

浏览器六个阶段

1、用户界面(User Interface): 用户所看到及与之交互的功能组件,如地址栏,返回,前进按钮等

2、浏览器引擎(Browser engine): 负责控制和管理下一级的渲染引擎

3、渲染引擎(Rendering engine): 负责解析用户请求的内容(如HTML或XML,渲染引擎会解析HTML或XML,以及相关CSS,然后返回解析后的内容)

4、网络(Networking): 负责处理网络相关的事务,如HTTP请求等

5、UI后端(UI backend): 负责绘制提示框等浏览器组件,其底层使用的是操作系统的用户接口

6、JavaScript解释器(JavaScript interpreter): 负责解析和执行JavaScript代码

7、数据存储(Data storage): 负责持久存储Stroage诸如cookie和缓存等应用数据

浏览器内核

1、Trident内核:  IE

2、Webkit内核: Chrome,Safari

3、Gecko内核: FireFox

DNS预解析

浏览器DNS解析大多时候较快,且会缓存常用域名的解析值,但是如果网站涉及多域名,在对每一个域名访问时都需要先解析出IP地址,

希望在跳转或者请求其他域名资源时尽量快,则可以开启域名预解析,浏览器会在空闲时提前解析声明需要预解析的域名,如: 

<link rel="dns-prefetch" href="http//t1.we.com">

多进程

浏览器加载资源一般会并行进程同时加载,限制一般在2-6个

渲染引擎

一、访问一个页面执行流程

    1、发起请求        2、解析HTML        3、解析样式        4、执行JavaScript        5、布局        6、绘制


二、通过网络模块加载到HTML文件后渲染引擎渲染流程如下,这也通常被称作关键渲染路径(Critical Rendering Path):

    1、构建DOM树(DOM tree): 从上到下解析HTML文档生成DOM节点树(DOM tree), 也叫内容树(content tree)

    2、构建CSSOM(CSS Object Model)树: 加载解析样式生成CSSOM树

    3、执行JavaScript: 加载并执行JavaScript代码(包括内联代码或外联JavaScript文件)

    4、构建渲染树(render tree): 根据DOM树和CSSOM树, 生成渲染树(render tree) 渲染树: 按顺序展示在屏幕上的一系列矩形,这些矩形带有字体,颜色和尺寸等视觉属性

    5、布局(layout): 根据渲染树将节点树的每一个节点布局在屏幕上的正确位置

    6、绘制(painting): 遍历渲染树绘制所有节点,为每一个节点适用对应的样式,这一过程是通过UI后端模块完成


三、解析样式和脚本

    1、脚本是可能存在改变DOM结构,于是浏览器以同步方式解析,加载和执行脚本,浏览器遇到script标签就选择js代码,现在HTML5提供defer和async两个属性支持延迟和异步加载JavaScript文件

        <script defer src="script.js">

    2、样式不同于脚本,浏览器对样式处理并不会阻塞文档解析,因为样式不会改变DOM结构


四、重绘、重排

    尽量减少reflow:

    重排: 当页面结构发生改变,渲染树重新组装,如块级元素的(margin、padding)当前元素位置发生改变会影响下面所有元素的位置需要重排,position: absolute不会引发重排

    重绘: 就是不改变页面的结构,只改变一些颜色,如(文字颜色、边框颜色)

收集

一、访问域名

    访问京东域名时,会发现有Remote Address,这里是在访问域名时并不会直接访问服务器而是在中间过了一层,目的是为当前用户找到离他最近的一台服务来进行跳转,可以让最快速度来访问

jd_ip

| http://blog.codingplayboy.com/2017/03/29/webpage_render/
| https://www.webpagetest.org/ // 网站的性能评估