leadscloud

Google SEO|外贸营销推广

看到这个标题大家一定会想到这篇神文《How Browsers Work》,这篇文章把浏览器的很多细节讲得很细,而且也被翻译成了中文。为什么我还想写一篇呢?因为两个原因,

1)这篇文章太长了,阅读成本太大,不能一口气读完。

2)花了大力气读了这篇文章后可以了解很多,但似乎对工作没什么帮助。

所以,我准备写下这篇文章来解决上述两个问题。希望你能在上班途中,或是坐马桶时就能读完,并能从中学会一些能用在工作上的东西。

浏览器工作大流程

废话少说,先来看个图:

从上面这个图中,我们可以看到那么几个事:

 

1)浏览器会解析三个东西:

  • 一个是HTML/SVG/XHTML,事实上,Webkit有三个C++的类对应这三类文档。解析这三种文件会产生一个DOM Tree。

  • CSS,解析CSS会产生CSS规则树。

  • Javascript,脚本,主要是通过DOM API和CSSOM API来操作DOM Tree和CSS Rule Tree.
    2)解析完成后,浏览器引擎会通过DOM Tree 和 CSS Rule Tree 来构造 Rendering Tree。注意:

  • Rendering Tree 渲染树并不等同于DOM树,因为一些像Header或display:none的东西就没必要放在渲染树中了。

  • CSS 的 Rule Tree主要是为了完成匹配并把CSS Rule附加上Rendering Tree上的每个Element。也就是DOM结点。也就是所谓的Frame。

  • 然后,计算每个Frame(也就是每个Element)的位置,这又叫layout和reflow过程。
    3)最后通过调用操作系统Native GUI的API绘制。

DOM解析

HTML的DOM Tree解析如下:

1
2
3
4
5
6
7
8
9
10
11
12
<html>
<html>
<head>
<title>Web page parsing</title>
</head>
<body>
<div>
<h1>Web page parsing</h1>
<p>This is an example Web page.</p>
</div>
</body>
</html>

上面这段HTML会解析成这样:

下面是另一个有SVG标签的情况。

CSS解析

CSS的解析大概是下面这个样子(下面主要说的是Gecko也就是Firefox的玩法),假设我们有下面的HTML文档:

1
2
3
4
5
6
7
8
9
<doc>
<title>A few quotes</title>
<para>
Franklin said that <quote>"A penny saved is a penny earned."</quote>
</para>
<para>
FDR said <quote>"We have nothing to fear but <span>fear itself.</span>"</quote>
</para>
</doc>

于是DOM Tree是这个样子:

然后我们的CSS文档是这样的:

1
2
3
4
/* rule 1 */ doc { display: block; text-indent: 1em; }
/* rule 2 */ title { display: block; font-size: 3em; }
/* rule 3 */ para { display: block; }
/* rule 4 */ [class="emph"] { font-style: italic; }

于是我们的CSS Rule Tree会是这个样子:

注意,图中的第4条规则出现了两次,一次是独立的,一次是在规则3的子结点。所以,我们可以知道,建立CSS Rule Tree是需要比照着DOM Tree来的。CSS匹配DOM Tree主要是从右到左解析CSS的Selector,好多人以为这个事会比较快,其实并不一定。关键还看我们的CSS的Selector怎么写了。

注意:CSS匹配HTML元素是一个相当复杂和有性能问题的事情。所以,你就会在N多地方看到很多人都告诉你,DOM树要小,CSS尽量用id和class,千万不要过渡层叠下去,……

通过这两个树,我们可以得到一个叫Style Context Tree,也就是下面这样(把CSS Rule结点Attach到DOM Tree上):

所以,Firefox基本上来说是通过CSS 解析 生成 CSS Rule Tree,然后,通过比对DOM生成Style Context Tree,然后Firefox通过把Style Context Tree和其Render Tree(Frame Tree)关联上,就完成了。注意:Render Tree会把一些不可见的结点去除掉。而Firefox中所谓的Frame就是一个DOM结点,不要被其名字所迷惑了

注:Webkit不像Firefox要用两个树来干这个,Webkit也有Style对象,它直接把这个Style对象存在了相应的DOM结点上了。

渲染

