Javascript異步編程


一、什麼是異步(Asynchronous)編程?

    相對於同步(Synchronous)而言,異步就是後一個任務不須要等待前一個任務結束就執行,而前一個任務結束之後執行回調函數。

    最多見的異步編程有setTimeout函數、 ajax請求等。

    如:

        for (var i = 1; i <= 3; i++) {
            setTimeout(function(){
                console.log("#",i);
            }, 0);
            console.log("*",i);
        };

    輸出的結果是:*1 *2 *3 #4 #4 #4

    涉及到的知識點: 異步、閉包、做用域

    setTimeout是一個註冊事件,在主程序運行結束前,是不會調用的。

    就像爲某個div綁定一個點擊事件同樣,在沒點擊以前,這個事件是不會被觸發的。

    這就是一個常見的異步編程的例子。


二、異步編程的方法

    Ⅰ、回調函數

        假設有 f1(); f2(); 兩個函數,其中f2()在等待f1()的執行結果。

        function f1(f2){
            setTimeout(function(){
              f2();
            }, 1000);
          }

        代碼執行順序:f1(f2);

        優勢:f1不會堵塞程序運行,至關於先執行程序的主要邏輯,將耗時的操做推遲執行
        缺點:不利於代碼的閱讀和維護,各個部分之間高度耦合(Coupling),並且每一個任務只能指定一個回調函數
            
    Ⅱ、事件監聽

        f1.on('done', f2);//jQuery寫法,當f1發生done事件,就執行f2

        function f1(){
        setTimeout(function () {
          f1.trigger('done');//執行完成後,當即觸發done事件
        }, 1000);
      }

        優勢:能夠綁定多個事件,每一個事件能夠指定多個回調函數,並且能夠"去耦合"(Decoupling),有利於實現模塊化
        缺點:整個程序都要變成事件驅動型,運行流程會變得很不清晰


    Ⅲ、發佈/訂閱

        jQuery.subscribe("done", f2);//f2向jQuery訂閱"done"信號

        function f1(){
       setTimeout(function () {
         jQuery.publish("done");//f1執行完成後,向jQuery發佈"done"信號,從而引起f2的執行
       }, 1000);
     }


    Ⅳ、Promises對象   

        它的思想是,每個異步任務返回一個Promise對象,該對象有一個then方法,容許指定回調函數。好比,f1的回調函數f2,能夠寫成:

        f1().then(f2);

        對f1進行以下改寫:

        function f1(){
       var dfd = $.Deferred();
       setTimeout(function () {
         dfd.resolve();
       }, 500);
       return dfd.promise;
     }

        優勢:回調函數變成了鏈式寫法,程序的流程能夠看得很清楚,能夠指定多個回調函數,如:

             f1().then(f2).then(f3);
             f1().then(f2).fail(f3);

        缺點:編寫和理解,都相對比較難    

附幾個概念:

1、事件

    事件就是文檔或瀏覽器窗口中發生的一些特定的交互瞬間。

