在 mac 下安装 nodejs 相对来说是比较方便的,如果你之前安装过类似 Macports 或者homebrew 这样的工具,只需要简单的一句话就可以安装。如果使用的是 Macports,那么在终端执行如下命令即可:

1
brew install node

如果使用的是 homebrew,则执行下面的命令即可安装:

1
sudo port install nodejs

如果你没有使用过这两个工具,建议去尝试使用一下,可以像 linux 下面的 apt-get 一样安装软件,非常方便。

如果你还没有使用过这两个工具,那么就只能手动安装了。Mac 下默认没有安装 gcc,无法直接从源码编译安装,laser 尝试了单独安装 gcc 的方法,没有成功。最好的建议是直接从 AppStore 下载安装 Xcode,安装之后常用的开发工具包就都有了。不过下载 Xcode 时间比较长,网速比较好的话可能也要 4 个小时以上。

安装好 Xcode 后,系统就有了 gcc 的功能,下面可以继续安装 git,从 Git clone 下来源码进行编译安装。关于 Git 是什么和如何安装 Git,网上已经有无数的资料,laser 这里就不再赘述了,推荐去看 Github 的帮助文档,讲解很详细,只不过是英文的。从 Git 安装的步骤如下:

1
2
3
4
5
git clone https://github.com/joyent/node.git nodejs
cd nodejs
./configure
make
sudo make install

等待命令成功执行即安装完成了。

如果你没有安装 Git,那么也可以直接下载 nodejs 的源码 ,解压缩后放到合适的路径,然后进入该文件夹,仍然执行:

1
2
3
4
cd nodejs
./configure
make
sudo make install

即可安装。

posted @ 2012-02-05 21:35 姬光 阅读(41) 评论(0) 编辑

This is a brief introducion of Javascript Regular Expressions, hope it will helps.

More:
posted @ 2012-02-05 21:33 姬光 阅读(7) 评论(0) 编辑

mac的几个功能键可以组合出各种快速操作,下面详细介绍:

操作:Ctrl+Shift+Eject

作用:关闭显示器休眠,如果在“系统偏好设置” –> “安全性”中有设定进入睡眠后唤醒要输入密码,就等于是锁屏

操作:Option+Command+Eject

作用:让Mac直接进入睡眠状态

操作:Ctrl+Option+Command+Eject

作用:直接关机

操作:Control+Eject

作用:选择重启、睡眠、关机的对话框

操作:Control+Command+Eject

作用:退出所有应用程序,并重新启动计算机

posted @ 2012-02-05 21:32 姬光 阅读(30) 评论(0) 编辑

Intellij IDEA 是一款非常强大到跨平台的IDE,可以在任何主流操作系统中使用并且保证一致的操作习惯。但是这款优秀的IDE的相关中文教程却少得可怜,大部分使用者都是在慢慢摸索、互相学习才得以熟练使用。

这里laser介绍一下 FTP 服务器自动同步的配置和一些注意事项,希望能对你有所帮助。

首先前提是你已经创建了一个本地的工程,然后假设我在工程目录里新建一个文件夹叫做wordpress,我们将用它来同步我的 FTP 服务器上的文件。

打开“Tools -> Deployment -> Configuration…”,然后点击左上角的小加号新建一个服务器,在“Connection”页卡下填好各项参数。

填写完“FTP host”和“User name”、“Password”之后,可以选择“Test FTP connection…”测试一下设置是否正确,如果提示“Successfully connected to xx.xx.xx.xx”则说明连接成功。

还有一项“Root path”可以选择“Autodetect…”,但要注意一定要在连接测试成功以后才能点,你也可以点击旁边的省略号按钮,手动指定“Root path”。

注意:这里有的FTP服务器无法自动检测,当点击旁边的省略号按钮时也无法列出服务器文件目录,这时你需要点击“Advanced options…”,然后将“Passiv mode”勾选上即可。

填完这些以后我们就有了一个有效的服务器连接了,下面转到“Mappings”页卡,这里有三个输入框,第一个“Local path”当然就是你本地的路径了,你可以点省略号按钮,选择刚刚创建的wordpress目录。

第二个输入框是“Deployment path on server ‘xxx’”,这个就是你希望部署在服务器上的哪个目录,一般跟“Connection”页卡下的“Root path”是相同的,如果是默认的根目录就是一个斜杠“/”。当然你也可以部署到其他目录。这个目录部署后,本地的 wordpress 文件夹里面的文件,在上传时就会保存到这个目录中。

第三个输入框是“Web path on server ‘xxx’”,这个是通过你的网址可以访问到的路径,因为有的时候部署的路径不一定是实际的访问路径。如果部署的路径与实际的访问路径相同,则此处只填一个英文句点“.”即可,代表当前路径。

当完成这些以后,点击下方的“Apply”,然后点“Ok”关闭对话框。

这时,在Project列表中右键点击创建的wordpress文件夹,应该会多出一个“Deployment”选项,里面的子选项即为上传和下载文件或目录,这说明本地的文件夹已经和 FTP 服务器上的路径建立了联系。

如果想要设置在本地保存后自动同步到 FTP 服务器,可以先左键单击 wordpress 目录,然后选择“Tools -> Deployment -> Configuration…”打开刚才设置服务器的对话框,在左侧选择此服务器,然后单击上方四个小图标最右侧服务器模样的图标,点击后可以看到服务器的名字加粗了,这样就将该服务器设置成了wordpress目录首要使用的服务器连接,完成后关闭对话框。

再次打开“Tools -> Deployment ”,单击下方的“Automatic Upload”,这样就完成了自动同步的设置,当本地的 wordpress 目录中有文件修改并保存时,将自动同步到服务器(前提是本地与服务器上目录结构一致且文件名相同)。

posted @ 2012-02-05 21:31 姬光 阅读(26) 评论(0) 编辑

