“You might not need jQuery”

I stumbled on the You Might Not Need jQuery website, and I think that it’s a fantastic idea.

What it does is that it compares code written using jQuery, and code written in plain Javascript. If you develop mainly in jQuery, this helps you to write the same code in plain Javascript. On the other hand, if you are like me and don’t like jQuery for any reason, then it’s a good resource to learn from other people’s code.

It also links to some good libraries that can be used independently of jQuery.

Personally, I find using jQuery quite annoying for the following reasons.

  1. It can noticeably slow down page loading, especially on mobile. It even slows down PCs with Core i5 processors by 100ms.
  2. The jQuery website boasts that it’s only 32kB minified and gzipped, and they call it lightweight. On the contrary, the Ponzu system that I’m developing, which uses Javascript for AJAX, hashtag-based navigation, localStorage-based page caching, JSON-driven HTML templates and more, is less than 20kB total (minified and gzipped). It’s hard to justify 32kB when the vast majority of code is not going to be used.
  3. There are often too many functions doing similar things (and I’m saying this coming from Ruby, which also has a lot of redundant functions). Event handling is especially an area that put me off.

In Ponzu, we use jQuery only if the client is Internet Explorer. We have a small number of shims that use jQuery as a compatibility layer.

Analysis of How External Scripts Can Block Page Loading

I recently found two excellent blog articles (1, 2) by Steve Souders on how a single externally loaded Javascript, CSS and fonts can block page loading, resulting in completely or partially blank pages. Steve calls these Frontend SPOF (Frontend Single Point of Failure) and shows some screenshots of what the pages actually look like. I have copied one below.

NewImage

This screenshot was taken when Steve was in Beijing and was caused by the Chinese firewall blocking the domain cdn.eyewonder.com. I also had a similar experience when I was in Shanghai and the firewall blocked a Twitter badge that I had (I was using an old synchronous Twitter badge. Twitter now uses synchronous badges only, which do not cause fronted SPOF).

However, this experience is not limited to China. Technically, this can happen whenever loading of a resource takes a lot of time. This often happens when you have a bad Internet connection, for example when you have a weak 3G connection or you have an unreliable WiFi setup. I experienced this a lot in conferences and exhibitions where not enough money was spent to beef up the WiFi.

It is unfortunate that many web developers are still unaware of this issue.

Javascript Callback Hell and how I cope

I’m not a heavy Javascript coder, but I have already experienced “Callback Hell” more that I would like.

“Callback Hell” is well describe in this website, and they provide some ways to remedy. I however have some issues with this approach.

I’ve copied their example for “Keep your code shallow”, which I understand is the most generic solution (meaning the solution that doesn’t depend on external libraries).

function formSubmit(submitEvent) {
  var name = document.querySelector('input').value
  request({
    uri: "http://example.com/upload",
    body: name,
    method: "POST"
  }, postResponse)
}
function postResponse(err, response, body) {
  var statusMessage = document.querySelector('.status')
  if (err) return statusMessage.value = err
  statusMessage.value = body
}
document.querySelector('form').onsubmit = formSubmit

The issue that I have with this code is that there is no central function that gives me an outline of the program flow. For example, if you wanted to know how error messages are displayed, you would have to first go into formSubmit. There you notice that the callback for the request is postResponse so you read the postResponse function. There you finally find how the error messages are handled.

Having the program flow scattered all over the place makes my head hurt. I need to know how the functions in my code fit together. Especially if you are writing some controller code, you are most likely going to summon functions from a lot of different objects/classes and having to wade through those to understand program flow is something that I want to avoid. I want an overview of the program flow in one single location. I’ve tried “Keeping my code shallow”, but in my experience, it actually made the situation worse.

Coming from a Ruby background where the mantra is to keep methods short and clean, Javascript functions look awfully long and complicated. You feel an urge to separate these into discrete functions and this works if your code is synchronous. When you are dealing with asynchronous code however, you often find yourself writing the same kind of code described above, and you find that it’s more difficult to understand the refactored code than the initial monolithic function. This drove me crazy.

If you could write synchronous code, you could write something like this, which is how I would want to write it;

function formSubmit(submitEvent) {
  var name = document.querySelector('input').value
  response = request({
    uri: "http://example.com/upload",
    body: name,
    method: "POST"
  })
  postResponse(response)
}

