编程小贴士

给你的编程提供小点子


Javascript异步编程

JavaScript 异步编程简介

回调函数和异步执行

所谓的异步指的是函数的调用并不直接返回执行的结果,而往往是通过回调函数异步的执行。

我们先看看回调函数是什么:

?
1
2
3
4
5
6
7
8
9
10
11
12
var fn = function(callback) {
    // do something here
    ...
    callback.apply(this, para);
};
var mycallback = function(parameter) {
    // do someting in customer callback
};
// call the fn with callback as parameter
fn(mycallback);

回调函数,其实就是调用用户提供的函数,该函数往往是以参数的形式提供的。回调函数并不一定是异步执行的。比如上述的例子中,回调函数是被同步执行的。大部分语言都支持回调,C++可用通过函数指针或者回调对象,Java一般也是使用回调对象。

在Javascript中有很多通过回调函数来执行的异步调用,例如setTimeout()或者setInterval()。

?
1
2
3
setTimeout(function(){
    console.log("this will be exectued after 1 second!");
},1000);

在以上的例子中,setTimeout直接返回,匿名函数会在1000毫秒(不一定能保证是1000毫秒)后异步触发并执行,完成打印控制台的操作。也就 是说在异步操作的情境下,函数直接返回,把控制权交给回调函数,回调函数会在以后的某一个时间片被调度执行。那么为什么需要异步呢?为什么不能直接在当前 函数中完成操作呢?这就需要了解Javascript的线程模型了。

Javascript线程模型和事件驱动

Javascript最初是被设计成在浏览器中辅助提供HTML的交互功能。在浏览器中都包含一个Javascript引擎,Javscript程序就运 行在这个引擎之中,并且只有一个线程。单线程能都带来很多优点,程序员们可以很开心的不用去考虑诸如资源同步,死锁等多线程阻塞式编程所需要面对的恼人的 问题。但是很多人会问,既然Javascript是单线程的,那它又如何能够异步的执行呢?

这就需要了解到Javascript在浏览器中的事件驱动(event driven)机制。事件驱动一般通过事件循环(event loop)和事件队列(event queue)来实现的。假定浏览器中有一个专门用于事件调度的实例(该实例可以是一个线程,我们可以称之为事件分发线程event dispatch thread),该实例的工作就是一个不结束的循环,从事件队列中取出事件,处理所有很事件关联的回调函数(event handler)。注意回调函数是在Javascript的主线程中运行的,而非事件分发线程中,以保证事件处理不会发生阻塞。

Event Loop Code:

?
1
2
3
4
5
6
7
8
while(true) {
 var event = eventQueue.pop();
 if(event && event.handler) {
     event.handler.execute(); // execute the callback in Javascript thread
 } else {
     sleep(); //sleep some time to release the CPU do other stuff
 }
}

通过事件驱动机制,我们可以想象Javascript的编程模型就是响应一系列的事件,执行对应的回调函数。很多UI框架都采用这样的模型(例如Java Swing)。

那为什要异步呢,同步不是很好么?

异步的主要目的是处理非阻塞,在和HTML交互的过程中,会需要一些IO操作(典型的就是Ajax请求,脚本文件加载),如果这些操作是同步的,就会阻塞其它操作,用户的体验就是页面失去了响应。

综上所述Javascript通过事件驱动机制,在单线程模型下,以异步回调函数的形式来实现非阻塞的IO操作。

Javascript异步编程带来的挑战

Javascript的单线程模型有很多好处,但同时也带来了很多挑战。

代码可读性

想象一下,如果某个操作需要经过多个非阻塞的IO操作,每一个结果都是通过回调,程序有可能会看上去像这个样子。

?
1
2
3
4
5
6
7
8
9
10
11
operation1(function(err, result) {
    operation2(function(err, result) {
        operation3(function(err, result) {
            operation4(function(err, result) {
                operation5(function(err, result) {
                    // do something useful
                })
            })
        })
    })
})

我们称之为意大利面条式(spaghetti)的代码。这样的代码很难维护。这样的情况更多的会发生在server side的情况下。

流程控制

