顯示具有 javascript 標籤的文章。 顯示所有文章
顯示具有 javascript 標籤的文章。 顯示所有文章

2016年5月7日 星期六

immediately-invoked-function-expression


立即函是是Javascript中一種可以立即執行的函式,其本質其實是個函式表示式。下面程式碼代表著一個簡單的立即函式。

(function(){
  // my special code
}());
其中的括號()代表的就是立刻執行該函式。在語法上,括號()也可以被放到左括號)外面,像是這樣。

(function(){
  // my special code
})();

1.全域變數的減少:

   寫程式難免會用到一些變數,但要避免變數暴露在全域之中,唯一的方式就是把它包裹在函式之中,或許你以前也有減少全域變數的觀念,所以你把程式碼寫在一個函式中,然後再呼叫它。現在你其實可以不需要這樣做,因為有立即函式的存在,所以你可以把程式碼包裹在立即函式中,然後放在它該出現的位置,在也不用看到一個init()(譬如說啦..)的呼叫,然後要拉到程式碼最下方去看這init()在做啥了。

2.全域變數區域化:

   看到JQuery的範例了嗎,他把全域變數window當成參數傳遞給立即函式中,因此在函式中,window就變成了區域變數。這樣做是因為Javascript在看到變數時會先查找區域變數,然後再查找全域變數,因此全域變數變成區域變數在效率上有些微的提升。另外也可以最小化變數名稱,一般Javascript最小化的程式並不會對全域變數進行壓縮(因為不安全),但區域變數就可以。因此全域變數區域化可以減少檔案的大小。當然你也可以自己來最小化。

(function( w, u) {
....

})( window );  

understanding-javascript-function-prototype-bind

understanding-javascript-function-prototype-bind

var foo = {
    x: 3
}

var bar = function(){
    console.log(this.x);
}

bar(); // undefined

var boundFunc = bar.bind(foo);

boundFunc(); // 3


bind something to as this 

JavaScript-Scoping-and-Hoisting

http://www.adequatelygood.com/JavaScript-Scoping-and-Hoisting.html


Function declarations and variable declarations are always moved (“hoisted”) invisibly to the top of their containing scope by the JavaScript interpreter. Function parameters and language-defined names are, obviously, already there. This means that code like this:

function foo() {
    bar();
    var x = 1;
}
is actually interpreted like this:

function foo() {
    var x;
    bar();
    x = 1;
}

How to Code With This Knowledge

Now that you understand scoping and hoisting, what does that mean for coding in JavaScript? The most important thing is to always declare your variables with a var statement. I strongly recommend that you have exactly one var statement per scope, and that it be at the top. If you force yourself to do this, you will never have hoisting-related confusion. However, doing this can make it hard to keep track of which variables have actually been declared in the current scope. I recommend using JSLint with the onevar option to enforce this. If you’ve done all of this, your code should look something like this:

/*jslint onevar: true [...] */
function foo(a, b, c) {
    var x = 1,
        bar,
        baz = "something";


}

2016年5月3日 星期二

JS 一定要放在Body 的最底部麼?聊聊瀏覽器的渲染機制


我們需要統一一下什麼叫我們經常掛在嘴邊的“頁面渲染出來了” ——指的是是“首屏顯示出來了”還是“頁面完整地加載好了”(後面統稱StepC) ? 
如果指的是首屏顯示出來了,那麼問題又來了:假設網頁首屏有圖片,這裡的“首屏”指的是“顯示了全部圖片的首屏”(後面統稱StepB)還是“沒有圖片的首屏”(後面統稱StepA)。

確定清楚“頁面渲染出來了” 指的是StepA、StepB、StepC 中的哪一個是非常關鍵的(雖然至今還沒有一個應聘者嘗試這麼做過),如果“頁面渲染出來了” 指的是StepC,那麼我的最後一問的答案是肯定的——script標籤不放在body底部不會拖慢頁面完整地加載好的時間。