mac系统的Finder中默认是不显示隐藏文件的,搜索也搜不到。下面介绍两种显示和隐藏文件的办法。

打开终端,通过下面的两行命令可以控制是否显示隐藏文件,注意大小写:

显示Mac隐藏文件的命令:

1
defaults write com.apple.finder AppleShowAllFiles -bool true

隐藏Mac隐藏文件的命令:

1
defaults write com.apple.finder AppleShowAllFiles -bool false

键入相应命令后回车,然后关闭终端并重启Finder后才能生效。

另外还有一条终端命令可以直接控制文件或文件夹的显隐:

隐藏文件/文件夹命令:

1
chflags hidden (文件/文件夹的相对或绝对路径)

例如输入:

1
chflags hidden /Users/jiguang/Desktop/test

就可以隐藏桌面上的test文件夹

显示文件/文件夹命令:

1
chflags nohidden (文件/文件夹的相对或绝对路径)

例如输入:

1
chflags nohidden /Users/jiguang/Desktop/test

就可以显示刚才隐藏掉的test文件夹了。

这两种方法都只是设置Finder中的文件的显隐的,对于会使用终端的同学就不管用了。所以,还是换个地方把苍井空天海翼小泽玛利亚等姐妹们好好保管吧。

posted @ 2012-02-05 21:30 姬光 阅读(40) 评论(0) 编辑

原文链接:http://www.codeproject.com/KB/solution-center/HTML5-Web-Workers.aspx

很明显html5的应用是用JavaScript写的,但是跟其他的开发环境相比(例如一些原生的),JavaScript一直有个很严重的局限性:它的所有执行进程都在同一个线程里。

这对于如今像i5/i7这种动辄就8个CPU的多核处理器就有些麻烦了,即使最新的ARM手机处理器也都是双核或者4核。如果顺利的话,我们有望看到HTML5为Web开发提供一个应对这些又新又强劲的处理器的途径,让我们可以拥抱一个Web应用开发的新时代。

原文插图1

在没有 Workers 之前

这个JavaScript的局限性意味着一个长时间运行的进程会冻结主窗口。我们常说我们被“UI 线程”阻塞。这是由于主线程在处理所有的可视化元素及其相关任务:绘制,刷新,动画,用户输入事件等等。

我们都知道这个线程过载的严重后果:页面冻结并且用户不能再与你的应用进行交互了。当然,这时的用户体验那是相当差了,并且用户可能决定关掉这个Tab或者整个浏览器,你可能不希望看到这发生在你的app上。

为了避免发生这种情况,浏览器已经引入一种保护机制,当一个脚本有可能长时间运行时,可以对用户进行警告。

悲剧的是,这种机制并不能正确分辨究竟一段脚本是编写有问题,还是它确实需要更多的时间来完成它的工作。尽管如此,由于它阻塞了UI线程,所以还是让你知道有可能现在有错误发生的比较好。下面是一些消息的例子(从Firefox 5 和 IE9 获得):

原文插图

原文插图

迄今为止,由于以下两个原因,那些问题已经很少发生了:

  1. HTML和JavaScript已经与原来的使用方式不同了,而且使用的目的也不同了,因为其他的技术可以完成多线程的任务。与本地的应用相比,网站也没有提供更丰富的体验。
  2. 总有一些其他的办法可以或多或少地解决这些并发问题。

那些办法都是Web开发者所熟知的。例如,通过 setTimeout() 和 setInterval()方法,我们可以试图模拟并行任务。通过 XMLHttpRequest对象,也可以异步地处理HTTP请求,避免了从远程服务器载入资源时冻结UI。最后,应用DOM事件写出的应用程序给人一种错觉,让人误以为几个事件在同时发生。真的是错觉吗?是的!

为了更好的理解其原理,让我们来看一段伪代码并且看看在浏览器内部究竟发生了什么:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<script type="text/javascript">
function init(){
{ piece of code taking 5ms to be executed }
A mouseClickEvent is raised
{ piece of code taking 5ms to be executed }
setInterval(timerTask,"10");
{ piece of code taking 5ms to be executed }
 }
function handleMouseClick(){
piece of code taking 8ms to be executed
}
function timerTask(){
piece of code taking 2ms to be executed
}
</script>

让我们为这段代码建立一个模型。这个图表向我们展示了一个时间段内浏览器内部究竟发生了什么:

原文插图

这个图表很好地诠释了我们的任务的非并行本质。5毫秒后,用户产生一个鼠标点击事件。然而,由于init()方法仍然在执行,并且独占了主线程,所以这个事件不能被立即处理。点击事件将被保存并且延迟处理。

从5毫秒到10毫秒之间:init()方法在这5毫秒中仍然执行,然后在10毫秒时请求调用 timerTask() 这个方法。这个方法理论上应该在20毫秒的时间点执行。

从10毫秒到15毫秒之间:init()方法仍然需要5毫秒来完成运行。这与15毫秒时的黄色区块相对应。由于我们冻结了主线程,所以浏览器现在才可以继续进行刚才保存的请求。

从15毫秒到23毫秒之间:浏览器开始执行handleMouseClick()方法,该方法执行了8毫秒(蓝色区块)。

从23毫秒到25毫秒之间:作为一个副作用,在20毫秒时间点就应该执行的timerTask()方法被稍微平移了3毫秒。而其他的时间点,被当作没有代码占用CPU。

注意:这个例子和上面的图表(通过特征监测机制判断使用SVG或者PNG)是受到这篇文章的启发:HTML5 Web Workers Multithreading in JavaScript

所有这些提示并没有解决我们最初的问题:所有东西都在主UI线程里执行。

此外,即使JavaScript还没有被用来开发像其他“高级语言”一样的应用,它仍然在随着HTML5和其相关技术所提供的新的可能而改变。因此给JavaScript赋予更多新的能力,使之能够建立新一代的能够处理并行任务的应用,就变得更加重要了。这就是为什么我们有了Web Workers。