渲染的流程基本上如下(黄色的四个步骤):

  1. 计算CSS样式
  2. 构建Render Tree
  3. Layout – 定位坐标和大小,是否换行,各种position, overflow, z-index属性 ……
  4. 正式开画

注意:上图流程中有很多连接线,这表示了Javascript动态修改了DOM属性或是CSS属会导致重新Layout,有些改变不会,就是那些指到天上的箭头,比如,修改后的CSS rule没有被匹配到,等。

这里重要要说两个概念,一个是Reflow,另一个是Repaint。这两个不是一回事。

ul>

  • Repaint——屏幕的一部分要重画,比如某个CSS的背景色变了。但是元素的几何尺寸没有变。
  • Reflow——意味着元件的几何尺寸变了,我们需要重新验证并计算Render Tree。是Render Tree的一部分或全部发生了变化。这就是Reflow,或是Layout。(HTML使用的是flow based layout,也就是流式布局,所以,如果某元件的几何尺寸发生了变化,需要重新布局,也就叫reflow)reflow 会从这个root frame开始递归往下,依次计算所有的结点几何尺寸和位置,在reflow过程中,可能会增加一些frame,比如一个文本字符串必需被包装起来。
    下面是一个打开Wikipedia时的Layout/reflow的视频(注:HTML在初始化的时候也会做一次reflow,叫 intial reflow),你可以感受一下:

 

Reflow的成本比Repaint的成本高得多的多。DOM Tree里的每个结点都会有reflow方法,一个结点的reflow很有可能导致子结点,甚至父点以及同级结点的reflow。**在一些高性能的电脑上也许还没什么,但是如果reflow发生在手机上,那么这个过程是非常痛苦和耗电的**。

 

所以,下面这些动作有很大可能会是成本比较高的。

  • 当你增加、删除、修改DOM结点时,会导致Reflow或Repaint
  • 当你移动DOM的位置,或是搞个动画的时候。
  • 当你修改CSS样式的时候。
  • 当你Resize窗口的时候(移动端没有这个问题),或是滚动的时候。
  • 当你修改网页的默认字体时。

注:display:none会触发reflow,而visibility:hidden只会触发repaint,因为没有发现位置变化。

多说两句关于滚屏的事,通常来说,如果在滚屏的时候,我们的页面上的所有的像素都会跟着滚动,那么性能上没什么问题,因为我们的显卡对于这种把全屏像素往上往下移的算法是很快。但是如果你有一个fixed的背景图,或是有些Element不跟着滚动,有些Elment是动画,那么这个滚动的动作对于浏览器来说会是相当相当痛苦的一个过程。你可以看到很多这样的网页在滚动的时候性能有多差。因为滚屏也有可能会造成reflow。

基本上来说,reflow有如下的几个原因:

  • Initial。网页初始化的时候。
  • Incremental。一些Javascript在操作DOM Tree时。
  • Resize。其些元件的尺寸变了。
  • StyleChange。如果CSS的属性发生变化了。
  • Dirty。几个Incremental的reflow发生在同一个frame的子树上。

好了,我们来看一个示例吧:

1
2
3
4
5
6
7
8
9
10
11
12
var bstyle = document.body.style; // cache

bstyle.padding = "20px"; // reflow, repaint
bstyle.border = "10px solid red"; // 再一次的 reflow 和 repaint

bstyle.color = "blue"; // repaint
bstyle.backgroundColor = "#fad"; // repaint

bstyle.fontSize = "2em"; // reflow, repaint

// new DOM element - reflow, repaint
document.body.appendChild(document.createTextNode('dude!'));

当然,我们的浏览器是聪明的,它不会像上面那样,你每改一次样式,它就reflow或repaint一次。一般来说,浏览器会把这样的操作积攒一批,然后做一次reflow,这又叫异步reflow或增量异步reflow。但是有些情况浏览器是不会这么做的,比如:resize窗口,改变了页面默认的字体,等。对于这些操作,浏览器会马上进行reflow。

但是有些时候,我们的脚本会阻止浏览器这么干,比如:如果我们请求下面的一些DOM值:

  1. offsetTop, offsetLeft, offsetWidth, offsetHeight
  2. scrollTop/Left/Width/Height
  3. clientTop/Left/Width/Height
  4. IE中的 getComputedStyle(), 或 currentStyle

