第十二章:異步處理 第十一章:事件系統

瀏覽器與後端的nodejs存在這各類消耗巨大或堵塞線程的行爲。javascript

對於javascript這樣單線程的東西惟一解耦的方法就是提供異步的api。異步的API是怎麼的呢,簡單來講,就是不會當即執行的方法html

比方來講,一個長度爲1000的數組,在for循環內,可能不到幾毫秒就執行完畢,若在後端的其它語言,則耗時更少。但有的時候,咱們不須要這麼快的操做,咱們須要在頁面上用肉眼看到執行的每一步,那就須要異步API。還有些操做,好比加載資源,想快也快不了,它不可能一會兒提供給您,須要等待。但也不能一直這麼等待下去,咱們得容許咱們跳過這些加載資源的邏輯,執行下面的代碼。因而,瀏覽器先作出兩個api,setTimeout,setInterval。後面出現各類事件的回調,它只有用戶執行了某種操做纔會觸發。再以後,就更多了,XHR,postMeeage,webWorkor,setImmediate,requestAnimationFrame等。前端

這些API方法都用一個共同特色,就是擁有一個回調函數,描述一下子幹什麼,有的異步的API還提供了中斷的API。好比clearTime,clearInterval,clearImmediate,cancelAnimationFrame。java

隨着iframe的挖掘和XHR的出現,無縫刷新讓用戶駐留在同一個頁面上的事件愈來愈長,不少功能都機制在一個頁面,實現這些功能,咱們就須要從後端加載數據與模板,來拼裝這些新區域。這些加載數據與模板的請求多是並行的,多是存在依賴的。只有全部的模板與數據存在時,咱們才能順利拼接出HTML子頁面插到正確的位置上。面對這些複雜的流程,前端們不得不發明一些新模式來對應它們。最先被髮明出來的是"回調地獄(callback hell)",這應該是一個技能。事實上,幾乎javascript中的全部異步函數都用到了回調,連續執行幾個異步函數的結果就是層層嵌套的回調函數,以及隨之而來的複雜的代碼。所以,回調就是程序員的goto語句。node

此外,這樣的寫法並非一路順風,若是有一個寫錯了呢?對於javascript這樣單線程的語言,每每是致命的,必須try....catch,但try....catch語句只能捕捉當前拋出的異常,對後來執行的代碼無效。程序員

這裏不難理解,domReady,動畫,Ajax,在骨子裏都是同同樣東西,倘若能將它們抽象成一個東西,很是有用的web

setTimeout與setInterval後端

首先,咱們的深刻學習一個這兩個API。對咱們建立更有用的異步模型很是有用。api

1.若是回調的執行時間大於間隔間隔,那麼瀏覽器會繼續執行它們,致使真正的間隔比原來大一點
2.它們存在一個最小的時鐘間隔,在IE6-IE8中爲15.6ms,後來精準到10ms,IE10爲4ms,其它的瀏覽器相仿。咱們能夠試着求其值。數組

    function test(count, ms){
        var C = 1;
        var time = [new Date() * 1];
        var id = setTimeout(function () {
            time.push(new Date() * 1);
            C += 1;
            if (C <= count) {
                setTimeout(arguments.callee, ms);
            } else {
                clearTimeout(id);
                var tl = time.length;
                var av = 0;
                for (var i = 1; i < tl; i++) {
                    var n = time[i] - time[i - 1]; //收集每一次與上一次相差的時間數
                    av += n; 
                }
                console.log(av / count) ;//取得平均值
            }
        },ms)
    }
    window.onload = function() {
        var id = setTimeout (function(){
            test(100, 1);
            clearTimeout(id)
        },3000)
    }

 各個瀏覽器和系統時間各不相同,咱們或許有辦法改造下setTimeout,利用image死鏈時當即執行onerror回調的狀況進行改造。

    var orig_setTimeout = window.setTimeout;
    window.setTimeout = function (fun, wait) {
        if (wait < 15) {
            orig_setTimeout(fun, wait);
        } else {
            var img = new Image();
            img.onload = img.onerror = function(){
                fun()
            };
            img.src = "data:,foo"
        }
    }

有關零秒延遲,此回調會放在一個能當即執行的時段進行觸發。javascript大致自上而下執行,但中間穿插着DOM渲染,事件迴應等異步代碼,它們將組成一個隊列,零秒延遲將進行隊列操做。

標準瀏覽器都支持額外參數,從第三個參數起,做爲回調傳參傳入!

    setTimeout(function(){
        alert([].slice.call(arguments))
    },10,1,2,4)

Mochikit Deferred(deferred),JSdeferred,jQuery Deferred,Promise/A mmDeferred等框架涉及到太多跨越式的內容,此處僅作備註。

咱們說下異步處理的前景,在異步處理上,yield能夠輕鬆的以同步的形式寫出異步的代碼,只要將它們放到某個函數體內。基於這個思路,有幾個庫被開發出來,例如deferred-generator,taskjs,gens,CO,tamejs,windjs。前四個基於原生的yield,後兩個基於源碼預編譯。

本章內容結束

上一章:第十一章:事件系統  下一章:第十三章: 動畫引擎

相關文章
相關標籤/搜索