1

一 分页优化

  1. 首次查询的时候缓存结果。这样情况就变得简单了,无论是结果条目的数量,总共的页面数量,还是取出其中的部分条目。

  2. 不显示总共有多少条目。Google搜索结果的分页显示就用了这个特性。很多时候你可能看了前几页,就够了。那么我可以这样,每次我都把结果限制在500条(这个数据越大 资源消耗越大)然后你每次查询的时候,都查询501条记录,这样,如果结果真有501个,那么我们就显示链接 “显示下500条记录”。

  3. 不显示总页面数。只给出“下一页”的链接,如果有下一页的话。(如果用户想看上一页的话,他会通过浏览器来回到上一页的)。那你可能会问我“不显示总页面数”怎么知道是不是有下一页呢?这里有一个很好的小技巧:你在每次显示你当前页面条目的时候你都多查询一条,例如你要显示第11-20个条目时,你就取出11-21条记录(多取一条,并不显示这多取的内容),那么当你发现第21条存在的时候就显示“下一页的链接”,否则就是末页了。这样你就不用每次计算总页面数量了,特别是在做缓存很困难的时候这样做效率非常好。

  4. 估算总结果数。Google就是这么做的,事实证明效果很好。用EXPLAIN 来解释你的SQL,然后通过EXPLAIN的结果来估算。EXPLAIN结果有一列”row”会给你一个大概的结果。(这个办法不是处处都行,但是某些地方效果是很好的)这些办法可以很大程度上减轻数据库的压力,而且对用户体验不会有什么影响。


二 为什么跨域怎么解决

1 动态创建script标签

为什么script标签引入的文件不受同源策略的限制?因为script标签引入的文件内容是不能够被客户端的js获取到的,不会影响到被引用文件的安全,所以没必要使script标签引入的文件遵循浏览器的同源策略。而通过ajax加载的文件内容是能够被客户端js获取到的,所以ajax必须遵循同源策略,否则被引入文件的内容会泄漏或者存在其他风险


function loadScript(url, func) {
            var head = document.head || document.getElementByTagName('head')[0];
            var script = document.createElement('script');
            script.src = url;
            script.onload = script.onreadystatechange = function() {
                if(!this.readyState || this.readyState == 'loaded' || this.readyState == 'complete') {
                    func();
                    script.onload = script.onreadystatechange = null;
                }
            };
            head.appendChild(script);
        }
        window.baidu = {
            sug: function(data) {
                console.log(data);
            }
        }
        loadScript('http://suggestion.baidu.com/su?wd=w', function() {
            console.log('loaded')
        });
//此处可以是服务端的数据接口直接返回需要的信息
//        loadScript('http://localhost:8080/resteasyDemo/rest/echo/test?test=1', function() {
//            console.log('loaded')
//            console.log(name)
//        });

2 window.name+iframe


window.name 的美妙之处:name 值在不同的页面(甚至不同域名)加载后依旧存在,并且可以支持非常长的 name 值(2MB)。

步骤 1 创建包含获取和创建iframe代码的A域名下a.html

步骤 2 创建A域名下的空页面b.html

目的是当iframe设置跨域后的页面后立即重新src到同源的b.html页面,从而完成加载的是跨域页面而实际src是同源页面,用来实现同源获取值

a.html页面写如下代码

function proxy(url, func) {
                var isFirst = true,
                    ifr = document.createElement('iframe'),
                    loadFunc = function() {
                        if(isFirst) {
                            ifr.contentWindow.location = 'http://10.149.4.6:8020/b.html';
                            isFirst = false;
                        } else {
                            func(ifr.contentWindow.name);
                            ifr.contentWindow.close();
                            document.body.removeChild(ifr);
                            ifr.src = '';
                            ifr = null;
                        }
                    };

                ifr.src = url;
                ifr.style.display = 'none';
                if(ifr.attachEvent) ifr.attachEvent('onload', loadFunc);
                else ifr.onload = loadFunc;

                document.body.appendChild(ifr);
            }

调用跨域页面

proxy('http://10.149.4.10:8080/c.html', function(data) {
                console.log(JSON.stringify(data));
            });

c页面设置window.name

<body>
    <script type="text/javascript">
        window.name='{"foo":"bar"}';
    </script>
</body>

3 postMessage HTML5中 XMLHttpRequest level2中的 API


a.com/index.html

<iframe id="ifr" src="b.com/index.html"></iframe>
<script type="text/javascript">
window.onload = function() {
    var ifr = document.getElementById('ifr');
    var targetOrigin = 'http://b.com';  // 若写成'http://b.com/c/proxy.html'效果一样
                                        // 若写成'http://c.com'就不会执行postMessage了
    ifr.contentWindow.postMessage('I was there!', targetOrigin);
};
</script>

b.com/index.html

<script type="text/javascript">
    window.addEventListener('message', function(event){
        // 通过origin属性判断消息来源地址
        if (event.origin == 'http://a.com') {
            alert(event.data);    // 弹出"I was there!"
            alert(event.source);  // 对a.com、index.html中window对象的引用
                                  // 但由于同源策略,这里event.source不可以访问window对象
        }
    }, false);
</script>

4 jsonP


不用多说..js标签执行回调

5 web sockets


var socket = new WebSockt('ws://www.baidu.com');//http->ws; https->wss
socket.send('hello WebSockt');
socket.onmessage = function(event){
    var data = event.data;
}

三 事件委托

需要了解的是 对象的 冒泡事件和捕获事件(true)

1 针对同一个元素来说捕获事件和冒泡事件的执行顺序取决于对这个元素绑定事件的先后声明

2 对于除去本身点击元素外的父元素来说,捕获事件优先于冒泡事件触发

e.target和e.currentTarget区别是 前者是事件触发的元素,后者是事件绑定的触发元素