瀏覽器的渲染過程

  1. Create/Update DOM And request css/image/js:瀏覽器請求到HTML代碼後,在生成DOM的最開始階段(應該是Bytes → characters後),並行發起css、圖片、js的請求,無論他們是否在HEAD裡。注意:發起js文件的下載request並不需要DOM處理到那個script節點,比如:簡單的正則匹配就能做到這一點,雖然實際上並不一定是通過正則:)。這是很多人在理解渲染機制的時候存在的誤區。
  2. Create/Update Render CSSOM:CSS文件下載完成,開始構建CSSOM
  3. Create/Update Render Tree:所有CSS文件下載完成,CSSOM構建結束後,和DOM一起生成Render Tree。
  4. Layout:有了Render Tree,瀏覽器已經能知道網頁中有哪些節點、各個節點的CSS定義以及他們的從屬關係。下一步操作稱之為Layout,顧名思義就是計算出每個節點在屏幕中的位置。
  5. Painting:Layout後,瀏覽器已經知道了哪些節點要顯示(which nodes are visible)、每個節點的CSS屬性是什麼(their computed styles)、每個節點在屏幕中的位置是哪裡(geometry)。就進入了最後一步:Painting,按照算出來的規則,通過顯卡,把內容畫到屏幕上。
以上五個步驟前3個步驟之所有使用“Create/Update” 是因為DOM、CSSOM、Render Tree都可能在第一次Painting後又被更新多次,比如JS修改了DOM或者CSS屬性。

Layout和Painting也會被重複執行,除了DOM、CSSOM更新的原因外,圖片下載完成後也需要調用Layout和Painting來更新網頁。


  • 首屏時間和DomContentLoad事件沒有必然的先後關係
  • 所有CSS儘早加載是減少首屏時間的最關鍵
  • js的下載和執行會阻塞Dom樹的構建(嚴謹地說是中斷了Dom樹的更新),所以script標籤放在首屏範圍內的HTML代碼段裡會截斷首屏的內容。
  • script標籤放在body底部,做與不做async或者defer處理,都不會影響首屏時間,但影響DomContentLoad和load的時間,進而影響依賴他們的代碼的執行的開始時間。

回到前面的問題:
script標籤的位置會影響首屏時間麼?
答案是:不影響(如果這里里的首屏指的是頁面從白板變成網頁畫面——也就是第一次Painting),但有可能截斷首屏的內容,使其只顯示上面一部分。

為什麼說是“有可能”呢?,如果該js下載地比css還快,或者script標籤不在第一屏的html裡,實際上是不影響的。明白這一影響邊界非常重要,這樣我們在考察頁面性能瓶頸的時候就有的放矢了。舉個例子:在網頁的第二屏有一個通用模塊,實際上我們是可以把它的js邏輯獨立成一個文件,將模塊的html和js標籤放在一起做成獨立的模板引進來的(如果它的js比較小或者說因為多了一個文件會多佔用一個TCP連接和帶寬,這實際上是另外​​一個話題了,請參考我文章開頭的聲明)。


我們來總結一下:
  • 如果script標籤的位置不在首屏範圍內,不影響首屏時間
  • 所有的script標籤應該放在body底部是很有道理的
  • 但從性能最優的角度考慮,即使在body底部的script標籤也會拖慢首屏出來的速度,因為瀏覽器在最一開始就會請求它對應的js文件,而這,佔用了有限的TCP鏈接數、帶寬甚至運行它所需要的CPU。這也是為什麼script標籤會有async或defer屬性的原因之一。

2016年4月16日 星期六

how to build a virtual dom tree

如何實現一個Virtual DOM算法

  1. use javascript object to present the structure of dom, and use it to build a real dom tree, then insert to document
  2. when state updated, recreate a object tree, and then compare old tree and new tree, and record the diff
  3. use 2.) diff to 1.) real dom tree

2.1. how to compare:
1.Depth-first search for new and old tree, and add unique mark
2.diff type: REPLACE, REORDER, PROPS, TEXT

3.compare list: ex => abcdefghi =>abchdfgij 

2014年6月13日 星期五

Mustache Template with Nested Array of Objects