因为,如果我们的程序需要这些值,那么浏览器需要返回最新的值,而这样一样会flush出去一些样式的改变,从而造成频繁的reflow/repaint。

减少reflow/repaint

下面是一些Best Practices:

1)不要一条一条地修改DOM的样式。与其这样,还不如预先定义好css的class,然后修改DOM的className。

1
2
3
4
5
6
7
8
9
10
11
// bad
var left = 10,
top = 10;
el.style.left = left + "px";
el.style.top = top + "px";

// Good
el.className += " theclassname";

// Good
el.style.cssText += "; left: " + left + "px; top: " + top + "px;";

2)把DOM离线后修改。如:

  • 使用documentFragment 对象在内存里操作DOM
  • 先把DOM给display:none(有一次reflow),然后你想怎么改就怎么改。比如修改100次,然后再把他显示出来。
  • clone一个DOM结点到内存里,然后想怎么改就怎么改,改完后,和在线的那个的交换一下。
    3)**不要把DOM结点的属性值放在一个循环里当成循环里的变量。**不然这会导致大量地读写这个结点的属性。

4)尽可能的修改层级比较低的DOM。当然,改变层级比较底的DOM有可能会造成大面积的reflow,但是也可能影响范围很小。

5)为动画的HTML元件使用fixed或absoult的position,那么修改他们的CSS是不会reflow的。

6)千万不要使用table布局。因为可能很小的一个小改动会造成整个table的重新布局。

In this manner, the user agent can begin to lay out the table once the entire first row has been received. Cells in subsequent rows do not affect column widths. Any cell that has content that overflows uses the ‘overflow’ property to determine whether to clip the overflow content.

Fixed layout, CSS 2.1 Specification
This algorithm may be inefficient since it requires the user agent to have access to all the content in the table before determining the final layout and may demand more than one pass.

Automatic layout, CSS 2.1 Specification

几个工具和几篇文章

有时候,你会也许会发现在IE下,你不知道你修改了什么东西,结果CPU一下子就上去了到100%,然后过了好几秒钟repaint/reflow才完成,这种事情以IE的年代时经常发生。所以,我们需要一些工具帮我们看看我们的代码里有没有什么不合适的东西。

参考

原文:http://coolshell.cn/articles/9666.html

最近浏览器在保存图片或上传文件时经常崩溃, 个人猜测是因为windows资源管理器的问题, 一直无法解决,今天能过windows的事件查看器,看到以下错误,在网上搜索,果然发现有类似问题, 其实不是浏览器的问题, 以前经常是搜索chrome经常崩溃怎么办, 所以没的到解决办法.

Application Error

错误应用程序名称: chrome.exe,版本: 26.0.1410.64,时间戳: 0x5163bfb1
错误模块名称: shellext.dll_unloaded,版本: 0.0.0.0,时间戳: 0x50d2bf97
异常代码: 0xc0000005
错误偏移量: 0x11df83fa
错误进程 ID: 0x620
错误应用程序启动时间: 0x01ce67dd5bda0094
错误应用程序路径: C:\Program Files\Google\Chrome\Application\chrome.exe
错误模块路径: shellext.dll
报告 ID: 719d9e97-d420-11e2-9e59-50e5494efd95

问题出在 shellext.dll, 是软件桌面工具,http://www.wenjian.cn/xijie/shellext.dll.html .