The benefit of the synchronous code is that you now have a central location which dictates the flow of the code. You know upfront that your choices for hunting down the error handling code is either the request function or the postResponse function, and judging by the names, postResponse looks more likely. Compare this with the synchronous code where you only learn of the existence of the postResponse function after you read the call to request inside of formSubmit.

This becomes a huge problem when the code is more complex and you need to process the request through multiple steps (resulting in multiple nested callbacks).

My approach is to code like the following;

function formSubmit(submitEvent, callback) {
  var name = document.querySelector('input').value
  request({
    uri: "http://example.com/upload",
    body: name,
    method: "POST"
  }, callback)
}
function postResponse(err, response, body) {
  var statusMessage = document.querySelector('.status')
  if (err) return statusMessage.value = err
  statusMessage.value = body
}
document.querySelector('form').onsubmit =
  function(event){formSubmit(event, 
    function(){postResponse(err,response,body)}
  )}

This style makes it clear that formSubmit subsequently calls postResponse.

If you need to do some more complex processing, you can write the following;

function formSubmit(submitEvent, callback) {
  var name = document.querySelector('input').value
  request({
    uri: "http://example.com/upload",
    body: name,
    method: "POST"
  }, callback())
}
function postResponse(err, response, body, callback) {
  var statusMessage = document.querySelector('.status')
  if (err) return statusMessage.value = err
  statusMessage.value = body
  callback()
}
function doSomethingExtra(callback){
  // Do something here
  callback();
}
function doEvenMore(callback){
  // Do something here
  callback();
}
document.querySelector('form').onsubmit =
  function(event){formSubmit(event, 
    function(err,response,body){postResponse(err,response,body,
      function(){doSomethingExtra(
        function(){doEvenMore()}
      )}
    )}
  )}

It is still super easy to understand the program flow. If you did something like this with the normal approach, you would have to first look into formSubmit, postResponse, doSomethingExtra and finally doEvenMore.

If you use Coffeescript, then the code would look like the following, which makes the intent of the code super easy to understand;

document.querySelector('form').onsubmit = (event) ->
  formSubmit event, (err, response, body) ->
    postResponse err, response, body, ->
      doSomethingExtra ->
        doEvenMore()

The interesting thing about the Coffeescript code is that with the functions statements out of the way, it starts to look like synchronous code with the exception that each consecutive method call is indented one step more than the previous. What I really like is that the program flow is as easy to understand as synchronous code.

Not being a heavy Javascript coder, I haven’t really put my head into error handling and such so I’m sure there is a lot that I’ve overlooked. I’m just posting here the way that I’m overcoming “Callback Hell”, and I really like it compared to the alternative remedies that I find on the web.

iBooks AuthorのウィジェットがePub3じゃなくて良かったという話 – Booki.sh Blogより

先日「iBooks Authorは電子書籍ではなくブックアプリを作るソフト。だからePub3じゃない。」という書き込みの中で、iBooks AuthorがePub3を採用しなかった最大の理由はデジタルの可能性を最大限に追求したいからだろうと推論しました。

その書き込みをしたときから気になっていたことがあります。ePub3ではJavascriptが使えます。そしてJavascriptを使えば、もしかしてiBooks Authorと同じようなインタラクティブなウィジェットが作れるかもしれません。つまり、iBooks Authorと同じ機能をePub3で実現することが不可能とは断言できないのです。

それにもかかわらずiBooks AuthorがウィジェットにePub3を採用しなかった理由は何だろうと考えました。以前の書き込みをした当時は、ePub3やJavascriptのような業界スタンダードに縛られてしまって、イノベーションのスピードが落ちるのを危惧したのではないかと考えていました。

しかし Booki.sh Blogの“A favor from Goliath”という記事を読んで、考えが変わりました(ちなみにBooki.shはebookをブラウザで読むためのプラットフォーム)。