异步带来的另一个问题是流程控制,举个例子,我要访问三个网站的内容,当三个网站的内容都得到后,合并处理,然后发给后台。代码可以这样写:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var urls = ['url1','url2','url3'];
var result = [];
for (var i = 0, len = urls.length(); i < len; i++ ) {
    $.ajax({
        url: urls[i],
        context: document.body,
        success: function(){
          //do something on success
          result.push("one of the request done successfully");
          if (result.length === urls.length()) {
              //do something when all the request is completed successfully
          }
        }});
}

上述代码通过检查result的长度的方式来决定是否所有的请求都处理完成,这是一个很丑陋方法,也很不可靠。

异常和错误处理

通过上一个例子,我们还可以看出,为了使程序更健壮,我们还需要加入异常处理。 在异步的方式下,异常处理分布在不同的回调函数中,我们无法在调用的时候通过try…catch的方式来处理异常, 所以很难做到有效,清楚。

更好的Javascript异步编程方式

“这是最好的时代,也是最糟糕的时代”

为了解决Javascript异步编程带来的问题,很多的开发者做出了不同程度的努力,提供了很多不同的解决方案。然而面对如此众多的方案应该如何选择呢?我们这就来看看都有哪些可供选择的方案吧。

Promise

Promise 对象曾经以多种形式存在于很多语言中。这个词最先由C++工程师用在Xanadu 项目中,Xanadu 项目是Web 应用项目的先驱。随后Promise 被用在E编程语言中,这又激发了Python 开发人员的灵感,将它实现成了Twisted 框架的Deferred 对象。

2007 年,Promise 赶上了JavaScript 大潮,那时Dojo 框架刚从Twisted框架汲取灵感,新增了一个叫做dojo.Deferred 的对象。也就在那个时候,相对成熟的Dojo 框架与初出茅庐的jQuery 框架激烈地争夺着人气和名望。2009 年,Kris Zyp 有感于dojo.Deferred 的影响力提出了CommonJS 之Promises/A 规范。同年,Node.js 首次亮相。

在编程的概念中,future,promise,和delay表示同一个概念。Promise翻译成中文是“承诺”,也就是说给你一个东西,我保证未来能 够做到,但现在什么都没有。它用来表示异步操作返回的一个对象,该对象是用来获取未来的执行结果的一个代理,初始值不确定。许多语言都有对Promise 的支持。

Promise的核心是它的then方法,我们可以使用这个方法从异步操作中得到返回值,或者是异常。then有两个可选参数(有的实现是三个),分别处理成功和失败的情景。

?
1
2
var promise = doSomethingAync()
promise.then(onFulfilled, onRejected)

异步调用doSomethingAync返回一个Promise对象promise,调用promise的then方法来处理成功和失败。这看上去似乎并 没有很大的改进。仍然需要回调。但是和以前的区别在于,首先异步操作有了返回值,虽然该值只是一个对未来的承诺;其次通过使用then,程序员可以有效的 控制流程异常处理,决定如何使用这个来自未来的值。

对于嵌套的异步操作,有了Promise的支持,可以写成这样的链式操作:

?
1
2
3
4
5
6
7
8
9
10
11
operation1().then(function (result1) {
    return operation2(result1)
}).then(function (result2) {
    return operation3(result2);
}).then(function (result3) {
    return operation4(result3);
}).then(function (result4) {
    return operation5(result4)
}).then(function (result5) {
    //And so on
});

Promise提供更便捷的流程控制,例如Promise.all()可以解决需要并发的执行若干个异步操作,等所有操作完成后进行处理。

?
1
2
3
4
5
6
var p1 = async1();
var p2 = async2();
var p3 = async3();
Promise.all([p1,p2,p3]).then(function(){
    // do something when all three asychronized operation finished
});

对于异常处理,

?
1
2
3
4
5
doA()
  .then(doB)
  .then(null,function(error){
      // error handling here
  })

如果doA失败,它的Promise会被拒绝,处理链上的下一个onRejected会被调用,在这个例子中就是匿名函数function(error){}。比起原始的回调方式,不需要在每一步都对异常进行处理。这生了不少事。

以上只是对于Promise概念的简单陈述,Promise拥有许多不同规范建议(A,A+,B,KISS,C,D等),名字(Future,Promise,Defer),和开源实现。大家可以参考一下的这些链接。

  • jQuery’s Deferred Object
  • YUI Promise Class
  • Dojo Promises
  • Q
  • RSVP.js
  • When.js
  • MochiKit.Async
  • FutureJS
  • node-promise
  • WinJS

     