Web Workers 或者 如何在UI线程执行代码

Web Workers APIs定义了一个在后台运行脚本的方法。你可以执行一些存活在主页面之外的线程而不影响页面的绘制性能。然而,同样的方式,我们知道不是所有的算法都能并行执行的,也不是所有的JavaScript代码都能从Workers中受益。Ok,唠叨的够多了,让我们看看这些著名的Workers。

我的第一个Web Worker

由于Web Workers将在一个独立的线程里执行,你必须把代码从主页面中分离出来,放到独立的文件中。完成这些后,你需要实例化一个Worker对象来调用它们:

1
var myHelloWorker = new Worker('helloworkers.js');

然后你就可以给它发送一条信息来开启Worker(因此也开启了一个窗口之外的线程):

1
myHelloWorker.postMessage();

的确,Web Workers和主页面通过消息进行通信。这些消息可以是一般的字符串或者JSON对象。为了演示简单的消息发送,我们来review一个非常基础的例子。这个例子会发送一个字符串给worker,将其与worker联系起来。首先,将下面代码放到“ helloworker.js”文件中:

1
2
3
4
5
6
7
8
function messageHandler(event) {
// Accessing to the message data sent by the main page var messageSent = event.data;
// Preparing the message that we will send back
var messageReturned = "Hello " + messageSent + " from a separate thread!";
// Posting back the message to the main page this.postMessage(messageReturned);
}
// Defining the callback function raised when the main page will call us
this.addEventListener('message', messageHandler, false);

我们只在“helloworkers.js”中定义了一小段将在另一个线程执行的代码。它可以从你的主页面接收消息,在上面完成一些任务,并且向你的主页面返回一个消息。然后我们需要在主页面编写一个接收者。下面是处理消息的页面:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<!DOCTYPE html>
<html>
<head>
<title>Hello Web Workers</title>
</head>
<body>
<div id="output"></div>
<script type="text/javascript">
// Instantiating the Worker
var myHelloWorker = new Worker('helloworkers.js');
// Getting ready to handle the message sent back
// by the worker myHelloWorker.addEventListener("message", function (event) {
document.getElementById("output").textContent = event.data;
}, false);
// Starting the worker by sending a first message
myHelloWorker.postMessage("David");
// Stopping the worker via the terminate() command myHelloWorker.terminate();
</script>
</body>
</html>

运行的结果将是:”Hello David from a separate thread!”,你被打动了,有木有?

你要注意worker会一直存活直到你终止它。

既然没有自动垃圾收集,那么控制它们的状态就全靠你自己了。并且你要记住,初始化一个worker会消耗一定的内存…而且也不要忽略冷启动时间。要想停止一个worker,有两种可能的方式:

  1. 从主调用页面调用terminate()命令。
  2. 在worker内部通过调用close()命令。

演示:你可以在浏览器中测试这个稍微增强了一点的例子:
http://david.blob.core.windows.net/html5/HelloWebWorkers_EN.htm

通过JSON发送消息

当然,大多数时候我们会发送更加结构化的数据给Workers。(顺便说一下,Web Workers也可以通过Message channels进行通讯)

但是使用JSON格式是唯一可以给worker发送结构化消息的方法。幸运的是,浏览器现在支持worker的程度已经与原生支持JSON的程度一样好了。他们真是太好了!

让我们拿出之前的代码例子。我们打算增加一个WorkerMessage类型的对象。这种类型将被用来向Web Workers发送一些带参数的命令。

我们使用下面这个简化版的HelloWebWorkersJSON_EN.htm页面:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!DOCTYPE html>
<html>
<head>
<title>Hello Web Workers</title>
</head>
<body>
<div id="output"></div>
<script type="text/javascript">
// Instantiating the Worker
var myHelloWorker = new Worker('helloworkers.js');
// Getting ready to handle the message sent back
// by the worker
myHelloWorker.addEventListener("message", function (event) {
document.getElementById("output").textContent = event.data;
}, false);
// Starting the worker by sending a first message
myHelloWorker.postMessage("David");
// Stopping the worker via the terminate() command
myHelloWorker.terminate();
</script>
</body>
</html>

我们使用一种非侵入式的JavaScript方法来帮助我们分离表现层和逻辑层。然后绑定的逻辑就存在于HelloWebWorkersJSON_EN.js文件中:

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
36
37
38
39
// HelloWebWorkersJSON_EN.js associated to HelloWebWorkersJSON_EN.htm
// Our WorkerMessage object will be automatically
// serialized and de-serialized by the native JSON parser
function WorkerMessage(cmd, parameter) {
this.cmd = cmd; this.parameter = parameter;
}
// Output div where the messages sent back by the worker will be displayed
var _output = document.getElementById("output");
/* Checking if Web Workers are supported by the browser */
if (window.Worker) {
// Getting references to the 3 other HTML elements
var _btnSubmit = document.getElementById("btnSubmit");
var _inputForWorker = document.getElementById("inputForWorker");
var _killWorker = document.getElementById("killWorker");
// Instantiating the Worker
var myHelloWorker = new Worker('helloworkersJSON_EN.js');
// Getting ready to handle the message sent back
// by the worker
myHelloWorker.addEventListener("message", function (event) {
_output.textContent = event.data;
}, false);
// Starting the worker by sending it the 'init' command
myHelloWorker.postMessage(new WorkerMessage('init', null));
// Adding the OnClick event to the Submit button
// which will send some messages to the worker
_btnSubmit.addEventListener("click", function (event) {
// We're now sending messages via the 'hello' command
myHelloWorker.postMessage(new WorkerMessage('hello', _inputForWorker.value));
}, false);
// Adding the OnClick event to the Kill button
// which will stop the worker. It won't be usable anymore after that.
_killWorker.addEventListener("click", function (event) {
// Stopping the worker via the terminate() command
myHelloWorker.terminate();
_output.textContent = "The worker has been stopped.";
}, false);
} else {
_output.innerHTML = "Web Workers are not supported by your browser. Try with IE10: <a href=\"http://ie.microsoft.com/testdrive\">download the latest IE10 Platform Preview</a>";
}