根据这篇文章(http://blog.csdn.net/phoenix2121/article/details/8854501)确定是快用青苹果助手的问题. 把快用助手卸载掉就行了.

最初用Privoxy是因为七星庐的文章强大的代理调度器代理Privoxy,用作代理切换,后来顺便也用起它广告过滤的功能

能实现这两个功能的软件/插件很多,而且用起来往往比privoxy来的方便,比如foxproxy和adblock。我之所以用privoxy是因为以下原因:

  • 作为系统的全局自动代理切换器。GNOME和环境变量的代理设置不是对任何软件都管用,PAC也不是哪里都行
  • 广告过滤可用于任何浏览器,并且容易定制,改改网页什么的

配置是繁琐些,但用起来确实不错。

安装用源里的就可以,默认是作为系统服务启动的。装好后请将浏览器代理设置为127.0.0.1:8118,以便测试。地址栏输入”p.p”可以查看配置、文档、调试等等。

代理切换

配置文件都在/etc/privoxy目录下。编辑config文件,加入一行
actionsfile pac.action
这表示添加一个动作文件,文件名是pac.action。在同目录下建立文件”pac.action”,并写入配置。一个示例如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{{alias}}
direct = +forward-override{forward .}
ssh = +forward-override{forward-socks5 127.0.0.1:7000 .}
gae = +forward-override{forward 127.0.0.1:8000}
default = direct
#==========默认代理==========
{default}
/
#==========直接连接==========
{direct}
.edu.cn
202.117.255.
222.24.211.70
#==========SSH代理==========
{ssh}
.launchpad.net
#==========GAE代理==========
{gae}
.webupd8.org
222.24.211.70

上面的{{alias}}部分定义了一些缩写,注意http代理和socks代理的写法不同。

后面的如{direct}部分定义对哪些地址应用这个代理。其中”/“表示全部地址。注意一个URL的域名部分只能用glob匹配,而地址部分可以用复杂的正则表达式。具体可以看Privoxy的文档

这些规则在后面的会覆盖前面的,比如222.24.211.70实际是以gae代理访问的。这样可以实现一些稍微复杂的功能

广告过滤

广告过滤用的文件要多些,可能还需要filter文件。先看一个最基本的只使用action文件和block动作的广告过滤。直接编辑user.action文件,添加

1
2
3
{+block}
.5622.cn
/.*\.swf$

这样5622.cn和所有flash都被阻止了。如果你还想看某些flash视频,可以在后面再-block,这会覆盖前面的设置,如

1
2
{-block}
static.youku.com/.*\.swf$

配合filter文件和action文件,可以实现对网页内容的替换,从而屏蔽某些不想要的内容。先编辑config文件,去掉”filterfile user.filter”这行的注释,然后在同目录下建立user.filter文件,写入

1
2
3
4
FILTER: iframe
s@</head>@<style type="text/css">\n\
iframe {display:none; !important}\n\
</style>\n$0@

这样就定义了一个名为”iframe”的过滤器。之后再编辑user.action文件,添加

1
2
{+filter{iframe}}
.filestube.com

这表明对filestube应用”iframe”这个过滤器。filter书写复杂些

除了过滤广告,还能做做地址转向,比如

1
2
3
4
5
{+redirect{s@^http://[^/]*/.*?&amp;q=(.*)@http://www.google.com/search?hl=en&amp;q=$1@}}
.google.com.hk/search

{+redirect{s@^http://[^/]*(/$|$)@http://www.google.com/ncr@}}
.google.com.hk/$

其它内容

以普通用户启动

先关掉privoxy服务,可以用sysv-rc-conf或者直接删掉/etc/init.d/privoxy文件。然后将/etc/privoxy目录的内容复制到家目录下,比如~/.privoxy。编辑config文件,将”confdir /etc/privoxy”改为

confdir /home/用户名/.privoxy
然后用下面命令启动
privoxy --no-daemon $HOME/.privoxy/config

有身份验证的代理

先获得”用户名:密码”的base64编码,方法如下

1
perl -e "use MIME::Base64; print encode_base64('用户名:密码');"

然后这样写alias

1
proxy = +forward-override{forward 127.0.0.1:808} +add-header{Proxy-authorization: Basic <auth>}

<auth>替换为上面得到的base64编码的用户名和密码

一个完整的方案

上面这些文件完全可以精简和清晰,我的目录下只有config、pac.action、user.action、user.filter这四个文件。另外还可以小脚本来切换默认的代理。下面贴出这些配置和切换脚本,略加修改过的,我的配置目录是~/.proxy

切换脚本:http://paste.pocoo.org/show/372771/

这个脚本是,在家里默认代理(default)directgae之间切换,学校是在paper和gae之间切换。绑定个快捷键会很方便

人们总喜欢往HTML标签上添加自定义属性来存储和操作数据。但这样做的问题是,你不知道将来会不会有其它脚本把你的自定义属性给重置掉,此外,你这样做也会导致html语法上不符合Html规范,以及一些其它副作用。这就是为什么在HTML5规范里增加了一个自定义data属性,你可以拿它做很多有用的事情。

你可以去读一下HTML5的详细规范,但这个自定义data属性的用法非常的简单,就是你可以往HTML标签上添加任意以 “data-“开头的属性,这些属性页面上是不显示的,它不会影响到你的页面布局和风格,但它却是可读可写的。

下面的一个代码片段是一个有效的HTML5标记:

1
<div id="awesome" data-myid="3e4ae6c4e">Some awesome data</div>

可是,怎么来读取这些数据呢?你当然可以遍历页面元素来读取你想要的属性,但jquery已经内置了方法来操作这些属性。使用jQuery的.data()方法来访问这些”data-*” 属性。其中一个方法就是 .data(obj),这个方法是在 jQuery1.4.3版本后出现的,它能返回相应的data属性。

举个例子,你可以用下面的写法读取 data-myid属性值:

1
2
var myid= jQuery("#awesome").data('myid');
console.log(myid);

你还可以在”data-*” 属性里使用json语法,例如,如果你写出下面的html:

1
<div id="awesome-json" data-awesome='{"game":"on"}'></div>

你可以通过js直接访问这个数据,通过json的key值,你能得到相应的value:

1
2
var gameStatus= jQuery("#awesome-json").data('awesome').game;
console.log(gameStatus);

你也可以通过.data(key,value)方法直接给”data-“ 属性赋值。一个重要的你要注意的事情是,这些”data-“ 属性应该和它所在的元素有一定的关联,不要把它当成存放任意东西的存储工具。

译者补充:尽管”data-“ 是HTML5才出现的属性,但jquery是通用的,所以,在非HTML5的页面或浏览器里,你仍然可以使用.data(obj)方法来操作”data-“ 数据。

[英文原文:HTML 5 data-* attributes, how to use them and why ]

关于两者的区别,其实是很古老的问题。但是时至今日,由于各种网络误传以及一些不负责任的书籍误笔,仍然有相当多的人将伪类与伪元素混为一谈,甚至不乏很多CSS老手。早些年刚入行的时候,我自己也被深深误导,因为论坛里的帖子大多不关心这种概念的细微差别,即使有人出来说一句:“这两个是不同的”,也只是被更多的帖子淹没掉而已。所以觉得有必要写下这些我所知的部分,这里着重写的是为什么这两者不同,以及一些平时容易错过的细节。

无论是伪类还是伪元素,都属于CSS选择器的范畴。所以它们的定义可以在CSS标准的选择器章节找到。分别是 CSS2.1 Selectors 和 CSS Selector Level 3,两者都已经是推荐标准。

标准的定义

在CSS2.1里,5.10 Pseudo-elements and pseudo-classes 描述了这两个概念的由来,它们是被一同提及的。但到了 Selector Level 3 里,它们就被分开到两个小节里加以区分。但无论如何,伪类和伪元素的引入都是因为在文档树里有些信息无法被充分描述,比如CSS没有“段落的第一行”之类的选择器,而这在一些出版场景里又是必须的。用标准里的话说:

CSS introduces the concepts of pseudo-elements and pseudo-classes to permit formatting based on information that lies outside the document tree.
简单翻译一下,就是:
CSS 引入伪类和伪元素的概念是为了实现基于文档树之外的信息的格式化
这么说很抽象,其实就是为了描述一些现有CSS无法描述的东西。缺少什么,则引入什么,不管是标准,还是人,都是如此成长而来。

伪类与伪元素的区别

这里我大可以列一个表格,把所有的伪类和伪元素分开罗列,但这未免太形式化,与其记住“哪些是哪些不是”,不如真正地加以区分。伪类和伪元素本身就有一个根本的不同之处,这点直接体现在了标准的描述语句上。

先看一个伪元素 first-line 例子。现在有一段HTML,内容是一个段落:

1
2
3
4
<p>I am the bone of my sword. Steel is my body, and fire is my blood. 
I have created over a thoustand blades.
Unknown to Death.Nor known to Life. Have withstood pain to create many weapon.
Yet, those hands will never hold anything. So as I pray, unlimited blade works.</p>

如果我要描述这个段落的第一行,在不用伪元素的情况下,我会怎么做?想来我一定要嵌套一层 span,然后加上类名:

1
2
3
4
<p><span class="first-line">I am the bone of my sword. Steel is my body, and fire is my blood. </span> 
I have created over a thoustand blades.
Unknown to Death.Nor known to Life. Have withstood pain to create many weapon.
Yet, those hands will never hold anything. So as I pray, unlimited blade works.</p>

再反观一个伪类 first-child 的例子,有一个简单的列表:

1
2
3
4
<ul>
<li></li>
<li></li>
</ul>

如果我要描述 ul 的第一个元素,我无须嵌套新的元素,我只须给第一个已经存在的 li 添加一个类名就可以了:

1
2
3
4
<ul>
<li class="first-child"></li>
<li></li>
</ul>

尽管,第一行第一个元素,这两者的语意相似,但最后作用的效果却完全不同。所以,伪类和伪元素的根本区别在于:它们是否创造了新的元素(抽象)。从我们模仿其意义的角度来看,如果需要添加新元素加以标识的,就是伪元素,反之,如果只需要在既有元素上添加类别的,就是伪类。而这也是为什么,标准精确地使用 “create” 一词来解释伪元素,而使用 “classify” 一词来解释伪类的原因。一个描述的是新创建出来的“幽灵”元素,另一个则是描述已经存在的符合“幽灵”类别的元素。

伪类一开始单单只是用来表示一些元素的动态状态,典型的就是链接的各个状态(LVHA)。随后CSS2标准扩展了其概念范围,使其成为了所有逻辑上存在但在文档树中却无须标识的“幽灵”分类。

伪元素则代表了某个元素的子元素,这个子元素虽然在逻辑上存在,但却并不实际存在于文档树中。

伪类和伪元素混淆的由来

最为混淆的,可能是大部分人都将 :before 和 :after 这样的伪元素随口叫做伪类,而且即使在概念混淆的情况下,实际使用上也毫无问题——因为即使概念混淆,对真正使用也不会造成多少麻烦:)

CSS Selector Level 3 为了区分这两者的混淆,而特意用冒号加以区分:

  • 伪类用一个冒号表示 :first-child
  • 伪元素则使用两个冒号表示 ::first-line
    并且规定,浏览器既要兼容CSS1和2里既存的伪元素的单冒号表示,同时又要不兼容CSS3新引入的伪元素的单冒号表示。后来的结果大家都知道,因为低版本IE对双冒号的兼容问题,几乎所有的CSSer在写样式的时候都不约而同的使用了单冒号。这无形中,让这种混淆延续了下来。而CSS3新伪元素的使用到目前为止,还远远不成气候。

伪类和伪元素使用上需要注意的地方

明白其不同之后,就需要注意和考虑在实际使用上的一些问题。比如:伪类和伪元素的选择器特殊性(优先级)如何计算?

我在之前的 CSS选择器距离无关 一文中,翻译过CSS标准的计算选择器的特殊性这一部分,看完那部分,答案就清楚了:除了否定伪类的特殊规定外,分开各自作为真正的类和元素计算

虽然标准以后的版本可能会允许选择器多伪元素的情况,但就目前为止,伪元素在一个选择器里只能出现一次,并且只能出现在末尾。实则,伪元素是选中了某个元素的符合逻辑的某个实际却不存在的部分,所以应用中也不会有人将其误写成多个。伪类则是像真正的类一样发挥着类的作用,没有数量上的限制,只要不是相互排斥的伪类,也可以同时使用在相同的元素上。关于CSS3选择器的详细解释,推荐 rogerjohansson 的 CSS 3 selectors explained

结束语

本来只是想稍稍写点,不想话又多了…到了最后,我一度觉得自己还漏了很多,不断在脑海里搜索,但可能只能下次在补充了。写这篇的目的是为下篇《CSS伪类与CSS伪元素的典型应用》做个铺垫,不想理论的东西一写自己就开始废话连篇了,惭愧…回看本篇,自己的思路跳的有些乱了,洋洋洒洒这么多字,可能概括起来没几句话,但如果希望尽可能表达清楚,则又免不了冗余过头。理论总是显得枯燥了些,下篇闲谈应用应该不至于这么沉闷:)

参考资料

  1. CSS2.1 Pseudo-elements and pseudo-classes from W3C
  2. Selectors Level 3 W3C Recommendation 29 September 2011 from W3C
  3. Difference between a pseudo-class and a pseudo-element by Laura L. Carlson
  4. THE DIFFERENCE BETWEEN PSEUDO-CLASSES AND PSEUDO-ELEMENTS by Stephan Muller

useradd -M -s /sbin/nologin -n username

passwd username

输入两次密码就行了,然后你就可以使用了。可以使用myentunnela或者BitviseSSHClient。

清明:

晴,天气相比前几天比较热。与同事去动物园玩玩,人人人人人人人人动物人人人人人人人人人人人。

没回家有点遗憾,不过后来证实回家也须更不好。

有些人与你的距离越来越远了。

那些逝去的人,今天会想起你们,曾经的岁月我们那样年轻。现在

目前的状态不是很好,,,

郑州动物园

[caption id=”attachment_313582” align=”aligncenter” width=”3264”]郑州动物园 郑州动物园[/caption]

最近在做关于google maps 的开发,遇到一些只有回调函数没有返回值的函数,但又必须得到返回值,找了很多资料终于解决了问题,需要再写个函数,在回调函数中获取。

原文在这儿:http://stackoverflow.com/questions/2993563/how-do-i-return-a-variable-from-google-maps-javascript-geocoder-callback

这是一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
var geocoder;
function initialize() {
geocoder = new google.maps.Geocoder();
var latlng = new google.maps.LatLng(40.730885,-73.997383);
codeLatLng(function(addr){
alert(addr);
});
}

function codeLatLng(callback) {
var latlng = new google.maps.LatLng(40.730885,-73.997383);
if (geocoder) {
geocoder.geocode({'latLng': latlng}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
if (results[1]) {
callback(results[1].formatted_address);
} else {
alert("No results found");
}
} else {
alert("Geocoder failed due to: " + status);
}
});
}

jquery在ajax方面是非常强大和方便的,以下是jquery进行ajax请求时方法模板:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$.ajax({
type: "get",
url: "",
data : {},
beforeSend : function(){

},
success : function(data){

},
complete : function(){

}
});

jquery的ajax方法的全部全局事件:

  • ajaxStart:ajax请求开始前
  • ajaxSend:ajax请求时
  • ajaxSuccess:ajax获取数据后
  • ajaxComplete:ajax请求完成时
  • ajaxError:ajax请求发生错误后
  • ajaxStop:ajax请求停止后

当你使用jquery的ajax方法,不管是$.ajax()、$.get()、$.load()、$.getJSON()等都会默认触发全局事件,只是通常不绑定全局事件,但实际上这些全局事件非常有用处。

ajax方法的全局事件的用处

ajax全局事件,有个典型的应用场合:
你的页面存在多个甚至为数不少的ajax请求,但是这些ajax请求都有相同的消息机制。ajax请求开始前显示一个提示框,提示“正在读取数据“;ajax请求成功时提示框显示“数据获取成功”;ajax请求结束后隐藏提示框。

不使用全局事件的做法是:

给$.ajax()加上beforeSend、success、complete回调函数,在回调函数中加上处理提示框。

使用全局事件的做法是:

1
2
3
4
5
6
7
8
9
10
11
12
13
$(document).ajaxStart(onStart)
.ajaxComplete(onComplete)
.ajaxSuccess(onSuccess);

function onStart(event) {
//.....
}
function onComplete(event, xhr, settings) {
//.....
}
function onSuccess(event, xhr, settings) {
//.....
}

ajax方法完整事件流

为了更直观的说明,明河使用Axure画了二个流程图,画的不好还请见谅,O(∩_∩)O

ajax方法完整事件流演示

为了让朋友更容易理解整个事件流,明河做了以下demo。

原文:http://www.36ria.com/2882

$.post 最终还是 $.ajax 实现的.

详见如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
post: function( url, data, callback, type ) {
if ( jQuery.isFunction( data ) ) {
callback = data;
data = {};
}

return jQuery.ajax({
type: "POST",
url: url,
data: data,
success: callback,
dataType: type
});
},
0%