四 实现extend

对浅拷贝的一次递归实现了深拷贝

function cloneOriginal(obj) {
                if(typeof obj != "object" && obj != null || obj == null) return obj;
                var temObj = obj.constructor === Array?[]:{};
                for(var key in obj) {
                    temObj[key] = cloneOriginal(obj[key]);
                }
                return temObj;
            }
            
            function extend() {
                if(arguments.length < 2) return arguments;
                var temObj = cloneOriginal(arguments[0]);
                for(var i = 1;i<arguments.length;i++) {
                    for(var j in arguments[i]) {
                        temObj[j] = cloneOriginal(arguments[i][j]);
                    }
                }
                return temObj;
            }
            
            var a = {name:111,age:222,kkk:[1,2,3],ddd:{height:100},e:function() {console.log("eee")}};
            var b = {width:333};
            var c = {color:"黄色",border:"1px"};
            var d = extend(b,a,c);
            console.log(d);
            a.kkk.push(44444);
            console.log(d);
            
            //2使用json解析
            var a2 = {name:111,age:222,kkk:[1,2,3],ddd:{height:100}};
            var b2 = JSON.parse(JSON.stringify(a));
            console.log(b2);
}

而其中json解析的方法对于序列化的简单的拷贝来说可以,但是对于很大没有完全序列化的对象来说是不行的

例:var a = {name:111,b:function() {}}


五 Event Loop

图片描述

上图中,主线程运行的时候,产生堆(heap)和栈(stack),栈中的代码调用各种外部API,它们在"任务队列"中加入各种事件(click,load,done)。只要栈中的代码执行完毕,主线程就会去读取"任务队列",依次执行那些事件所对应的回调函数。

执行栈中的代码(同步任务),总是在读取"任务队列"(异步任务)之前执行


六 同一帧数管理页面

当页面动画非常繁多,并且需要不断的刷新不同动画数据的时候,浏览器每次收到从Server端发来的消息,js脚本都会将消息的内容作为一个新的文本节点添加到页面中去。这样做,会立刻导致HTML文档的部分DOM树重构,部分渲染树重构,部分渲染树重排,已经部分渲染树重绘。也就是说,每当浏览器收到一条消息,都会执行上面的4个步骤。这样一来,处理每条消息时,浏览器画在更新渲染页面上的时间大大超出了js脚本运行所需的时间。于是我们看到的结果就是页面变得非常卡,用户体验极差。

图片描述

通过setTimeout递归调用自己,并且是每隔16ms调用一次,大约一秒60次。每次被调用的时候,该函数都会挨个检查页


七 promise详解

具体API都在这里了

知识点:偏函数应用

偏函数应用 闭包应用的一种
实例:

function joinWords(a,b) { return [a,b].join(' '); }

function prefixer(word) { return function(b) { return joinWords(word,b); } }

var prefixWithHate = prefixer('Hate'); console.log(prefixWithHat('Java'));

prefixer函数授受一个词作为参数,返回一个函数并预先填入这个词作为第一个参数,这是利用闭包,word 对于内部函数是可以访问的,

学习点,

偏函数中的闭包 参数对于子函数永远可见

函数内用retrurn 返回函数的写法

用一个变量获得成为一个函数,

偏函数设置默认的是值,并不变量,类似闭包实现


八 基本类型和引用类型

ECMAScript 中,所有函数的参数都是按值来传递的。基本类型值的传递和基本类型变量复制一致(采用在栈内新建值),引用类型值的传递和引用类型变量的复制一致(栈内存空间的复制,栈内存放的是指针,指向堆中同一对象


九 bind

Function.prototype.bind_ = function() {
            var t = this,
                param = Array.prototype.slice.call(arguments),
                fn = param.shift(),
                content = param;
            return function() {
                return t.apply(fn, content.concat(Array.prototype.slice.call(arguments)));
            }
        }
        
        //赋值默认值
        var fuzhi = function() {
            var t = this,
                param = Array.prototype.slice.call(arguments),
                fn = param.shift(),
                content = param;
            return function() {
                return fn.apply(this,content.concat(Array.prototype.slice.call(arguments)))
            }
        }
        
        function test(n,name) {
            setTimeout(function() {
                console.log(name);
            },n)
        }
        
        var test_ = fuzhi(test,2000);
        test_("hahah");
}

十 关于new运算符

这是在书中看到的,拿来总结下
当一个函数对象被创建时,Function构造器产生的函数对象会运行这样的一段代码:

Function.prototype = {constructor:this}

new的实际意义:

Function.prototype.method = function(name,fn) {
                if(this.prototype[name]) return this;
                this.prototype[name] = fn;
                return this;
            }
            Function.method('new',function() {
                var that = Object.create(this.prototype);
                var other = this.apply(that,arguments);
                return (typeof other === 'object' && other) || that;
            })
}

简单应用例子

//简单的伪类继承
            Function.method("jc",function(jcObj) {
                this.prototype = new jcObj();
                return this;
            })
            
            var people = function() {
                this.name = "people";
            }.method("getName",function() {
                console.log(this.name);
            })
            
            var man = function() {
                this.manName = "man";
            }
            .jc(people)
            .method("detail",function() {
                console.log("my father`s name is: "+this.name);
                console.log("my name is: "+this.manName);
            })
            
            var obj = new man();
            obj.detail()
            }

实际简单总结下就是如下代码
step1 :创建构造函数

function A() {
    this.name = "a";
}
var a = new A();

step2 创建a实例使用new经历了以下四个步骤
1 var obj = {};

2 obj.__proto__ = A.prototype;

3 A.call(obj);

4 return obj;


呼啦星星星
80 声望7 粉丝

推倒前端这只伪娘!!!