如果你有选择困难综合症,面对这么多的开源库不知道如何决断,先不要急,这还只是一部分,还有一些库没有或者不完全采用Promise的概念

Non-Promise

下面列出了其它的一些开源的库,也可以帮助解决Javascript中异步编程所遇到的诸多问题,它们的解决方案各不相同,我这里就不一一介绍了。大家有兴趣可以去看看或者试用一下。

  • Node-fibers
  • Streamlinejs
  • Step
  • Flow-js
  • Async
  • Async.js
  • slide-flow-control

Non-3rd Party

其实,为了解决Javascript异步编程带来的问题,不一定非要使用Promise或者其它的开源库,这些库提供了很好的模式,但是你也可以通过有针对性的设计来解决。

比如,对于层层回调的模式,可以利用消息机制来改写,假定你的系统中已经实现了消息机制,你的code可以写成这样:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
eventbus.on("init", function(){
    operationA(function(err,result){
        eventbus.dispatch("ACompleted");
    });
});
eventbus.on("ACompleted", function(){
    operationB(function(err,result){
        eventbus.dispatch("BCompleted");
    });
});
eventbus.on("BCompleted", function(){
    operationC(function(err,result){
        eventbus.dispatch("CCompleted");
    });
});
eventbus.on("CCompleted", function(){
    // do something when all operation completed
});

这样我们就把嵌套的异步调用,改写成了顺序执行的事件处理。

下一代Javscript对异步编程的增强

ECMAScript6

下一代的Javascript标准Harmony,也就是ECMAScript6正在酝酿中,它提出了许多新的语言特性,比如箭头函数、类(Class)、生成器(Generator)、Promise等等。其中Generator和Promise都可以被用于对异步调用的增强。

Nodejs的开发版V0.11已经可以支持ES6的一些新的特性,使用node –harmony命令来运行对ES6的支持。

co、Thunk、Koa

koa是由Express原班人马(主要是TJ)打造,希望提供一个更精简健壮的nodejs框架。koa依赖ES6中的Generator等新特性,所以必须运行在相应的Nodejs版本上。

利用Generator、coThunk,可以在Koa中有效的解决Javascript异步调用的各种问题。

co是一个异步流程简化的工具,它利用Generator把一层层嵌套的调用变成同步的写法。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var co = require('co');
var fs = require('fs');
var stat = function(path) {
  return function(cb){
    fs.stat(path,cb);
  }
};
var readFile = function(filename) {
  return function(cb){
    fs.readFile(filename,cb);
  }
};
co(function *() {
  var stat = yield stat('./README.md');
  var content = yield readFile('./README.md');
})();

通过co可以把异步的fs.readFile当成同步一样调用,只需要把异步函数fs.readFile用闭包的方式封装。

利用Thunk可以进一步简化为如下的code, 这里Thunk的作用就是用闭包封装异步函数,返回一个生成函数的函数,供生成器来调用。

?
1
2
3
4
5
6
7
8
9
10
11
var thunkify = require('thunkify');
var co = require('co');
var fs = require('fs');
var stat = thunkify(fs.stat);
var readFile = thunkify(fs.readFile);
co(function *() {
  var stat = yield stat('./README.md');
  var content = yield readFile('./README.md');
})();

利用co可以串行或者并行的执行异步调用。

串行

?
1
2
3
4
co(function *() {
  var a = yield request(a);
  var b = yield request(b);
})();

并行

?
1
2
3
co(function *() {
 var res = yield [request(a), request(b)];
})();

总结

异步编程带来的问题在客户端Javascript中并不明显,但随着服务器端Javascript越来越广的被使用,大量的异步IO操作使得该问题变得明 显。许多不同的方法都可以解决这个问题,本文讨论了一些方法,但并不深入。大家需要根据自己的情况选择一个适于自己的方法。

同时,随着ES6的定义,Javascript的语法变得越来越丰富,更多的功能带来了很多便利,然而原本简洁,单一目的的Javascript变得复杂,也要承担更多的任务。Javascript何去何从,让我们拭目以待。

