浅析jsonp原理与实现

jsonp,作为跨域的最常用解决方案,大家已经对其非常熟悉了。各个前端框架或库都对jsonp有自己的实现。其实对jsonp原理熟悉,并自己实现过,相信在技术选型或遇到问题时,能处在更加主动的位置。接下来就讲讲jsonp的原理以及我自己的实现。

同源策略下,a.com域下的javascript无法访问b.com域下的页面内容,ajax也无法向向b.com提交内容(服务端返回的Access-Control-Allow-Origin头可以允许跨域提交),而script标签不受该策略限制,在a.com页面插入src=”http://b.com/jsonp?foo=bar&callback=cb”的script节点,就相当于发送了GET请求到b.com域下,关于同源政策可参见wiki

b.com收到请求后,应当返回一段可执行的javascript代码,一般将数据作为参数传入一个callback函数中,例如:


1
callback({"foo":"bar"})

这就会执行a.com页面的window.callback函数,{“foo”:”bar”}作为参数传入callback函数,至此a.com拿到了b.com的数据。当然,加载script之前必须声明callbak全局函数,否则加载后会报错。以下是本人实现的jsonp,callback函数在加载前定义,并在加载结束后从window中删除,避免污染全局。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
;(function(){
    if (typeof(window.Ys) === 'undefined') window.Ys = {};
    Ys.jsonp = function(options){

        Ys.jsonp.id = 0;

        var script = document.createElement('script');

        if(/\?/.test(options.url)){
            script.src = options.url + '&callback=' + options.callback;
        } else {
            script.src = options.url + '?callback=' + options.callback;
        }

        var tmpData = null;

        window[options.callback] = function(data){tmpData = data};

        script.onload = script.onreadystatechange = function(){
            if(typeof(this.readyState) === "undefined" || this.readyState === "loaded" || this.readyState === "complete" ){

                options.onSuccess(tmpData);
                tmpData = null;
                delete window[options.callback];
                var tmp = document.getElementById('jsonpScript' + Ys.jsonp.id);
                tmp.parentNode.removeChild(tmp);
                Ys.jsonp.id++;
            }
        }
        script.id = 'jsonpScript' + Ys.jsonp.id;
        Ys('#content')[0].appendChild(script);  

    }

})(window);

合理利用webkit页面缓存(page cache)

webkit内核有一种页面缓存策略,能大大减少移动端的流量消耗——页面缓存策略(page cahce)

这里引用一下webkit官方文档关于page cache的解释

Ideally the previous page can instead be placed in the Page Cache. The entire live page is kept in memory even though it is not on screen. This means that all the different bits and pieces that represent what you see on the screen and how you interact with it are suspended instead of destroyed. They can then be revived later in case you click the back button.

其实现方式就是:

页面跳转时,把前一页面的dom,css,js,javascript堆栈信息全部存入内存中,这样在用户点“返回”时,浏览器不需要发出任何http请求,直接从内存中调出页面即可

给用户的感觉就是:”一瞬间页面就加载出来了“

page cache优势很明显,但也有很明显的缺陷:

1.页面上的数据是过时的;2.页面不触发onload事件

两个问题可以一并解决,监听window的pageshow,pagehide事件,他们分别在页面展现和关闭时触发

pageshow和pagehide都有persisted属性,通过event.persisted的值,即刻知道当前页面是否是从缓存中还原的

如果不想使用pagecache中的页面,当event.persisted == true的时候,reload下页面即可

关于为什么会新增pageshow,pagehide事件见下文:

firefox对于pageshow,pagehide事件的解释

另外推荐两篇webkit官方关于pagecache的详解:

Surfin’ Safari – Blog Archive » WebKit Page Cache I – The Basics

Surfin’ Safari – Blog Archive » WebKit Page Cache II – The unload Event

转载请注明出处:http://www.yinfan.org/article/rational-use-of-the-webkit-page-cache

 

wordpress屏蔽垃圾评论(改源码,非插件)

worpress的垃圾评论让人很烦躁,使用插件神马的会让博客变慢,强制用户登录或输入验证码会让博客活跃度下降,有用的评论也少了

今天介绍一种方式,不用插件,允许用户不用登陆也能发表评论,同时有效杜绝垃圾评论!

废话不说了,直接上方法:

1.更改根目录下wp-comments-post.php的文件名,随意改,尽量改的奇怪些,例如:wpp-post.php

2.编辑/wp-includes/comment-template.php,将2046行的:


1
<form action="<?php echo site_url( '/wp-comments-post.php' ); ?>" method="post" id="<?php echo esc_attr( $args['id_form'] ); ?>" class="comment-form"<?php echo $html5 ? ' novalidate' : ''; ?>>

替换成:


1
2
3
4
<form action="" method="post" id="<?php echo esc_attr( $args['id_form'] ); ?>" class="comment-form"<?php echo $html5 ? ' novalidate' : ''; ?>>
<script>
    document.getElementById('<?php echo esc_attr( $args['id_form'] ); ?>').action = "./submit-comments-ivanyin.php";
</script>

下面说说原理:

一般的垃圾评论都是机器直接提交,直接post数据到根目录下的wp-comments-post.php

另一种则是扫描已打开的页面,匹配出评论form指向的action地址,再用机器提交

我的思路就是改变默认的wp-comments-post.php文件名,同时将评论表单的action置空

只有在浏览器中打开页面,js才会将评论表单的action指向正确的地址,这样就杜绝了机器分析

本人的博客已经相当久没有垃圾评论啦

文章地址:http://www.yinfan.org/article/wordpress-block-comment-spam-modified-source-code-non-plugin

此方法纯原创,转载请写明出处,谢谢

 

 

订阅-发布模式

事件监听大家都经常用,今天就讲讲事件监听的高级抽象——订阅-发布模式(观察者模式)

发布-订阅(publish–subscribe)是一种消息传播模式,消息的发送者(发布者)不会将消息直接发送给特定的接收者(订阅者)。而是将发布的消息按特征分类,无需对订阅者(如果有的话)有所了解。同样的,订阅者可以表达对一个或多个类别的兴趣,只接收感兴趣的消息,无需对发布者(如果有的话)有所了解。

我们常用的事件监听往往是一对一或一对多的形式(dom.onclick=function(){}的形式只能绑定一个事件处理函数,属于一对一)

而订阅-发布模式要求支持多对多的形式,因此需要抽象一个对象,同时面向发布者和订阅者,发布者和订阅者通过约定的数据结构进行通信
继续阅读

再谈事件冒泡与事件捕获

之前谈过javascript事件代理的机制和思路,提了一下事件冒泡,不是很全。

今天详细讲讲事件冒泡和事件捕获。

这个话题源自addEventListener与attachEvent的区别

其中addEventlistener的第三个参数决定了事件是被捕获还是被冒泡。

具体的区别这里有篇文章已经讲得比较详细了,这里不再阐述。

就像提醒一点,之前在写Ys.js库的时候也遇到过这个坑,希望大家不要跳坑:

attachEvent绑定事件时,handler中的this关键字指向window,而不是要绑定的dom!

想绑定当前dom需要自己解决,距地放下下文会讲到。

下面说说事件冒泡与事件获取。

很多资料会用“js事件冒泡”或者“js事件捕获”来描述,

其实这样说是不太准确的,准确的来说,

事件冒泡和事件捕获都是DOM事件流,一个是冒泡事件流,一个是捕获事件流。

下面给大家直观的看看两者的区别:

继续阅读