情境:使用者點選按贊的人數時 顯示出按贊的人是誰
view: ajax 送js
contoller處理
def likedPeople
  @post = Post.find(params[:post_id] 
    respond_to do |format|
    format.js
  end
end
之後到likedPeople.js.erb
  2 var template = $('#template').html();
  3 Mustache.parse(template);   // optional, speeds up future uses
  4
  5 var arr = <%= safe(@post.liked_people.to_json) %> ;
  6
  7 var rendered = Mustache.render(template, {rows: arr})
  8
  9 $('#target').html(rendered);
先將@post.liked_people.to_js 再送到Mustache裡面去
但由於其內容是Nested Array of Objects
所以再加個
  7 var rendered = Mustache.render(template, {rows: arr})
來處理
template 就處理每個row
  3 <script id="template" type="x-tmpl-mustache">
  4   <ul class="list-like-group">
  5     {{#rows}}
  6     <li class="list-like-group-item" >
  7       <img class="like-author-photo" src="{{image.url}}" />
  8       <a href="/users/{{id}}/posts">
  9         {{name}}
 10       </a>
 11     </li>
 12     {{/rows}}
 13   </ul>
 14 </script>

jquery on

jquery binding的問題
當有些html是隨著操作動態產生的時候
如果直接用
('.class').click的話 後續產生的會沒有作用
Event handlers are bound only to the currently selected elements; they must exist on the page at the time your code makes the call to .on().
要用
$( "#dataTable tbody tr" ).on( "click", function() {
  alert( $( this ).text() );
});
$( "#dataTable tbody" ).on( "click", "tr", function() {
  alert( $( this ).text() );
});

fancybox


用這套來呈現一些點擊跳出的圖片 事件
一般用法 是會開啟a href所帶的資訊
<a class="fancybox" rel="group" href="big_image_1.jpg"><img src="small_image_1.jpg" alt="" /></a>
<a class="fancybox" rel="group" href="big_image_2.jpg"><img src="small_image_2.jpg" alt="" /></a>
<script type="text/javascript">
    $(document).ready(function() {
        $(".fancybox").fancybox();
    });
</script>
但當a href有另外的目的時,可用content的方法直接將要呈現的內容帶入
http://stackoverflow.com/questions/15325465/jquery-and-fancybox-with-click-event
<a href="/posts/29/likedPeople" class="likedPeople"  data-remote="true" >
 24       $("a.likedPeople").fancybox({
 25         content: $('#likedPeopleForm'),
 26         helpers : {
 27           overlay : {
 28             locked : false
 29             }
 30           }
 31       });

2014年6月8日 星期日

mustache

Mustache is a wonderfully simple templating language that is supported by a number of programming languages, including Ruby and JavaScript

/app/views/products/index.html.erb
<div id="products" data-json-url="<%= products_url(:format => :json) %>">
getJSON to get the products JSON from that URL. The getJSON function takes a callback function that fires when the data is returned and we’ll pass in a new function called render
/app/assets/products.js.coffee
 $.getJSON($('#products').data('json-url'), @render)
As our partial is a Mustache template it will need to have a .mustache extension rather than the usual .erb.
/config/initalizers/mustache_template_handler.rb
module MustacheTemplateHandler
  def self.call(template)
    if template.locals.include? :mustache
      "Mustache.render(#{template.source.inspect}, mustache).html_safe"
    else
      "#{template.source.inspect}.html_safe" 
     end
  end
end


ActionView::Template.register_template_handler(:mustache, MustacheTemplateHandler)
template.source which is the content of the template that’s being rendered
inspect on this to return an object which will be the string-escaped version of it’s Ruby representation
html_safe on the output from this to make sure that it’s escaped properly
render the template out using the Ruby Mustache passing in the mustache variable that contains the current product.Otherwise we render out the raw template for JavaScript to deal with on the client
register the new handler by calling register_template_handler, passing in the name of the handler and our module.
render json: @products.map { |p| view_context.products_for_mustache(p) }
Note that as we’re calling a helper method from a controller we need to call it through view_context.


2014年4月23日 星期三

rails data-method changed by javascript

reference http://stackoverflow.com/questions/9935956/changing-data-method-with-javascript-does-not-change-what-method-the-ajax-calls

$(this).data('method', 'post'); # sets "data-method" attribute to "post"
$(this).data('method', 'delete'); # sets "data-method" attribute to "delete"
For example, given the following HTML:
<div data-role="page" data-last-value="43" data-hidden="true" data-options='{"name":"John"}'></div>

All of the following jQuery code will work.
$( "div" ).data( "role" ) === "page";
$( "div" ).data( "lastValue" ) === 43;
$( "div" ).data( "hidden" ) === true;
$( "div" ).data( "options" ).name === "John";





2014年3月16日 星期日

full_calendar scroll to current time

full_scroll to current time

http://stackoverflow.com/questions/3317940/making-fullcalendar-scroll-to-the-current-time

var firstHour = new Date().getUTCHours() - 5;
$('#calendar').fullCalendar({
  firstHour: firstHour;
});

getUTCHours --> UTC time is the same as GMT time.  台灣要加八小時