再次说明,这个例子是非常基础的。但是,它可以帮助你理解背后的逻辑。当然,没人能阻止你发送一些可以被人工智能或者物理引擎处理的游戏元素。

演示:你可以在这儿测试JSON的例子:
http://david.blob.core.windows.net/html5/HelloWebWorkersJSON_EN.htm

浏览器支持

Web Workers刚刚出现在IE10平台预览版。Firefox(3.6以上),Safari(4.0以上),Chrome和Opera11也都支持。然而,这些浏览器的手机版并不支持。如果你想获得更详尽的浏览器支持列表,可以看看这里:http://caniuse.com/#search=worker

为了实时地了解你的代码的支持情况,请使用特性监测机制。(你不应该使用神马用户代理嗅探!)

为了帮助你实现,这里有2个可用的解决方案。第一个是用这样一小段代码,你自己简单地测试特性:


 

1
/* Checking if Web Workers are supported by the browser */ if (window.Worker) { // Code using the Web Workers }

第二个是使用著名的Modernizr库(现在已经原生的移到了ASP.NET的MVC3项目模版中)。然后,只要用下面这样一段代码:

1
2
3
4
5
6
7
8
<script type="text/javascript">
 var divWebWorker = document.getElementById("webWorkers");
if (Modernizr.webworkers) {
divWebWorker.innerHTML = "Web Workers ARE supported";
} else {
divWebWorker.innerHTML = "Web Workers ARE NOT supported";
}
</script>

例如,这里就是你的浏览器支持情况:Web Workers are not supported inside your browser.(原文页面对当前浏览器支持情况进行监测并将结果展示在这里。译者注。)

这将使你的应用产生两个版本。如果Web Workers不被支持,你就正常执行你的JavaScript代码。如果是在大多数现代浏览器中,Web Workers是被支持的,你就可以推送一些JavaScript代码给workers用来加强你的应用的性能。这样你就不必中断任何事情或者仅仅为最新的浏览器单独建立一个版本了。它在全部浏览器中都能工作,只是性能稍有差别。

Worker不能访问的元素(Worker不能干什么)

与其看看你用Workers不能干什么,不如让我们了解一下你只能用worker干点儿什么:

(下面是几个表格)

Method Description
void close(); Terminates the worker thread.
void importScripts(urls); A comma-separated list of additional JavaScript files.
void postMessage(data); Sends a message to or from the worker thread.

Attributes Type Description
location WorkerLocation Represents an absolute URL, including protocol, host, port, hostname, pathname, search, and hash components.
navigator WorkerNavigator Represents the identity and onLine state of the user agent client.
self WorkerGlobalScope The worker scope, which includes the WorkerLocation and WorkerNavigator objects.

Event Description
onerror A runtime error occurred.
onmessage Message data received.

Method Description
void clearInterval(handle); Cancels a timeout identified by handle.
void clearTimeout(handle); Cancels a timeout identified by handle.
long setInterval(handler, timeout value, arguments); Schedules a timeout to be run repeatedly after the specified number of milliseconds. Note that you can now pass additional arguments directly to the handler. If handler is a DOMString, it is compiled as JavaScript. Returns a handle to the timeout. Clear with clearInterval.
long setTimeout(handler, timeout value, arguments); Schedules a timeout to run after the specified number of milliseconds. Note that you can now pass additional arguments directly to the handler. If handler is a DOMString, it is compiled as JavaScript. Returns a handle to the timeout. Clear with clearTimeout.

注意:这些表格是从MSDN文档中引用的:HTML5 Web Worker

总之,你没有操作DOM的权限。这有一个非常好的图表作为总结:

原文配图

例如,既然你在worker中没有对window对象的操作权限,你就不能操作本地存储(Local Storage,反正看起来也不像线程安全的)。那些限制对于在其他环境中使用多线程操作的开发者来说或许看起来过于严格了。然而,最大的优点是我们不会陷入我们经常遇到的问题:死锁,竞争条件等。对于这些,在Web Workers中我们都不用考虑。这使得当使用Web Workers在一些特殊的场景中允许一些有趣的性能增强时变得非常好用。

错误处理与调试

处理Web Workers的错误非常容易。你只需要用与注册OnMessage事件同样方法注册一个OnError事件即可:


 

1
myWorker.addEventListener("error", function (event) { _output.textContent = event.data; }, false);

这是Web Worker能给你的帮助你调试代码的最好的原生支持了…不过这个非常有限不是吗?

通过F12开发工具获得更好的调试体验

为了突破这些局限,IE10在它的脚本调试器中为你提供了一个直接调试Web Workers代码的功能,就像调试其他脚本一样。

对此,你需要通过F12健运行开发者工具栏,并且点击“脚本“页卡。你应该还看不到与你的worker相关的JS文件。但是一旦点击”开始调试“按钮,它就应该神奇地出现了:

原文配图

下一步就是像调试你以往的JavaScript代码一样调试你的worker了!

原文配图

IE10是目前唯一支持这样调试的浏览器。如果你想了解更多关于这个特性的细节,你可以读一下这篇文章:Debugging Web Workers in IE10

一个用来模拟console.log()的有趣方法

最后,你要知道在worker中是不能使用console对象的。因此,如果你需要通过.log()方法来跟踪worker内部发生了什么,它将不会工作,因为console对象没有定义。幸好,我找到一个有趣的方法,通过MessageChannel:console.log() for Web Workers.可以模拟console.log()行为。该方法在IE10,Chrome和Opera中工作良好,但是在Firefox中还不行,因为Firefox还不支持MessageChannel。

注意:为了使这个链接中的例子在IE10下能工作,你需要把下面这行代码:

1
console.log.apply(console,args); // Pass the args to the real log

修改成:

1
console.log.apply(console, args); // Pass the args to the real log

然后,你应该可以得到这样的结果:

原文配图

例子:如果你想使用这个console.log()模拟,请到这里:http://david.blob.core.windows.net/html5/HelloWebWorkersJSONdebug.htm

用例分析与如何识别潜在的候选者(使用场景)

-Web Workers 用在什么场景?

当你在网上查找Web Workers的例子时,你总会找到一类的例子:强化的数学/科学计算。然后你会看到一些JavaScript光线跟踪,分形,素数之类的东西。虽然是理解Workers工作方式的很好的例子,但是很少能给我们一些关于如何在”真实的世界“中的应用中使用它们具体观点。

确实,我们上面所看到的这些Web Workers自身的不足缩小了能使用Web Workers的有趣场景的范围。尽管如此,如果你花点儿时间仔细想想,你就会发现一些新的有趣用途:

  • 图像处理 通过使用从&lt;canvas&gt;或者<video>元素中获取的数据。你可以把图像分割成几个不同的区域并且把它们推送给并行的不同Workers。这样你就会在新一代的多核处理器中受益。你受益越多,你运行的就越快。
  • 大量数据 检索,你需要在调用 XMLHTTPRequest后处理大量的数据。如果处理这些数据所需的时间长短非常重要,你最好在Web Worker中来做这些,避免冻结UI线程。这样你可以保持一个可交互的应用。
  • 背景数据分析:由于在使用Web Workers的时候,我们有更多潜在的CPU可用时间,我们现在可以考虑一下JavaScript中的新应用场景。例如,我们可以想像在不影响UI体验的情况下实时处理用户输入。利用这样一种可能,我们可以想像一个像Word(Office Web Apps 套装)一样的应用:当用户打字时后台在词典中进行查找,帮助用户自动纠错等等。
  • 针对本地数据的并发请求。IndexDB 将提供本地存储(Local Storage)所不能提供给我们的特性:一个针对Web Workers的线程安全的存储环境。

此外,如果你想转到视频游戏的世界,你可以考虑推送人工智能或者物理引擎的数据到Web Workers。例如,我做了这样一个小实验:On Web Workers, GWT, and a New Physics Demo ,该实验使用Box2D physic engine和Workers。对于你的人工智能引擎,这也意味着你可以使用同样的时间帧来处理更多的数据(例如在棋类游戏中预测更多的步数)。

我的一些同事或许会说唯一的限制就是你的想象力!

但是一般来说,只要你不需要DOM,任可能影响用户体验的耗时的JavaScript代码都是一个使用Web Workers很好的候选。然而,使用Workers时你还需要注意以下三点:

  1. worker的初始化时间和通讯时间不应该比自身的处理时间长。
  2. 使用多个Workers时的内存消耗。
  3. 代码块之间的依赖关系,你可能需要一些同步的逻辑。并行没那么简单我的朋友!

从我们的角度,我们最近发布了一个演示,叫做Web Workers Fountains:

原文配图

这个例子展示了一些颗粒效果(喷泉)并且对每个喷泉使用一个Web Worker来尽可能快地计算这些粒子。每个Worker的结果汇总后显示在<canvas>元素中。Web Workers也可以在通过 Message Channels 在它们之间交换信息。在该例中,这被用来询问每个Workers何时改变喷泉的颜色。我们之后循环这组颜色数组:红色,橙色,黄色,绿色,蓝色,紫色和粉色,这都归功于Message Channels。如果你对细节感兴趣,请跳到 Demo3.js 文件中的 LightManager() 函数部分。

而且,你可以在随意在 Internet Exploer 10 中运行这个例子,非常好玩!

如何识别你代码中的热点

为了追踪代码的瓶颈并且识别代码中的哪部分可以发送给Web Workers,你可以使用IE9/10中提供的F12工具栏里面的脚本探查器。它可以帮助你识别你代码中的热点。然而,识别一个热点并不意味着你已经找到一个适合Web Workers的好候选。为了更好地理解这些,我们来review两个有趣的案例。

案例1:<canvas>中的速读动画演示

这个演示是从 IE Test Drive获取的,并且可以直接在这儿找到:Speed Reading。该例试图使用<canvas>来尽可能快地显示字符。其目的是强调你的浏览器执行硬件加速层的质量。但是除此之外,把一些操作分割成线程能获得更好的性能吗?我们需要做一些分析来验证一下。

如果你在IE9/10中运行这个例子,你可以同时在几秒之内打开探查器。下面是你得到的结果:

enter image description here

如果你降序排列那些比较耗时的方法,你会清楚地看到那些最先出现的方法:DrawLoop(),Draw()和drawImage()。如果你双击Draw这一行,就会跳到这个方法对应的代码。你会看到几个这种类型的调用:


 

1
surface.drawImage(imgTile, 0, 0, 70, 100, this.left, this.top, this.width, this.height);

这里surface对象引用了一个<canvas>元素。

通过简短的分析,我们可以得到一个初步的结论,这个例子通过drawImage()方法花费了大部分的时间在Canvas内部绘图。由于Web Worker无法获取<canvas>元素,我们无法将这个耗时的任务分离到其他的线程中(例如我们可以想像一些并发处理<canvas>元素的方法)。这个例子就不是一个很好的用Web Workers处理并行的候选。

但是它很好地说明了你应该落实的操作过程。如果经过一些探查工作后,你发现耗时的脚本的主要部分与DOM对象紧密耦合,那么Web Workers就没办法帮你的Web app增强性能了。

案例2:<canvas>元素中的光线追踪

我们再举一个简单的例子帮助理解。我们拿一个这样的光线追踪的例子进行说明:Flog.RayTracer Canvas Demo。光线追踪使用一些CPU密集型的数学计算,据此来模拟光线的路径。这个主意是用来模拟一些诸如反射,折射,材质等效果的。

当我们运行脚本探察器时,你应该得到类似这样的结果:

原文配图

再一次的,如果我们降序排列这些方法,有2个方法明显地占用了大多数时间:renderScene()和getPixelColor()。

getPixelColor()方法的目的是计算当前的像素。光线追踪是一个像素一个像素的渲染场景。这个getPixelColor()方法之后再调用rayTrace()方法接管渲染阴影,环境光等等操作。这是我们的应用的核心部分。并且如果你review一下rayTrace()这个方法的代码,你就会发现它是100%原汁原味的JavaScript。这些代码没有任何DOM依赖。好吧,我相信你懂的:这个例子非常适合并行处理。此外,我们很容易将图像渲染拆分到几个线程中(也因此可能在几个CPU中),由于每个像素的计算之间没有同步进行的必要。每个像素的操作与它们的邻居是独立的,因为在本例中没有使用抗锯齿。

这样一来,如果我们发现一些使用Web Workers实现光线追踪的例子就不会奇怪了,比如这个:http://nerget.com/rayjs-mt/rayjs.html

使用IE10探查这个光线追踪例子,我们可以看出不使用Worker和使用4个Worker的显著区别:

enter image description here

在第一个截图中,processRenderCommand()方法几乎占据了全部可用CPU,并且场景绘制耗时2.854秒。

使用4个Web Workers之后,processRenderCommand()方法在4个并行的线程中执行。我们甚至可以在右侧一栏看到它们的Worker Id。这次场景绘制耗时1.473秒。受益是真实存在的:场景绘制快了一倍!

结论

关于Web Workers,没有什么神奇的或者新的概念用来回顾/构建你的JavaScript代码使之可以并行执行的。你需要将代码中的加强部分独立出来。它需要与你页面中的其他逻辑相对独立,避免等待同步的任务执行。并且最重要的部分是:代码不能跟DOM有耦合。如果所有这些条件都具备了,那就考虑一下Web Workers。它们绝对可以提高你的Web app的总体性能!

附加资源

这有一些有趣的附加资源,有兴趣可以读一下:

posted @ 2012-02-05 21:29 姬光 阅读(18) 评论(0) 编辑

原文链接:http://rogerdudler.github.com/git-guide/

git超简洁教程 ——只是初学者的简单教程,没有神马高深的。

安装

下载OSX平台的git:Download git for OSX

下载Windows平台的git:Download git for Windows

下载Linux平台的git:Download git for Linux

创建新分支

创建一个新目录,打开目录并执行

1
git init

来创建一个新的资源库(repository)。

检出分支

通过以下命令创建一个本地资源库(local repository)的工作副本(working copy):

1
git clone /path/to/repository

当使用远程服务器时,命令则为:

1
git clone username@host:/path/to/repository

工作流程

你的本地分支包含三个由git维护的“树”,第一个是你的工作目录(Working Directory),它保存着实际的文件;第二个是索引(Index),它的行为像是一个临时区域;最后一个是头(HEAD),它指向你的最后一次提交。

添加和提交

你可以使用下面的命令执行更改(添加到索引Index):

1
2
git add <filename>
git add *

这只git基本工作流的第一步,想确实提交这些更改要使用:

1
git commit -m "Commit message"

现在文件会被提交到头(HEAD),但是还没有到远程资源库(remote repository)中。

推入变更

你的更改现在在本地工作副本的头(HEAD)文件中,若想把更改发送到远程资源库,执行:

1
git push origin master

master可以改为任何你想要推入文件的资源库的名字。

如果你还没有克隆(clone)任何已存在的资源库,并且希望本地资源库连接到远程服务器,你需要用下面命令添加:

1
git remote add origin <server>

现在,你可以把你的更改推入选定的远程服务器了。

分支

分支(branch)是用来开发特性相互独立的部分,当创建一个资源库时,主(master)分支是默认的分支。可以使用其它分支进行开发,并在开发结束后合并到主分支。

创建一个名为“feature_x”的分支,并切换到该分支可以使用:

1
git checkout -b feature_x

可以再切回到主分支:

1
git checkout master

并且删除刚才创建的分支:

1
git branch -d feature_x

如果你不把分支推入到远程资源库的话,别人是无法使用该分支的:

1
git push origin <branch>

更新与合并

想要更新你的本地资源库到最新的提交,可以在你的本地资源库执行:

1
git pull

来抓取(fetch)和合并(merge)远程的更改。

要想合并其它分支到你的当前分支(active branch),比如主分支,使用:

1
git merge <branch>

在这两种情况下,git都会尝试自动合并更改。不幸的是,有时候这是不可能的,而且会导致冲突(conflicts)。这时你需要通过修改git所列出的文件来手动合并冲突,修改后,你需要将它们标记为已合并:

1
git add <filename>

在合并更改之前,也可以通过下列命令进行预览:

1
git diff <source_branch> <target_branch>

标签

我们最好为软件的版本创建标签(tag),这是已知的概念,在SVN中也存在。你可以通过执行下面的命令创建一个建一个名为1.0.0的新标签:

1
git tag 1.0.0 1b2e1d63ff

这个1b2e1d63ff 代表了你希望标签所引用的提交id(commit id)的前10个字符,你可以通过:

1
git log

来获取提交id,你也可以使用更少的字符作为提交id,只不过它必须是唯一的。

替换本地更改

万一你做错了什么(这肯定不会发生),你可以用下面的命令替换本地更改:

1
git checkout -- <filename>

这会用头(HEAD)文件中最后的内容来替换本地工作树(working tree)中的更改。已经添加到索引中的更改以及新文件都会被保留。

反之,如果你想放弃所有本地的更改和提交,可以抓取服务器最新的历史并将本地的主分支指向它,像这样:

1
2
git fetch origin
git reset --hard origin/master

有用的提示

内置的git图形界面(GUI):

1
gitk

使用彩色的git输出:

1
git config color.ui true

以每次提交单独一行的格式显示日志:

1
git config format.pretty oneline

使用交互的添加操作:

1
git add -i

链接及资源

图形客户端

指南及手册

posted @ 2012-02-05 21:28 姬光 阅读(23) 评论(0) 编辑

快速提示:为每个菜单项添加图像,并在鼠标悬停时滑出。

查看DEMO    下载源码

在这个叫做“提示与技巧”的分类中,我们会介绍一些关于Web开发和Web设计的简短有趣的方法。在今天的小提示中,我们会展示如何为菜单添加一个优美的悬停效果。主要的想法就是当鼠标悬停在菜单项时右侧滑出一个图片。

每个菜单项(在本例中是一个无序列表项)会包含一个含有两个 span 的锚点和一个图像:

1
2
3
4
5
6
7
8
9
10
<ul class="mh-menu">
    <li>
        <a href="#">
            <span>Art Director</span>
            <span>Henry James</span>
        </a>
        <img src="images/1.jpg" alt="image01"/>
    </li>
    <!-- ... -->
</ul>

我们会把 .mh-menu li a 设置成 display:block 并将背景设置为 rgba(255,255,255, 0.8) ,当鼠标悬停到列表项时,我们再把背景色设置成浅蓝色 rgba(225,239,240, 0.4)

1
2
3
.mh-menu li:hover a{
    background: rgba(225,239,240, 0.4);
}

第二个 span 在鼠标悬停时也会改变背景色,但我们希望不同的列表项能够显示不同的颜色,因此我们首先添加一个颜色渐变,然后使用 nth-child 选择器获取元素(有用的:nth-child秘方  ——译者注。):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
.mh-menu li a span:nth-child(2){
    /*...*/
    transition: color 0.2s linear;
}
.mh-menu li:nth-child(1):hover span:nth-child(2){
    color: #ae3637;
}
.mh-menu li:nth-child(2):hover span:nth-child(2){
    color: #c3d243;
}
.mh-menu li:nth-child(3):hover span:nth-child(2){
    color: #d38439;
}
.mh-menu li:nth-child(4):hover span:nth-child(2){
    color: #8e7463;
}

由于图像要滑到右侧,因此,首先它的 left 值必须是 0px,同时我们也为它的透明度添加一个渐变,它会从初始值 0 渐变到 1 :

1
2
3
4
5
6
7
8
9
10
11
12
.mh-menu li img{
    position: absolute;
    z-index: 1;
    left: 0px;
    top: 0px;
    opacity: 0;
    transition: left 0.4s ease-in-out, opacity 0.6s ease-in-out;
}
.mh-menu li:hover img{
    left: 300px;
    opacity: 1;
}

瞧,这样我们就有了一个很棒的滑出的效果了!

注意要确保锚点的 z-index 值比图像高一点儿,这样图像才会在锚点的下方滑出而不是在它的上面。

另外,我们还可以使背景色在悬浮的时候不透明,例如完全是白色(demo 2),或者为每个子元素设置不同的颜色(demo 3)。

本文中的演示由  Bartosz Kosowski  (CC BY-NC 3.0) 提供。

查看DEMO    下载源码

原文地址:http://tympanus.net/codrops/2012/01/22/how-to-spice-up-your-menu-with-css3/

posted @ 2012-02-05 21:23 姬光 阅读(13) 评论(0) 编辑

在刚刚发布的Firefox 10中新增了多个内置的Web开发工具,可以说目前来看基本都是鸡肋。对于习惯了Firebug的开发者来说,Firefox的这些工具简直太小儿科了!不过不能因为开始很鸡肋,就对它不理不睬,我们还是希望能够不断地有更加出色的Web开发工具出现的。

笔者也是带着好奇+折腾没够的心理,想看一看这货究竟有没有点儿长处。先来看看Page Inspector的截图吧:

 

图1:Firefox内置开发者工具截图

怎么样?很熟悉吧?

Firefox 10内置的这个工具目前只能查看HTML结构和CSS属性,对于HTML结构只能修改标签内的属性值,而不能修改文本内容。

对于CSS属性查看器,可以像Firebug一样增添属性或者修改属性值,也可以显示属性之间相互覆盖的情况。

这货不就是个精简版Firebug吗?是的!看样子是要跟Firebug抢饭碗啊,不过目前来看,这条路还长着呢。

那么,它究竟有没有点儿长处呢?经过笔者仔细查找,终于找到值得一提的一点长处了。在查看CSS的面板中,共有两个标签:Rules和Properties。

在Properties标签下可以查看或搜索应用在当前被检查的元素上的CSS属性,当鼠标悬浮到某个属性上时会出现一个小问号图标,点击此图标会直接跳到MDN上关于该属性的文档。因此,当你对某个属性不太熟悉时,可以直接点击这里查看文档,方便学习之用,这勉强算是一点儿优点吧。

另外,在Properties标签的搜索框旁边有个选项“Only user styles”,可以选择是否只显示用户样式。如果取消该选项,就可以看到许多浏览器内置的样式了,可以通过它来查看某些内置样式的值。

好了,我实在找不出其他有用的地方了!这里还有一个官方的视频,里面介绍的有些东西在Firefox 10里还没有,可以简单看一下。

对于Firefox本身,大家也可以关注一下它为开发者提供了哪些新的东西:Firefox 10 for developers 。

在前沿技术方面,Firefox 10还为开发者提供了全屏API,开发者可以开发以全屏模式运行的web应用。Firefox 10增加了对WebGL3D绘图标准的支持,并且支持CSS 3 3D Transform。这里有个原来只能在webkit运行的经典例子,现在也可以在Firefox 10运行了,不过看上去有点儿慢。

另外值得一提的是:Firefox 10明显改善了插件的兼容性问题,Mozilla能够自动检测服务器上插件的兼容性,在用户升级到Firefox 10时,此前的插件中的绝大部分都将标记为兼容插件。这就意味着自Firefox 10以后,插件开发者们就不用随着Firefox的每次升级而手动更改兼容版本号了。

有人说Firebug要危险了,不过笔者并不这么认为。Firebug的社区是非常强大而活跃的,还有很多坚决拥护Firebug的开发者,所以Firefox想把Firebug比下去还欠些火候。不过话说回来,如果Firefox真的能够开发出比Firebug更优秀更好用的产品,那么也不妨一试。

posted @ 2012-02-05 21:22 姬光 阅读(29) 评论(0) 编辑

小提示:本文提供的方法只能一定程度上防止通过feed采集的程序,对于直接采集文章页面的程序没有作用。

相信经常写博客的人都知道采集是怎么回事,网上有很多免费的或者付费的各种采集程序,可以采集文章、图片、下载内容等等,甚至还有各种明目张胆的小偷程序。做这种网站的目的很明显,就是不劳而获,通过采集文章,经过一定的伪原创处理将内容二次发布。其实现在很多门户网站也会这么做,只不多很多时候是靠人工的将文章“编译”一下,就作为原创了。

那么,对于那些坚持产出原创文章的博主,应该怎样防止被采集呢? 目前大部分的博客都是通过WordPress建立的,而Wordpress本身就可以安装各种采集插件(这里就不做介绍了),因而就有很多人直接用Wordpress来做采集站。当然,也有用其它博客程序或者CMS程序来做采集站的。 不过,一般的采集站都是以订阅feed为基础的,那么通过对feed进行一定的处理,就可以在某种程度上防止被采集程序强暴。

网上已经有一些Wordpress的防采集插件,有判断User-Agent的,有增加干扰文字的,这里就不做讨论了,有兴趣的同学可以搜一搜。这里有一篇水煮鱼的文章,年代久远了,不知是否还可用。

下面主要介绍几种对feed的处理办法:

将博客的feed设置只显示摘要,并增加“阅读全文”链接

通过这样的方法,采集程序只能采集到摘要部分,并含有“阅读全文”的链接。但是对于普通的订阅者,也只能看到这些了,那么这会不会造成不便呢?其实,让访问者打开你的网站阅读文章是可以提升用户体验的,你自己的排版设计等在阅读器中不一定能很好的展现,笔者就习惯在订阅器中看到好的文章时直接转到网站继续阅读。

具体做法:

1. 在Wordpress面板中,选择Settings(设置)- Reading Settings(阅读设置),选择下图中所示位置的 Summary(摘要),然后点击 Save Changes即可(中文版Wordpress可参照对应位置进行操作):

图1:将feed输出设置成只显示摘要

2. 在feed中加入”阅读全文“链接,找到你的模版文件中的functions.php,在<?php 和 ?> 之间添加以下代码:

1
2
3
4
5
/* RSS 中添加查看全文链接 @44ux.com */
function feed_read_more($content) {
    return $content . '<p><a rel="bookmark" href="'.get_permalink().'" target="_blank">阅读全文</a></p>';
}
add_filter ('the_excerpt_rss', 'feed_read_more');

保存后上传到服务器,覆盖原来的文件即可,这样在feed中就会显示”阅读全文“链接了。其实通过这种方式可以向feed中增添很多信息,甚至可以将Google Adsense的广告放进去,不过要小心,这样可能会引起订阅者的反感。

3. 还可以在feed中增添版权信息,让你的版权更加突出。同样是在functions.php中,增添以下代码(将版权信息改成你自己的)即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
/* RSS 中添加版权信息 @44ux.com */
function feed_copyright($content) {
     if(is_single() or is_feed()) {
          $content.= "<p class='copyright'>";
          $content.= '版权所有:<a title="Hi.laser! @44ux.com" href="http://www.44ux.com/">Hi,laser! @44ux.com</a> <a rel="bookmark" title="'.get_the_title().'" href="'.get_permalink().'">《'.get_the_title().'》</a><br />';
          $content.= '本文链接:<a rel="bookmark" title="'.get_the_title().'" href="'.get_permalink().'">'.get_permalink().'</a><br />';
          $content.= '特别声明:除特别标注,本站文章均为原创,遵循<a href="http://creativecommons.org/licenses/by-nc/3.0/deed.zh_HK" target="_blank">CC BY-NC 3.0</a>,转载请注明出处';
          $content.= "</p><br />";
     }
     return $content;
}
//add_filter ('the_content', 'feed_copyright'); //此句可像文章内容中添加版权
add_filter ('the_excerpt_rss', 'feed_copyright');

另外,顺便提一下,还有一些防止采集的方法,都各有利弊,这里简单列一下:

1、限制IP地址单位时间的访问次数

2、屏蔽ip

3、利用js加密网页内容

4、网页里隐藏网站版权或者一些随机垃圾文字,这些文字样式写在css中

5、用户登录才能访问网站内容

6、利用脚本语言做分页(隐藏分页)

7、防盗链措施(只允许通过本站页面连接查看,如:Request.ServerVariables(“HTTP_REFERER“)

8、全flash、图片或者pdf来呈现网站内容

9、网站随机采用不同模版

10、采用动态不规则的html标签

关于这几种方法,网上有相关文章详细讲解,这里不再赘述。

PS:关于采集一事要从两面来看,坚持产出原创文章确实很辛苦,但被人采集也说明文章还不错,我们只求能够拥有一个署名权而已。对于做垃圾站的人,也希望能够稍微保留一些原作者的权益。而对于专心经营博客的人来说,如果你不尊重别人文章的版权,如何能让别人来尊重你的呢?想要建立长久的影响的话,还是坚持原创吧。

posted @ 2012-02-05 21:15 姬光 阅读(659) 评论(2) 编辑