2、註冊事件
    
    註冊事件分爲屬性註冊和方法註冊。

    屬性註冊:1.內嵌在DOM結構裏的屬性賦值

                HTML: <button onclick="sayHello()">點擊</button>

                  JS: function sayHello() {
                             console.log('hello')
                      }

            2.經過JS來指定元素對象的屬性賦值

                document.body.onclick = function (e) {
                    alert("爲body註冊一個點擊事件");
                };

    方法註冊:1.經過addEventListener()方法註冊

                說明:在JS中,window、document、HtmlElement等對象能夠經過addEventListener()方法註冊事件的處理程序。

                語法:EventTarget.addEventListener(eventName, eventHandler, |useCapture )

                參數:

                    ①eventName {string} :所要註冊的事件名稱,不區分大小寫。此名稱不須要像註冊事件屬性那樣前綴加上"on"。如註冊鼠標點擊事件,寫爲click。

                    ②eventHandler {function | function Object} :函數或者函數對象。事件觸發時所須要執行的函數;當使用函數對象屢次註冊同一事件時,只當註冊一遍。

                    ③useCapture {boolean} 可選 :是否處於捕獲階段,默認爲false。

            屢次註冊:addEventListener()方法能爲同一個對象的同一事件註冊屢次。當發生此事件時,註冊的處理事件程序將按照註冊前後順序執行。

               注意:

                    ①IE9以前的IE的不支持此方法,可以使用attachEvent()代替。

                    ②若使用相同的事件處理程序對象屢次註冊在同一個事件上,只算註冊一次。

              例:

                      document.body.addEventListener('click',function(e){
                         console.log('被點擊一');
                    });
                             
                    document.body.addEventListener('click',function(e){
                        console.log('被點擊二');
                    });
                    
                    document.body.click(); // 輸出: 被點擊一 被點擊二

            2.經過attachEvent()方法註冊

              說明:IE9以前的IE版本可經過此方法註冊事件。

              語法:EventTarget.attachEvent(eventName, eventHandler)
              
                      ①eventName {string} :所要註冊的事件名稱,區分大小寫。這裏的名稱跟事件屬性同樣,以"on"開頭,後面跟着事件名稱。如:onclick、onload。
                      
                      ②eventHandler {function | function Object} :函數或者函數對象。事件觸發時所須要執行的函數;當使用函數對象屢次註冊同一事件時,可註冊屢次(addEventListener()方法只當註冊一次)。
              
          屢次註冊:attachEvent()方法能爲同一個對象的同一事件註冊屢次。當觸發此事件時,也會依次執行。

             例:

                  function sayHellow(){
                   console.log('hello');
                }
                document.body.attachEvent('onclick',sayHellow);
                document.body.attachEvent('onclick',sayHellow); // sayHellow第二次註冊同一事件
                document.body.click(); //輸出2次sayHellow函數 :hello hello

2、註銷事件

        JS中,可調用removeEventListener()[註銷addEventListener()] 和 detachEvent()[註銷attachEvent()] 來註銷元素的某個事件指定的處理程序,也能夠給事件屬性賦值null來註銷此事件的全部綁定。
    
        1.removeEventListener(eventName, function Object)
        
        說明:註銷經過addEventListener()註冊的事件處理程序。
    
        語法:EventTarget.removeEventListener(eventName, eventHandlerObj)
        
        參數:
        
            ①eventName {string} :所要註銷的事件名稱,不區分大小寫。此名稱不須要像註冊事件屬性那樣前綴加上"on"。如註冊鼠標點擊事件,寫爲click。
            
            ②eventHandlerObj {function Object} :函數對象。傳入一個函數體是沒有效果的。
    
        例:
            
            // 註銷body click事件的sayHello函數
            document.body.removeEventListener('click',sayHello);

        2.detachEvent(eventName, function Object)

            說明:註銷經過attachEvent()註冊的事件處理程序。

            語法:EventTarget.detachEvent(eventName, eventHandlerObj)
            
            參數:
            
                ①eventName {string} :所要註銷的事件名稱,區分大小寫。這裏的名稱跟事件屬性同樣,以"on"開頭,後面跟着事件名稱。如:onclick、onload。
                
                ②eventHandlerObj {function Object} ::函數對象。傳入一個函數體是沒有效果的。


           例:

                   // 註銷body click事件的sayHello函數
                   document.body.detachEvent('onclick', sayHello);

        3.取消事件

            給對象的事件屬性賦值爲null,可取消此事件的全部註冊過的處理事件程序。

            例:

                // onclick屬性賦值爲null,至關於註銷了onclick事件
                document.body.onclick=null;


參考連接:http://www.ruanyifeng.com/blog/2012/12/asynchronous%EF%BC%BFjavascript.html
                http://www.qdfuns.com/notes/17398/e8a1ce8f863e8b5abb530069b388a158/page/.html


    

javascript

相關文章
相關標籤/搜索