Booki.sh Blogが言っているのは要約すると次のことです;

  1. ebookの中にJavascriptを埋め込んでインタラクティブなウィジェットを実現するやり方はセキュリティー上の問題があるし、ユーザインタフェースとしても良くなりません。(詳細はこっち
  2. iBooks Authorのやり方は、ebookファイルにはどのようなインタラクティブな機能を実現するべきかを記載するに留め、それを動作させるための実際のプログラムはebookファイルに記載していません。ebookファイルに記載された通りの動作を実現するためのプログラムはiBooks 2の中に置いています。
  3. インタラクティブなウィジェットのプログラムをebookファイルの中に(Javascriptで)埋め込んでしまうと、ebookファイルそのものを書き直さない限り、ユーザインタフェースを改善したり、バグを直したりできません。それに対してウィジェットのプログラムがebookリーダーの中にあれば、ebookリーダーをアップデートするだけですべてのebookのウィジェットのユーザインタフェースが改善できます。

言われてみるとなるほどと思うものばかりですが、プログラミングをあまりやったことがない人だとわかりにくいかもしれませんので、以下に自分なりに解説してみたいと思います。 Continue reading iBooks AuthorのウィジェットがePub3じゃなくて良かったという話 – Booki.sh Blogより

Really, really simple way to use the back button on AJAX websites


Update
In the example code, I used an input type=”text” to store the state value. In order to hide this control, you should set the style to “display:none” instead of using an input type=”hidden” form control. Browser implementations are more likely to ensure that input type=”text” values are restored, and Safari 5 for example, decided that type=”hidden” values should not necessarily be preserved (Webkit Bugzilla). Using input type=”text” with style=”display:none” will work more reliably across browsers.

I was searching the web for techniques enabling the “back” button on my AJAX web site. Unfortunately, the only ones that I could find were really “hacky”. There are a couple libraries in active development like Really Simple History (RSH)YUI History by Yahoo! However, contrary to the name “Really Simple”, RSH appears to be a huge polling hack behind the scenes, running a Javascript every 0.5 seconds even if the user is doing absolutely nothing (This polling should become unnecessary with the HTML5 “window.onchangehash” event, that is currently supported in the most recent IE and FF versions, and Webkit nightlies). As far as I can tell, YUI History is doing more or less the same thing. Since you should be designing your site to be non-reliant on the forward and back buttons anyway, it is hard to justify intrusive polling in return for this hopefully rare functionality. The idea made me very uncomfortable.

On the other hand, if the “back” and “forward” buttons do not work as expected, you are surely going to make more than a few users quite infuriated. The typical AJAX application behavior when you push the “back” button is to completely erase everything that the user did, and send them to the fresh page as it was when they first visited it. Essentially, you are sending the users back to the entrance door. Sounds like you won’t be seeing them again any time soon.

Luckily, I managed to come up with a solution that works with browsers as erratic as IE6, does not require loading a library, and should only require a small amount of additional code. Although it only solves a small part of the browser history and “back” button problem, I think it solve the most irritating issues quite sufficiently, such that the user won’t feel one bit the urge to slam shut his laptop and pour himself a strong cup of coffee.

What is the “Back” button problem?

I probably don’t have to teach this to people who have done a fair amount of AJAX programming, but I will discuss it to clarify what my solution does and doesn’t solve.

AJAX is a technique that enables the browser to update only a part of a page, and is very useful for improving the perceived responsiveness of your web site. However, AJAX updates generally do not rewrite the location in the browser location bar. Since it is this location value that the browsers use to maintain their histories and to enable the back and forward buttons, AJAX renders these buttons useless. These buttons will typically send you to the first state that you saw when you first visited the web page, before any of the AJAX updates took place. In effect, all the work that you did since you visited the page will be lost (unless of course, the AJAX updates themselves rewrote the information on the server).

For example, imagine that you are visiting a web catalog site that lists electronic products, and uses AJAX to make browsing the product categories nice and quick. Imagine that the the user decided to do a text search after reaching a category deep in the hierarchy (“mac” in the illustration below). Also let’s assume that this product search fires a regular HTTP request (non-AJAX). Now after viewing the results, what would the user do if he decides to take another look at the “mac” category? Instinctively, he would push the “back” button on his browser, sending him unwittingly to the root category of the product catalog. You can almost see the cold sweat on his face as he realizes that he might have lost any way to get back to the “mac” category, save for going through the whole product hierarchy again. Pushing the “forward” button wouldn’t help either, since he would be taken straight to the search results page, right where his woes began.

Ajax javascript back button.jpg

We can easily see why the AJAX “back” button issue can cause such anger and frustration. Despite all your AJAX efforts to make navigation and data entry nice and quick, the “back” button issue will strip you of all the goodwill that was earned. Most likely, the users will even leave with a worse feeling than before they first visited.

The normal solution

Although there are many posts on the web and several libraries to solve the “back” button problem, all of the solutions that I could find on Google were basically variations of the methods used in RSH and YUI History. Namely, to use the hash (“#”) at the end of the location to store the state information in the browser’s history.

With AJAX, the URL can not be changed since this would fire a reload of the whole page. However, the portion after the hash (“#”) is handled differently. Changing this portion (with the Javascript “document.location.hash” property) will not fire a reload, but will cause the whole location to be stored in the browser’s history (at least for non-IE browsers). Therefore, if you store the current AJAX state in the hash portion, you would be able to resolve the “back” button issue. At least in theory.

However, since this is not the intended usage of the hash, browsers deviate in how this is handled. Changing the location does not trigger IE browsers to store the changed location in the browser’s history, and early versions of Safari did not provide a way to read the hash portion after it was changed. To support IE, both RSH and YUI store browser history in an iframe and send an otherwise unnecessary request to the server, an unfortunate hack. An even more troublesome hack is that RSH and YUI use polling to read the hash portion, even with the more recent browsers. Polling is the action of executing a method in regular intervals, even when the user is not interacting with the browser. With RSH, the polling frequency is an alarming 0.5 seconds. This can cause the whole computer to slow down and will cause laptops to consume more battery charge. Polling is generally a despised hack that most programmers try hard to avoid. (As mentioned above, HTML5 provides the window.onhashchange event so that you don’t have to rely on polling, but this is only supported on the most recent of browsers.)

Going through all these loops and potentially causing a slow down on the user’s computer sounds simply too much to solve the “back” button problem. HTML5 will hopefully make things much easier, but as things stand today, I think we need a different solution.

A solution using form elements

The issue with the “back” button boils down to how we can store AJAX state information. As described above, I think that using the hash (“#”) in the location is much too troublesome. In the method below, I used regular form elements.

Form elements do preserve their contents between “back” button clicks. Remember when you were editing a form on a web site, and you realized that you had made a mistake after hitting the submit button. If you go back to the data entry page by clicking the “back” button, you will see all the form elements containing the same information they had just before you submitted it. Most browsers (even the older ones), automatically restore this information, even if they are different from the default values in the HTML. In my method, I use this feature to store the AJAX state. (better description here)

Browsers store this information inside their caches. If this solution doesn’t work on your web app, try adding the HTTP header “Cache-control: private” in your response, which should tell browsers that they can cache content locally.

I’m not sure if the above behavior is dictated by a standard, or is just how the browsers have opted to behave. I do think that this feature is central to the end-users’ browsing experience, and this is probably why this solution seems to work on all browsers without any hacking.

With the form solution, we do not create a history entry, and as a result, we can only solve a small portion of what RSH and YUI History provides. This small part however, is in my opinion, the most frequent source of end-user headaches, and is by far the most important problem. Being able to solve this with a simple solution should really help.

The Code

The code below is all that I need to run a demo and illustrate the method. I am using Prototype.js to manipulate the DOM, but it should be possible to write it just as easily with raw JavaScript (I’m just too lazy to do it). I also have a demo site to make it easier to follow my explanations.

 1  <html>
 2  <head>
 3    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/prototype/1.6.1/prototype.js"></script>
 4    <script>
 5      function setColor() {
 6        $('field').setStyle('background-color:' + $F('field'));
 7      }
 8    </script>
 9  </head>  
 10 <body>
 11   <form>
 12     <input type="text" id="field" value="red"/>
 13   </form>
 14   <a href="Javascript:void()" onclick="$('field').setValue('blue');setColor();">blue</a>
 15   <a href="http://google.com">go to Google</a>
 16   <script>
 17     setTimeout("setColor();", 0);
 18   </script>
 19 </body>
 20 </html>

This demo works as follows.

  1. When you click the link “blue”, the content of the text field and its background color are changed to blue.
  2. Then go to another web site by clicking on the “go to Google” link that I provided.
  3. When you return to the demo web page by clicking the “back” button, the text field will contain the word “blue” and the background-color will also be blue. Just the way it was before going to Google. Compare this to another demo page with the 17th line commented out.

A description of the source follows.

  1. Lines 11-13 are a form to preserve the state (the state form). When the “back” button on the browser is pressed, the state values are restored from the browser cache.
  2. Line 14 is the link “blue”. When this is clicked, the value of “blue” is written to the state form with “$(‘field’).setValue(‘blue’)”. The next “setColor();” command changes the background color to synchronize with the value in the state form.
  3. Lines 17 is executed when the page is first loaded, and after the page is redrawn after coming back with the “back” button. The “setColor();” command will ensure that the background color is synchronized with the value in the state form. Safari and FF work fine without the setTimeout wrapper, but I found that it is necessary to get it working on IE when you come back with the “back” button.
  4. I have checked that this demo works on FireFox3.6, Safari 4 and IE6-8.

In this simple example, I only changed the background color. With an AJAX web app, you would save the AJAX request parameters in the state form, either before or after you made the AJAX request. You would also provide a command that sends the AJAX request after coming back with the “back” button, so that the DOM state will be synchronized with the state form values, which have been automatically restored from the browser hash.

What you can and what you cannot do with this method.

With this method, you can use the “back” button to return to your prior state after being sent to a new URL. You will be returned to the very last state. You cannot return to any intermediate AJAX state.

Ajax javascript back button 2.jpg

Of course, this is not a 100% solution covering bookmarking and stuff. I do believe that it does however cover more than 80% of the end-user needs. With a regular AJAX page, the end-user will lose all of their efforts; every click and every form entry. You are essentially showing the end-user the exit, and telling him that he doesn’t have to bother coming back. With the method that I described, the end-user will be sent back to his final state and he can simply modify things without going through the same procedure from the start. The equivalent of politely asking “Pardon. Could you please repeat that final request, Sir?”.

AJAXで書き換えたウェブページでバックボタンを使う


アップデート
下記のコード例では状態を保存するために input type=”text” を使いました。この値を表示したくない場合は、input type=”hidden” を使わずに style=”display:none” とした方が良いようです。ブラウザによっては(例えばSafariの5以降) type=”hidden”の値が保存されるとは限りません(Webkit Bugzilla)。input type=”text”とstyle=”display:none”の組み合わせに方が、異なるブラウザ間で確実に動作してくれそうです。

AJAXをたくさん使ったページでバックボタンを使えるようにしたいと思って、ウェブでいろいろ探しました。見つかったのは例えば Really Simple History (RSH)YUI Historyなどで、以下に述べるようにかなり怖いぐらいのハックをしているものでした。とても手軽に使う気にはなれません。(どれも結構歴史のあるものですが、最新バージョンでも同じハックを使い続けていると思います)

とは言うものの、バックボタンやフォワードボタンがうまく使えないと、ウェブサイトの利用者を非常に不満を与えてしまうことがあります。なんとか解決策は無いかと考えていたところ、非常にコードが少なく、なおかつ古いブラウザでもそのまま使える簡易的な方法が見つかりましたので以下に紹介します。

バックボタンの問題とは?

AJAXをたくさん使ってプログラミングしている人には紹介するまでもないのですが、今回の解決策の範囲を示すためにバックボタンの問題を簡単に紹介します。

AJAXはページ全体を再描写しないで済むので、レスポンス間の良いウェブサイトを作るのに非常に適しています。しかしAJAXでページを細かく書き換えても、ブラウザが指しているURL(ロケーションバーのURL)を全く書き換えられません。バックボタンはロケーションバーのURLに連動して動作しますので、結果として思い通りの動作をしてくれません。

例えば製品カタログのウェブサイトを作っているとします。カタログの中を調べていくとき、AJAXで画面を再描写するようにしてレスポンスを向上させていたとします。そしてある程度深い階層(ここでは「マック」)にユーザが入ったところで、検索を行ったとします。この検索はAJAXではなく、普通のHTTPでページを切り替えたとします。さて問題となるのは、検索を行ったユーザがバックボタンを押したときです。ユーザとしては「マック」の階層に戻ることを期待しています。しかしAJAXを使った場合はURLは最初のページのままなので、実際には「製品カタログ」のトップページに戻ってしまいます。ユーザが苦労してやっと「マック」のカテゴリーにたどり着いたのに、もう一度最初からやり直さなければならないのです。フォワードボタンを押そうが何をしようが無駄です。今までの作業は永遠に消えてしまうのです。

AJAX_back_button.jpg

このようにAJAXのバックボタン問題は、ユーザに大きな不快感を与えます。せっかくAJAXで使いやすいサイトに作ったとしても、バックボタン問題でそのすべてが吹っ飛んでしまいます。逆にネガティブになるリスクも高いと思います。

一般的な解決策

グーグルで調べた限り、ブラウザのロケーションのハッシュ部分にステートを保存する解決策やライブラリーが多く作られているようです。上述のRSHやYUI Historyと同じやり方です。

AJAXでは基本的にはURLは変わらない(変えられない)のですが、URLの”#”の後ろの部分(ハッシュ)だけは違います。この部分はブラウザの履歴に保存されますので、バックボタンを押したときにも残っています。そこでAJAXページの最後の状態(ステート)をハッシュ部分に保存すれば、原理的にはバックボタン問題を解決できます。

しかしロケーションのハッシュ部分にステートを保存するというのはかなり特殊な使い方で、ブラウザによってはよっぽど変わったことをやらないとうまく動作しないようです。例えばRSHとYUIのライブラリーではIEをサポートするために新たにiframeを作成し、本来必要の無いリクエストをサーバに送っているようです。YUIは古いSafariのバージョンではもっと訳の分からないことをやっています。またSafari 3 4やFireFoxなどの最新のブラウザでもpollingという禁断の技法を使っています。Pollingというのは例えば0.5秒おきにプログラムがロケーションを確認するというもので、ユーザがブラウザを全く触っていないときでも動作させるやり方です。パソコンの動作を無駄に遅くさせ、電池を消耗させることから、非常に嫌われている方法です。

バックボタンという比較的シンプルな機能を実現するためにこんなに無理をし、ユーザのパソコン全体の動作を重くさせていいのでしょうか。僕は絶対にこれはやりたくないので、この方法は使えません。ただHTML5ではdocumentwindow.onhashchangeというハンドルが加わり、将来的にはpollingは不要になりそうです。またブラウザの履歴をより直接的に操作できるようにもなるらしいですので、そのときはもうちょっとマシな方法が一般的になっていくでしょう。でも今はとにかくダメなので、別の方法を探りました。

フォームを使った解決策

バックボタンの問題を解決するためには、ブラウザのステートを保存しなければなりません。それを上述のようにロケーションバーに保存するのは現時点では無理があります。ここで紹介する方法ではフォームの中に保存しています。

例えばブラウザでフォームを編集して、それを送信した後、間違いに気づいたとします。通常バックボタンを押せば、送信する直前の状態、つまり各フィールドに情報を入力した状態に戻ります。このように、大部分のブラウザではフォームの内容を保持していて、バックボタンを押したときにそれが復活するようになっているのです。今回はこれを利用します。

フォームの内容を保持することは、ブラウザを使っているすべての利用者の利便性に直接関わります。ですから古いブラウザでも新しいブラウザでも同じ動作をしてくれますし、パソコン全体の動作を重くしてしまう心配もありません。その代わり、RSHやYUIと比べると実現できる機能はごく一部になってしまいます。しかしフォームを使って実現できるわずかな機能が、最も重要な機能だと思います。具体的には以下に紹介していきます。

コード

以下に示したのが、今回の方法を説明するのに必要なコードのすべてです。DOMを操るためにPrototype.jsを使っていますが、非常に簡単なことしかしていませんのでJQueryや生のJavaScriptしか使っていない人でも分かりやすいと思います。このコードを載せたデモサイトも用意しました。

 1  <html>
 2  <head>
 3    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/prototype/1.6.1/prototype.js"></script>
 4    <script>
 5      function setColor() {
 6        $('field').setStyle('background-color:' + $F('field'));
 7      }
 8    </script>
 9  </head>  
 10 <body>
 11   <form>
 12     <input type="text" id="field" value="red"/>
 13   </form>
 14   <a href="Javascript:void()" onclick="$('field').setValue('blue');setColor();">blue</a>
 15   <a href="http://google.com">go to Google</a>
 16   <script>
 17     setTimeout("setColor();", 0);
 18   </script>
 19 </body>
 20 </html>

このデモの動作は以下のようになります。

  1. “blue”のリンクをクリックすると、Javascriptを使ってテキストフィールとのバックグラウンドカラー(background-color)を変えます。
  2. そのあと”go to Google”のリンクをクリックして、google.comのページに移動します。
  3. ブラウザのバックボタンを押してこのデモのページに戻ったとき、テキストフィールドは最後の”blue”のままです。何もしていない普通のページであれば、テキストフィールドのバックグラウンドカラーは”blue”のリンクをクリックする前の色であったはずです。17行目をコメントアウトしたデモサイトも用意しましたので、動作を見比べてください。

プログラムを解説します。

  1. 11-13行目はステートを保持するためのフォームです。ブラウザのバックボタンを押すとこのフォームの内容は直前の状態になります。
  2. 14行目が”blue”のリンクです。これをクリックすると”$(‘field’).setValue(‘blue’)”でステート保持フォームに”blue”が書き込まれます。次に”setColor();”を呼んで、ステート保持フォームの内容がバックグラウンドカラーに反映されるようにしています。
  3. 16-17行目はページが最初に読み込まれたり、バックボタンで再表示されたときに実行されるJavascriptです。”setColor();”を読んで、ステート保持フォームの内容がバックグラウンドカラーに反映されるようにしています。なおSafariやFFではsetTimeoutで囲まなくてもうまく動作してくれたのですが、IEの場合はsetTimeoutで囲まないと、バックボタンを押したときに動作してくれませんでした。
  4. 動作確認はFireFox3.6, Safari 3 4, IE6-8で行いました。確認した限り、どれも同じように動作しました。

今回はバックグラウンドカラーを変えるという簡単なデモでしたが、AJAXを使ったウェブページであればAJAXのパラメータをステート保持フォームに保存することになるでしょう(AJAX呼び出し直前もしくは直後にJavascriptでこのフォームにパラメータを保存します)。バックボタンを押してこのページが再読み込みされたときは、まずステート保持フォームが空かどうかを確認し、空でなければそのパラメータでAJAX呼び出し行います。空であればAJAX呼び出しを行いません。

この方法でできること、できないこと

この方法でできるのは、新しいURLに移動した後、バックボタン(もしくはフォワードボタン)で戻る動作です。そしてAJAXを使ったページの一番最後の状態に戻ります。AJAXページの途中の状態に戻ることはできません。フォワードボタンでも同様です。

Ajax javascript back button 2.jpg

もちろんこれで100%十分という訳ではないのですが、恐らく80%近くは行けてると思います。単なるAJAXのページではバックボタンで今までの作業がすべて白紙に戻されるため、非常に頭にきます。しかし今回の方法を使えば、最後の状態に戻せます。逆に言うと、最後の状態にしか戻せません。新たな利便性を提供できないのは残念ですけど、少なくとも作業は失わないで済むのです。これは非常に大きな違いだと思います。

新しいWeb技術 SproutCoreがもたらすもの

6月9日のApple Worldwide Developer’s Conferenceは、iPhone 3Gの発表とそれがたった$199で発売されるというニュースで持ち切りでしたが、その陰で他にも非常に興味深い発表が多くありました。

その一つがSproutCoreという技術。これはAppleが発明した技術ではないのですが、Appleが全面的に支援している新しいWeb技術です。ひとことで言うと、SproutCoreを使うとWebの使い勝手が大幅に良くなります。しかも開発が簡単です。

日本語になっている記事がいくつかありますので、下にリンクを用意しました。

  1. アップル、ウェブアプリに向けオープンな「SproutCore」技術を採用か?
  2. アップルのMobileMeを試してみたい人は、SproutCoreをチェックしよう

さて、上のリンクだけだと専門的すぎて、ウェブ開発者でなければ理解できないものばかりです。
そこで僕は、このSproutCore的な技術が、バイオの研究にどのような利点をもたらすかに絞って紹介します。複雑な話なので、順番を追って。

AJAXという技術

HTMLを柱とするウェブ技術は、もともとページという概念が強く、すべての情報はページ単位という考え方でした。紙とかなり概念が似ていました。これはすごくシンプルでネットワーク上も扱いやすいという利点がありましたが、インターネットの双方向性とブロードバンド化が進むに従ってその限界が明確になってきました。

例えばマップ技術を見てみましょう。ぐるなびは初期のインターネットの技術を利用しています。そのため、地図を拡大するにしてもあるいは少しだけ場所をずらすにしても、ページが丸ごと再表示されてしまいます。
これに対してGoogle Mapsではすべての動作がスムーズです。地図の中心をずらすには地図をドラッグすればいいし、拡大縮小のときもページ全体が再描写されることはありません。

これはGoogle MapsでAJAXという技術が利用されているためです。AJAXを使うと、ウェブサイトをページ単位に扱う必要がなく、またドラッグのような操作を使うことができるようになります。ウェブのサイトを見ているというよりは、自分のパソコンにインストールされているソフトを使っている感覚に近くなるのです。

GoogleはMaps以外にもAJAX技術を活用していて、Google Docsではワープロ、スプレッドシート、プレゼンテーションを作成するためのソフトを無償提供しています。これらはいずれも自分のパソコンにソフトをインストールせずに、マイクロソフト オフィスのような機能と操作性のソフトを提供するものです。

まとめると、パソコンにインストールされたソフトと同じような高い操作性のものが、AJAX技術によってウェブで実現できるようになりました。

ソフト開発におけるフレームワークの重要性

AJAX技術はGoogle MapsとGoogle Docsに代表されるように、非常に強力な技術ですが、残念ながら開発は簡単ではありません。簡単なAJAXはずいぶん多くなりましたが、ユーザが入力したデータまで含めて管理する、Google DocsタイプのAJAXウェブサイトはまだ数えるほどしかありません。

SproutCoreはこの問題を解決してくれる可能性のあるテクノロジーです。これはAJAXソフトのための「フレームワーク」です。ソフトの開発ではこのフレームワークが非常に重要で、優秀なフレームワークがあればプログラマーの生産性は何倍にもなります。

フレームワークというのは例えると電気、ガス,水道、そしてそれを利用する流しやトイレ,コンロ、暖房のようなものです。家を造るために自分で電気、ガス、水道を引くのは大変ですし、トイレやコンロも全部用意するのも面倒です。それらをすべて備え付けておいてくれているのがフレームワークです。あとは居住者の趣味に合わせて家具やカーテンをそろえて、住み心地の良い部屋にすればいいのです。フレームワークはすべての人が必要として、ほぼ共通しているものをあらかじめ用意してくれているものなのです。

いままでもAJAXのフレームワークはいくつかありましたが、どちらかというと電気、ガス,水道どまりのものでした。SproutCoreはさらにトイレ,コンロ、暖房を用意したものになっています。ですから、SproutCoreの出現によって、Google Docsのようにデータまで管理してくれるAJAXウェブサイトが簡単に開発できるようになります。

Appleのサポート

AppleはSproutCoreの開発者を雇い入れ、7月に公開するMobileMeにSproutCoreを全面的に活用します。MobileMe Webアプリケーションとしてはメール、アドレス帳(連絡先)、カレンダー、iDisk、そして写真ギャラリーを用意しますが、いずれもパソコンにインストールされたソフト並みの操作性となっています。AppleはSproutCoreの技術を利用するだけでなく、SproutCoreの開発も支援していて、おかげでずいぶんとSproutCoreの性能が向上したと紹介されています。

バイオへの波及

AJAX技術はバイオにとってかなり重要な技術です。バイオの情報はあまりにも多く、多岐に分かれていますので、ページという単位で表現するのは困難です。情報を閲覧している人がいろいろな絞り込み検索を行ったり、画面の微調整をしたり、自分で整理したりしないと、なかなか目的の情報が得られません。

実際、NCBIもかなり努力をしていて、AJAX技術も使われているようです。Sequence ViewerもおそらくAJAXをかなり活用していると思われます。

SproutCoreなどが普及することにより、Sequence Viewerよりもっともっと使い勝手のいいものが、より多くのバイオインフォマティックス系のウェブサイトに登場することが期待されます。Sequence ViewerそのものがSproutCoreのカスタムコンポーネントとして普及し、データを持っているところであれば簡単に自分のウェブサイトに組み込めるようになるかもしれません。

またPubMedなども、いまでは論文のタイトルとリンクが表示されているだけですが、AJAX技術を利用すれば、ページを移動することなく、素早くSummaryをプレビューできるようになるでしょう。またメールソフトのようにお気に入りの論文をフォルダにドラッグして整理できるようになるかもしれません。

あと、塩基配列を解析して制限酵素サイトを探したり、プラスミドマップを作ったりするソフト。。。。AJAX無しのものとしてはNEBcutterPlasMapperなどはいいと思いますが、もっともっと便利なものができてくるでしょう。

MacのKeynoteをWeb上で実現

いままでデスクトップアプリケーションが必要だったものが、最近ではウェブ上でできてしまいます。

一番有名なのは言うまでもなくGoogle Docs。そしてついこの前知ったのは、Acrobat.com。Google Docsはワープロ・表計算・プレゼンのソフトがすべてそろっていて、マイクロソフトオフィスを不要にしてしまうものです。しかも無料。Acrobat.comはワープロとオンラインミーティングを実現するツールで、これも無料です。しかもAcrobat.comはかっこいい。AdobeはさらにPhotoshop Expressというものも用意しています。Photoshop Expressは写真をFilckrのように公開できるだけでなく、編集もできます。

そして今日知ったのは、なんとMacのKeynoteをウェブで実現してしまうツール。280 Northの280 Slidesというウェブサイト。まだ使っていませんが、Keynoteそっくりでとても楽しみです。

すごい!