124 Responses to “ Javascript异步编程 ”

  1. best pron说道:

    ojnRUg This can be the worst write-up of all, IaаАа’б‚Т€ТšаЂаŒаАа’б‚Т€ТžаБТžve study

  2. Looking forward to reading more. Great blog post. Keep writing.

  3. drawing说道:

    Thanks-a-mundo for the article.Much thanks again. Will read on

  4. We stumbled over here coming from a different web address and thought I may as well check things out. I like what I see so now i am following you. Look forward to looking into your web page yet again.

  5. Im thankful for the article.Much thanks again. Really Great.

  6. Some genuinely prime articles on this web site , saved to favorites.

  7. Your style is so unique in comparison to other folks I ave read stuff from. Thanks for posting when you have the opportunity, Guess I will just book mark this web site.

  8. Thanks for sharing, this is a fantastic blog post.Thanks Again. Really Great.

  9. Oluwadamilare说道:

    There are some lessons we have to drive the Muslims from its territory,

  10. This particular blog is without a doubt interesting and besides factual. I have picked up helluva interesting things out of this source. I ad love to return again soon. Thanks a lot!

  11. see this here说道:

    You have brought up a very good points , thanks for the post.

  12. that site What computer brands allow you to build your own computer?

  13. home说道:

    Souls in the Waves Very good Early morning, I just stopped in to visit your site and believed I would say I enjoyed myself.

  14. w88 world说道:

    Thank you for your blog article.Much thanks again. Will read on

  15. Thanks again for the blog.Much thanks again.

  16. Way cool! Some extremely valid points! I appreciate you penning this article and the rest of the site is very good.

  17. trap an hoi dep说道:

    I truly appreciate this blog. Really Great.

  18. private Hire说道:

    This is one awesome article.Much thanks again. Really Great.

  19. Way cool! Some very valid points! I appreciate you writing this article and also the rest of the website is very good.

  20. you ave gotten an ideal weblog right here! would you like to make some invite posts on my weblog?

  21. explore说道:

    Way cool! Some very valid points! I appreciate you writing this article and the rest of the website is also really good.

  22. we prefer to honor a lot of other world-wide-web web-sites around the web, even if they aren

  23. You are a great writer. Please keep it up!

  24. PhD Green Card说道:

    pasta maker home bargains WALSH | ENDORA

  25. Im obliged for the blog article.Much thanks again. Will read on

  26. Nwokolo说道:

    pretty useful stuff, overall I think this is really worth a bookmark, thanks

  27. vong nguyet que说道:

    Really enjoyed this post.Thanks Again. Really Great.

  28. Some genuinely interesting details you have written.Helped me a lot, just what I was looking for .

  29. There is clearly a lot to realize about this. I suppose you made various nice points in features also.

  30. Way cool! Some very valid points! I appreciate you writing this post plus the rest of the website is extremely good.

  31. Keep up the wonderful piece of work, I read few blog posts on this website and I conceive that your website is real interesting and has got sets of great information.

  32. P. Diddy说道:

    I think this is a real great blog article. Will read on

  33. ultra boost 3.0说道:

    A lot of thanks for your own work on this web page. My niece loves doing internet research and it’s simple to grasp why. All of us know all about the lively manner you present functional tips and hints via the web blog and therefore attract participation from other individuals on that situation and my girl is discovering a whole lot. Take advantage of the remaining portion of the year. You are always performing a glorious job.

  34. check out说道:

    Really informative blog post.Really thank you! Really Cool.

  35. I truly appreciate this post. I ave been looking everywhere for this! Thank goodness I found it on Bing. You have made my day! Thank you again

  36. Your style is unique in comparison to other folks I have read stuff from. I appreciate you for posting when you have the opportunity, Guess I will just bookmark this blog.

  37. Mighty helpful mindset, appreciate your sharing with us.. So happy to get discovered this submit.. So pleased to possess identified this article.. certainly, investigation is having to pay off.

  38. I will not speak about your competence, the post simply disgusting

  39. wow, awesome blog article.Really looking forward to read more. Great.

  40. giay da nam说道:

    Im no pro, but I believe you just made the best point. You definitely comprehend what youre talking about, and I can actually get behind that. Thanks for being so upfront and so sincere.

  41. Wow! This could be one particular of the most useful blogs We ave ever arrive across on this subject. Basically Great. I am also a specialist in this topic therefore I can understand your effort.

  42. thuc pham huu co说道:

    pretty handy stuff, overall I believe this is worth a bookmark, thanks

  43. sua hat huu co说道:

    Pretty! This was an extremely wonderful article. Thanks for providing this info.

  44. sim viettel说道:

    motorcycle accident claims I started creating templates, but I don at know how to make demos in my Joomla website, for my visitors to test them..

  45. Your style is so unique compared to other folks I have read stuff from. I appreciate you for posting when you have the opportunity, Guess I all just book mark this page.

  46. Major thankies for the post.Much thanks again. Want more.

  47. Online说道:

    Looking around I like to browse in various places on the web, regularly I will go to Digg and follow thru

  48. this website说道:

    Wow, great blog post.Thanks Again. Really Cool.

  49. This is very interesting, You are a very skilled blogger. I have joined your rss feed and look forward to seeking more of your excellent post. Also, I ave shared your site in my social networks!

  50. fitness说道:

    Thanks-a-mundo for the blog post.Really looking forward to read more. Much obliged.

  51. There is obviously a lot to identify about this. I feel you made certain nice points in features also.

  52. Thank you, I have recently been looking for info about this subject for ages and yours is the best I ave discovered till now. But, what about the bottom line? Are you sure about the source?

  53. Click here说道:

    You definitely ought to look at at least two minutes when you happen to be brushing your enamel.

  54. Very good post! We are linking to this particularly great article on our website. Keep up the good writing.

  55. Just wanna state that this is handy , Thanks for taking your time to write this.

  56. Ganchillo说道:

    That is a very good tip particularly to those fresh to the blogosphere. Short but very precise info Thanks for sharing this one. A must read article!

  57. try this说道:

    You have mentioned very interesting points ! ps decent website. What a grand thing, to be loved What a grander thing still, to love by Victor Hugo.

  58. blue nike说道:

    we prefer to honor numerous other online sites on the internet, even though they aren

  59. Pretty! This was a really wonderful post. Many thanks for providing this info.

  60. It as truly a great and helpful piece of information. I am glad that you shared this helpful tidbit with us. Please stay us up to date like this. Thanks for sharing.

  61. this website说道:

    or tips. Perhaps you can write subsequent articles

  62. Im thankful for the blog article.Much thanks again. Awesome.

  63. School admission说道:

    You completed various nice points there. I did a search on the topic and found mainly people will go along with with your blog.

  64. Waec exam说道:

    When I saw this page was like wow. Thanks for putting your effort in publishing this article.

  65. I’а†ve learn several excellent stuff here. Certainly price bookmarking for revisiting. I surprise how so much effort you set to create this kind of wonderful informative web site.

  66. It as not that I want to duplicate your web site, but I really like the layout. Could you tell me which style are you using? Or was it custom made?

  67. Thanks so much for this, keep up the good work

  68. Wow, great blog.Much thanks again. Much obliged.

  69. This website was how do you say it? Relevant!! Finally I have found something which helped me. Thank you!

  70. Whoa! This blog looks just like my old one! It as on a totally different subject but it has pretty much the same layout and design. Superb choice of colors!

  71. tm objection说道:

    Very neat blog article.Thanks Again. Really Great.

  72. The best richness is the richness of the soul.

  73. Very nice info and right to the point. I am not sure if this is actually the best place to ask but do you people have any thoughts on where to hire some professional writers? Thx

  74. Spot on with this write-up, I absolutely feel this site needs a lot more attention. I all probably be back again to see more, thanks for the advice!

  75. I was suggested this blog by my cousin. I am not sure whether this post is

  76. Wow, great blog.Really looking forward to read more. Want more.

  77. Major thanks for the blog.Really looking forward to read more. Want more.

  78. darey说道:

    You have brought up a very great points , thankyou for the post.

  79. resorts说道:

    Thank you ever so for you article.Really thank you! Keep writing.

  80. You have brought up a very wonderful details , appreciate it for the post.

  81. This awesome blog is obviously entertaining and also amusing. I have discovered a bunch of useful tips out of this source. I ad love to come back over and over again. Thanks!

  82. mac cosmetics cheap I dugg some of you post as I cogitated they were very helpful very helpful

  83. girl games说道:

    Major thankies for the article post.Really thank you! Fantastic.

  84. Very good blog post.Really thank you! Really Great.

  85. Way cool! Some extremely valid points! I appreciate you writing this article and the rest of the website is extremely good.

  86. see this website说道:

    Thanks-a-mundo for the article post.Really thank you! Really Cool.

  87. pool builders说道:

    Very informative blog post.Thanks Again. Awesome.

  88. some times its a pain in the ass to read what website owners wrote but this internet site is very user pleasant!.

  89. time just for this fantastic read!! I definitely liked every little bit of

  90. Wow! This could be one particular of the most useful blogs We have ever arrive across on this subject. Actually Excellent. I am also an expert in this topic so I can understand your effort.

  91. graham dailies说道:

    Really enjoyed this blog post.Much thanks again. Great.

  92. know more说道:

    Really informative blog article.Really thank you! Really Great.

  93. browse说道:

    Magnificent web site. A lot of helpful information here. I am sending it to a few friends ans also sharing in delicious. And obviously, thank you for your sweat!

  94. Suspendisse viverra, mauris vel auctor fringilla

  95. I’а†ve recently started a web site, the information you offer on this site has helped me greatly. Thanks for all of your time & work.

  96. your presentation however I find this topic to be really one thing

  97. Thanks for the blog article.Really looking forward to read more.

  98. for more info说道:

    I was recommended this website by my cousin. I am not sure whether this post is written by him as no one else know such detailed about my problem. You are amazing! Thanks!

  99. sprinted down the street to one of the button stores

  100. Thanks-a-mundo for the blog post. Great.

  101. Thanks so much for the blog article.Thanks Again. Keep writing.

  102. pretty practical material, overall I think this is really worth a bookmark, thanks

  103. Im grateful for the post.Really looking forward to read more. Fantastic.

  104. Wow! Thank you! I continuously needed to write on my site something like that. Can I implement a fragment of your post to my site?

  105. Woah! I am really enjoying the template/theme of this blog. It as simple, yet effective.

  106. There as noticeably a bundle to learn about this. I assume you made sure nice points in options also.

  107. facebook说道:

    This page definitely has all of the information and facts I needed concerning this subject and didn at know who to ask.

  108. more info说道:

    I think this internet site holds some very great info for everyone .

  109. Nice post. I learn something totally new and challenging on sites I stumbleupon everyday. It as always useful to read articles from other authors and practice something from their websites.

  110. premium ads说道:

    Say, you got a nice blog article.Really thank you!

  111. more details说道:

    Looking around I like to surf around the online world, regularly I will go to Stumble Upon and follow thru

  112. you can check说道:

    You are my breathing in, I own few web logs and occasionally run out from brand . Analyzing humor is like dissecting a frog. Few people are interested and the frog dies of it. by E. B. White.

  113. It as onerous to search out educated individuals on this topic, however you sound like you know what you are speaking about! Thanks

  114. ugg jimmy choo I am impressed by the quality of information on this website. There are a lot of good resources

  115. visit说道:

    Thanks for the article.Really thank you! Fantastic.

  116. magnificent issues altogether, you just received a new reader. What would you recommend in regards to your submit that you just made some days ago? Any certain?

  117. You ave made some good points there. I checked on the net to learn more about the issue and found most individuals will go along with your views on this web site.

  118. slot joker123说道:

    I truly appreciate this article post. Great.

  119. yeezy boost 350说道:

    My spouse and i got quite ecstatic that Louis could carry out his preliminary research from your ideas he acquired from your very own weblog. It is now and again perplexing to just choose to be freely giving tactics which usually a number of people may have been selling. And we fully understand we’ve got the blog owner to give thanks to because of that. All of the explanations you have made, the simple website menu, the relationships your site make it possible to promote – it’s mostly extraordinary, and it is making our son in addition to us reason why that matter is pleasurable, which is certainly really fundamental. Thanks for the whole thing!

  120. We can no longer afford established veterans if they have interest in him than expected.

  121. official site说道:

    that would be the end of this report. Here you

  122. more info说道:

    Really enjoyed this post.Much thanks again. Want more.

  123. you have got a terrific weblog here! would you wish to make some invite posts on my weblog?

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>