国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

JavaScript_框架

Jeffrrey / 1467人閱讀

摘要:框架與庫(kù)庫(kù)解決某個(gè)問(wèn)題而拼湊出來(lái)的一大堆函數(shù)與類的集合。框架一個(gè)半成品的應(yīng)用,直接給出一個(gè)骨架。鎖定,意味著無(wú)法擴(kuò)展。雙鏈?zhǔn)侵杆鼉?nèi)部把回調(diào)分成兩種,一種叫成功回調(diào),用于正常的執(zhí)行,一種叫錯(cuò)誤回調(diào),用于出錯(cuò)時(shí)執(zhí)行。

框架與庫(kù):

庫(kù):解決某個(gè)問(wèn)題而拼湊出來(lái)的一大堆函數(shù)與類的集合。每個(gè)函數(shù)(方法)之間都沒(méi)什么關(guān)聯(lián)。
框架:一個(gè)半成品的應(yīng)用,直接給出一個(gè)骨架。

種子模塊

對(duì)象擴(kuò)展數(shù)組化類型判定簡(jiǎn)單的事件綁定與卸載無(wú)沖突處理模塊加載domReady

命名空間

jQuery對(duì)命名空間的控制:
把命名空間保存到一個(gè)臨時(shí)變量中,后面通過(guò)noConflict放回去.

var _jQuery = window.jQuery, _$ = window.$ // 先把可能存在的同名變量保存起來(lái)

jQuery.extend({
    noConflict (deep) {
        window.$ = _$ // 這時(shí)再放回去
        if (deep) {
            window.jQuery = _jQuery
            return jQuery
        }
    }
})

對(duì)象擴(kuò)展

淺拷貝和深拷貝

在JavaScript中一般約定俗成為:extendmixin

// mass Framework的mix方法
function mix(target, source) {
    var args = [].slice.call(arguments), i = 1, key, ride = typeof args[args.length - 1] === "boolean" ? args.pop() : true
    if (args.length === 1) { // 處理$.mix(hash)的情形
        target = !this.window ? this : {}
        i = 0
    }

    while ((srouce = args[i++])) {
        for (key in source) { // 允許對(duì)象糅雜,用戶保證都是對(duì)象
            if (ride || !(key in target)) {
                target[key] = srouce[key]
            }
        }
    }
    return target
}

數(shù)組化

瀏覽器下存在許多類數(shù)組對(duì)象:

function內(nèi)的arguments

document.forms

form.elements

document.links

select.options

document.getElementsByName

document.getElementsByTagName

childNodes

children (獲取節(jié)點(diǎn)集合HTMLCollection, NodeList)

轉(zhuǎn)換方法:

Array.form()

[].slice.call()
Array.prototype.slice.call()
// jQuery的makeArray
var makeArray = function makeArray(array) {
    var ret = []
    if (array !== null) {
        var i = array.length
        if (i === null || typeof array === "string" || jQuery.isFunction(array) || array.setInterval) {
            ret[0] = array
        } else {
            while (i) {
                ret[--i] = array[i]
            }
        }
        return ret
    }
}

類型判定

JavaScript存在兩套類型系統(tǒng)

基本類型

對(duì)象類型系統(tǒng)

基本類型:undefined,null,string,boolean,number,Set,Map
對(duì)象類型:function,object

基本數(shù)據(jù)類型通過(guò)typeof來(lái)檢測(cè)
對(duì)象類型通過(guò)instanceof來(lái)檢測(cè)

一般通用的檢測(cè)方法:

Object.prototpe.toString.call(arg)

isPlainObject判斷是否為純凈的JavaScript對(duì)象

function isPlainObject (obj) {
    return obj && typeof obj === "object" && Object.getProtypeOf(obj) === Object.prootype
}

domReady

作用:滿足用戶提前綁定事件

方法:

window.onload

mass的DomReady處理方式:

var readyList = []
mass.ready = function (fn) {
    if (readyList) {
        readyList.push(fn)
    } else {
        fn()
    }
}
var readyFn, ready = W3C ? "DOMContentLoaded" : "readystatechange"
function fireReady () {
    for (var i = 0, fn; fn = readyList[i++]; ) {
        fn()
    }
    readyList = null
    fireReady = $.noop // 惰性函數(shù),防止IE9二次調(diào)用 _changeDeps
}

function deScrollCheck () {
    try { // IE下通過(guò)doScollCheck檢測(cè)DOM樹(shù)是否建完
        html.doScroll("left")
        fireReady()
    } catch (e) {
        setTimeout(doScrollCheck)
    }
}

// 在FF3.6之前,不存在readyState屬性
if (!DOC.readyState) {
    var readyState = DOC.readyState = DOC.boyd ? "complete" : "loading"
}
if (DOC.readyState === "complete") {
    fireReady() // 如果在domReady之外加載
} else {
    $.bind(DOC, ready, readyFn = function () {
        if (W3C || DOC.readyState === "complete") {
            fireReady()
            if (readyState) { // IE下不能改寫(xiě)DOC.readyState
                DOC.readyState = "complete"
            }
        }
    })
    if (html.doScroll) {
        try {
            if (self.eval ===parent.eval) {
                deScrollCheck()
            }
        } catch (e) {
            deScrollCheck()
        }
    }
}

無(wú)沖突處理

jQuery的無(wú)沖突處理:

var 
window = this, 
undefined, 
_jQuery = window.jQuery, 
_$ = window.$,
// 把window存入閉包中的同名變量,方便內(nèi)部函數(shù)在調(diào)用window時(shí)不要難過(guò)費(fèi)大力氣查找它
// _jQuery 與 _$用于以后重寫(xiě)
jQuery = window.jQuery = window.$ = function (selector, context) {
    // 用于返回一個(gè)jQuery對(duì)象
    return new jQuery.fn.init(selector, context)
}

jQuery.exnted({
    noConflict (deep) {
        // 引入jQuery類庫(kù)后,閉包外面的window.$與window.jQuery都存儲(chǔ)著一個(gè)函數(shù),它是用來(lái)生成jQuery對(duì)象或domReady后執(zhí)行里面的函數(shù)的
        // 在還沒(méi)有把function賦給它們時(shí),_jQuery與_$已經(jīng)被賦值了,因此它們倆的值必然是undefined,因此放棄控制權(quán),就是用undefined把window.$里面的jQuery系的函數(shù)清除掉。
        window.$ = _$ // 相當(dāng)于window.$ = undefined
        // 需要為noConflict添加一個(gè)布爾值,為true
        if (deep) {
            // 必須用一個(gè)東西接納jQuery對(duì)象與jQuery的入口函數(shù),閉包里面的東西除非被window等宿主對(duì)象引用,否則就是不可見(jiàn)的,因此把比較里面的jQuery return出去,外面用一個(gè)變量接納就可以
            window.jQuery = _jQuery // 相當(dāng)于window.jQuery = undefined
        }
        return jQuery
    }
})
模塊加載系統(tǒng)

AMD規(guī)范

AMD是Asynchronous Module Definition異步模塊定義

異步:有效避免了采用同步加載方式中,導(dǎo)致的頁(yè)面假死現(xiàn)象

模塊定義:每個(gè)模塊必須按照一定的個(gè)是編寫(xiě)

加載器所在路徑

要加載一個(gè)模塊,需要一個(gè)URL作為加載地址,一個(gè)script作為加載媒介。但用戶在require時(shí)都用ID,需要一個(gè)將ID轉(zhuǎn)換為URL的方法。約定URL的合成規(guī)則:

basePath + 模塊ID  + ".js"

在DOM樹(shù)中最后加入script

function getBasePath () {
    var nodes = document.getElementsByTagName("script")
    var node = nodes[nodes.length - 1]
    var src = document.querySelector ? node.src : node.getAttribute("src", 4)
    return src
}

獲取當(dāng)前Script標(biāo)簽

function getCurrentScript (base) { // 為true時(shí)相當(dāng)于getBasePath
    var stack
    try { // FF 可以直接 var e = new Error("test"),但其它瀏覽器只會(huì)生成一個(gè)空Error
        a.b.c() // 強(qiáng)制報(bào)錯(cuò),以便獲取e.stack
    } catch (e) { // Safari的錯(cuò)誤對(duì)象只有l(wèi)ine,sourceId,sourceURL
        stack = e.stack
        if (!stack && window.opera) {
            // opera 9 沒(méi)有e.stack,但有e.Backtrace,不能直接獲取,需要對(duì)e對(duì)象轉(zhuǎn)字符串進(jìn)行抽取
            stack = (`${e}`.match(/of inlked script S+/g) || []).join(" ")
        }
    }
    if (stack) {
        stack = stack.split(/[@]/g).pop() // 取得最后一行,最后一個(gè)空間或@之后的部分
        stack = stack[0] === "(" ? stck.slice(1, -1) : stack.replace(/s/, "") // 去掉換行符
        return stack.replace(/(:d+)?:d+$/i, "") // 去掉行號(hào)與或許存在的出錯(cuò)字符串起始位置
        // 在動(dòng)態(tài)加載模塊時(shí),節(jié)點(diǎn)偶插入head中,因此只在head標(biāo)簽中尋找
        var nodes = (base ? document : head).getElementByTagName("scirpt")
        for (var i = nodes.length, node; node = nodes[--i]) {
            if ((base || node.className) && node.readyState === "interactive") { // 如果此模塊
                return node.className = node.src
            } 
        }
    }
}

require 方法

作用:當(dāng)依賴列表都加載王弼執(zhí)行用戶回調(diào)。

取得依賴列表的第一個(gè)ID,轉(zhuǎn)換為URL。無(wú)論是通過(guò)basePath + ID +".js",還是以映射的方式直接得到。

檢測(cè)此模塊有沒(méi)有加載過(guò),或正在被加載。因此,需要一個(gè)對(duì)象來(lái)保持所有模塊的加載情況。當(dāng)用戶從來(lái)沒(méi)有加載過(guò)此節(jié)點(diǎn),就進(jìn)入加載流程。

創(chuàng)建script節(jié)點(diǎn),綁定onerror,onload,onreadychange等事件判定加載成功與否,然后添加href并插入DOM樹(shù),開(kāi)始加載。

將模塊的URL,依賴列表等構(gòu)建成一個(gè)對(duì)象,放到檢測(cè)隊(duì)列中,在onerror,onload,onreadychange等事件觸發(fā)時(shí)進(jìn)行檢測(cè)。

require的實(shí)現(xiàn):

window.require = $.require = function require(list, factory, parent) {
    var deps = {} // 檢測(cè)它的依賴是否都未2
    var args = [] // 保存依賴模塊的返回值
    var dn = 0 // 需要安裝的模塊數(shù)
    var cn = 0 // 已安裝的模塊數(shù)
    var id = parent || `callback${setTimeout("1")}`
    var parent = parent || basepath // basepath為加載器的路徑
    `${list}`.replace($.rowd, (el) => {
        var url = loadJSCSS(el, parent)
        if (url) {
            dn++
            if (module[url] && module[url].state === 2) {
                cn++
            }
            if (!deps[url]) {
                args.push(url)
                deps[url] = "alogy" // 去重
            }
        }
    })
    modules[id] = { // 創(chuàng)建一個(gè)對(duì)象,記錄模塊的加載情況與其他信息
        id: id,
        factory: factory,
        deps, deps,
        args: args,
        state: 1
    }
    if (dn === cn) { // 如果需要安裝的等于已安裝好的
        fireFactory(id, args, factory) // 安裝到框架中
    } else {
        // 放入到檢測(cè)對(duì)象中,等待 checkDeps處理
        loadings.unshift(id)
    }
    checkDeps()
}

大多數(shù)情況下喜歡使用Dep來(lái)表示消息訂閱器,Depdependence的縮寫(xiě),中文是依賴.

require一次,相當(dāng)于把當(dāng)前的用戶回調(diào)當(dāng)成一個(gè)不用加載的匿名模塊,ID是隨機(jī)生成,回調(diào)是否執(zhí)行,要待deps對(duì)象里面所有值都為2

require方法中重要方法:

loadJSCSS,作用:用于轉(zhuǎn)換ID為URL

fireFactory,執(zhí)行用戶回調(diào)

checkDeps,檢測(cè)依賴是否都安裝好,安裝好就執(zhí)行fireFactory

function loadJSCSS(url, parent, ret, shim) {
    // 1. 特別處理mass | ready標(biāo)識(shí)符
    if (/^(mass|ready)$/.test(url)) {
        return url
    }
    // 2. 轉(zhuǎn)換為完成路勁
    if ($.config.alias[url]) { // 別名
        ret = $.config.alias[url]
        if (typeof ret === "object") {
            shim = ret
            ret = ret.src
        }
    } else {

        if (/^(w+)(d)?:.*/.test(url)) { // 如果本來(lái)就是完整路徑
            ret = url
        } else {
            parent = parent.substr(0, parent.lastIndexOf("/"))
            var tmp = url.charAt(0)
            if (tmp !== "." && tmp !== "/") { // 相對(duì)于更路徑
                ret = basepath + url
            } else if (url.slice(0, 2) === "./") { // 相對(duì)于兄弟路徑
                ret = parent + url.slice(1)
            } lse if (url.slice(0, 2) === "..") { // 相對(duì)于父路徑
                var arr = parent.replace(//$/, "").split("/")
                tmp = url.replace(/..//g, () => {
                    arr.pop()
                    return ""
                })
                ret = `${arr.join("/")}/${tmp}`
            } else if (tmp === "/") {
                ret = `${parent}${url}`  // 相對(duì)于兄弟路徑
            } else {
                $.error(`不符合模塊標(biāo)識(shí)符規(guī)則:${url}`)
            }
        }
    }

    var src = ret.replace(/[?#].*/, "")
    var ext
    if (/.(css|js)$/.test(src)) {
        ext = RegExp.$1
    }
    if (!ext) { // 如果沒(méi)有后綴名,加上后綴名
        src += ".js"
        ext = "js"
    }
    //  開(kāi)始加載JS 或 CSS
    if (ext === "js") {
        if (!modules[src]) { // 如果之前沒(méi)有加載過(guò)
            modules[src] = {
                id: src,
                parent: parent,
                exports: {}
            }
            if (shim) { // shim機(jī)制
                require(shim.deps || "", () => {
                    loadJS(src, () => {
                        modules[src].state = 2
                        modules[src].exports = type shim.exports === "function" ? shim.exports() : window[shim.exports]
                        checkDeps()
                    })
                })
            } else {
                loadJS(src)
            }
        }
        return src
    } else {
        loadCSS(src)
    }
}

function loadJS(url, callback) {
    // 通過(guò)script節(jié)點(diǎn)加載目標(biāo)文件
    var node = DOC.createElement("script")
    node.className = moduleClass // 讓getCurrentScript只處理類名為moduleClass的script節(jié)點(diǎn)
    node[W3C ? "onload" : "onreadystatechange"] = function () {
        if (W3C || /loaded|complete/i.test(node.readyState)) {
            // facotrys里面裝著define方法的工廠函數(shù)(define(id?, deps?, factory))
            var factory = factorys.pop()
            factory && factory.delay(node.src)
            if (callback) {
                callback()
            }
            if (checkFail(node, false, !W3C)) {
                $.log(`已成功加載${node.src}`, 7)
            }
        }
    }
    node.onerror = function () {
        checkFail(node, true)
    }
    // 插入到head的第一個(gè)節(jié)點(diǎn)前,防止IE6下標(biāo)簽沒(méi)閉合前使用appendChild拋錯(cuò)
    node.src = url
    head.insertBefore(node, head.firstChild)
}

function checkDeps () {
    loop: for (var i = loadings.length, id; id = loadings[--i];) {
        for (var key in deps) {
            if (hasOwn.call(deps, key) && modules[key].state !== 2) {
                continue loop
            }
        }
        //  如果deps是空對(duì)象或者其依賴的模塊的狀態(tài)都是2
        if (obj.state !== 2) {
            loading.splice(i, 1) //  必須先移除再安裝,防止在IE下DOM樹(shù)建完成后手動(dòng)刷新頁(yè)面,會(huì)多次執(zhí)行它
            fireFactory(obj.id, obj.args, obj.factory)
            checkDeps() // 如果成功,則再執(zhí)行一次,以防止有些模塊就差本模塊沒(méi)有安裝好
        }
    }
}

function fireFactory (id, deps, factory) { // 從 modules中手機(jī)各模塊的返回值執(zhí)行factory
    for (var i = 0, array = [], d; d = deps[i++];) {
        array.push(modules[d].exports)
    }
    var module = Object(modules[id])
    var ret = factory.apply(global, array)
    modules.state = 2
    if (ret !== void 0) {
        modules[id].exports = ret
    }
    return ret
}

define方法

define需要考慮循環(huán)依賴的問(wèn)題。比如:加載A,要依賴B與C,加載B,要依賴A與C。這時(shí)A與B就循環(huán)依賴了。A與B在判定各自的deps中的鍵值都是2時(shí)才執(zhí)行,結(jié)果都無(wú)法執(zhí)行了。

window.define = $.define = function define (id, deps, factory) {
    var args = $.slice(arguments)
    if (typeof id === "string") {
        var _id = args.shift()
    }
    if (typeof args[0] === "boolean") { // 用于文件合并,在標(biāo)準(zhǔn)瀏覽器中跳過(guò)不定模塊
        if (args[0]) {
            return
        }
        args.shift()
    }
    if (typeof args[0] === "function") { // 上線合并后能直接的到模塊ID,否則尋找當(dāng)前正在解析中的script節(jié)點(diǎn)的src作為模塊ID
        args.unshift([])
    }
    // 除了Safari外,都能直接通過(guò)getCurrentScript一步到位得到當(dāng)前執(zhí)行的script節(jié)點(diǎn),Safari可通過(guò)onload+delay閉包組合解決
    id = modules[id] && modules[id].state >= 1 ? _id : getCurrentScript()
    factory = args[1]
    factory.id = _id // 用于調(diào)試
    factory.delay = function (id) {
        args.push(id)
        var isCycle = true
        try {
            isCycle = checkCycle(modules[id].deps, id)
        } catch (e) {}
        if (isCycle) {
            $.error(`${id}模塊與之前的某些模塊存在循環(huán)依賴`)
        }
        delete factory.delay // 釋放內(nèi)存
        require.apply(null, args)
    }
    if (id) {
        factory.delay(id, args)
    } else {
        factorys.push(factory)
    }
}

checkCycle方法:

function checkCycle (deps, nick) {
    // 檢測(cè)是否存在循環(huán)依賴
    for (var id in deps) {
        if (deps[id] === "alogy" && modules[id].state !== 2 && (id === nick || checkCycle(modules[id].deps, nick))) {
            return true
        }
    }
}
語(yǔ)言模塊

字符串

類型:

與標(biāo)簽無(wú)關(guān)的實(shí)現(xiàn):carAt.charCodeAt,concat,indexOf,lastIndexof,localCompare,match,replace,serach,slice,split,substring,toLocaleLowerCase,toLocaleUpperCase,toLowerCase,toUpperCase以及從Object繼承回來(lái)的方法,如toString,valueOf。

與標(biāo)簽有關(guān)的實(shí)現(xiàn),都是對(duì)原字符串添加一對(duì)標(biāo)簽:anchorbigblinkboldfixedfontcolor,italics,small,strike,sub,sup

后來(lái)添加或?yàn)闃?biāo)準(zhǔn)化的瀏覽器方法: trim,quote,toSource,trimLeft,trimRight

truncate
用于對(duì)字符進(jìn)行階段處理,當(dāng)超過(guò)限定長(zhǎng)度,默認(rèn)添加三個(gè)點(diǎn)號(hào)或其它。

function truncate (target, length = 30, truncation) {
    truncation = truncation === void(0) ? "..." : truncation
    return traget.length > length ? `${target.slice(0, length - target.length)}${truncation}` : `${target}`
}

cameliae
轉(zhuǎn)換為駝峰分格

function camelize (target) {
    if (target.indexOf("-") < 0 && target.indexOf("_") < 0) {
        return target
    }
    return target.replace(/[-_][^-_]/g, (match) => {
        return match.charAt(1).toUpperCase()
    })
}

dasherize
轉(zhuǎn)為連字符風(fēng)格,亦即CSS變量的風(fēng)格

function underscored (target) {
    return target.replace(/([a-zd]([A-Z]))/g, "$1_$2").replace(/-/g, "_").toLowerCase()
}
function dasherize (target) {
    return underscored(target).replace(/_/g, "-")
}

capitalize
首字母大寫(xiě)

function capitalize (target) {
    return target.charAt(0).toUpperCase() + target.substring(1).toLowerCase()
}

stripTags
移除字符串中 html標(biāo)簽

function stripTags (target) {
    return String(target || "").replace(/<[^>]+>/g, "")
}

stripScripts
移除字符串中所有的script標(biāo)簽

function stripScripts (target) {
    return Sting(target || "").replace(/]*>([Ss]*?)/img, "")
}

escapeHTML
將字符串經(jīng)過(guò)html轉(zhuǎn)義得到合適在頁(yè)面中顯示的內(nèi)容。比如:<替換<

function escapeHTML (target) {
    return target.replace(/&/g, "&")
                                .replace(//g, ">")
                                .replace(/"/g, """)
                                .replace(/"/g, "'")
}

unescapeHTML
將字符串中的html實(shí)體字符還原為對(duì)應(yīng)字符。

function unescapeHTML (target) {
    return target.replace(/"/g, """)
        .replace(//g, ">")
        .replace(/&/g, "&") // 處理轉(zhuǎn)義的中文和實(shí)體和實(shí)體字符
        .replace(/&#([d]+);/g, function ($0, $1) {//
            return String.fromCharCode(parseInt($1, 10))
        })
}

escapeRegExp
將字符串安全格式化為正則表達(dá)式的源碼

function escapeRegExp (target) {
    return target.replace(/([-.*+?^{}()|[]/])/g, "$1")
}

format

function formate (str, object) {
    // var array = Array.prototype.slice.call(arguments, 1)
    var array = Array.of(arguments)
    return str.replace(/?{{([^{}]+)}}/gm, (match, name) => {
        if (`${match.charAt(0)}` === "") {
            return match.slice(1)
        }    
        var index = Number(name)
        if (index >= 0) {
            return arry[index]
        }
        if (object && object[name] !== void 0) {
            return object[name]
        }
        return ""
    })
}

trim
去除前后端空格

function trim (str) {
    str.replace(/^ss*/, "").replace(/ss*$/, "")
}
function trime (str) {
    return str.replace(/^s+|s+/g, "")
}
function trim (str) {
    var whitespace = " 

	fx0bxa0u2000u2001u2002u2003
u2004u2005u2006u2007u2008u2009u200au200bu2028u2029u3000"
    for (var i = 0; i < str.length; i++) {
        if (whitespace.indexOf(str.charAt(i)) === -1) {
            str = str.substring(i)
            break
        }
    }
    for (i = str.length - 1; i >= 0; i--) {
        if (whitespace.indexOf(str.charAt(i)) === -1) {
            str = str.substring(0, i + 1)
            break
        }
    }
    return  whitespace.indexOf(str.charAt(0)) === -1 ? str : ""
}

數(shù)組

removeAt

/**
 * 移除數(shù)組中指定位置的元素
 * @param  {[type]} target [description]
 * @param  {[type]} index  [description]
 * @return {[type]}        [description]
 */
function removeAt (target, index) {
    return !!target.splice(index, 1).length
}

shffle
對(duì)數(shù)組進(jìn)行洗牌

function shuffle (target) {
    var j, x, i = target.length
    for (; i > 0; j = parseInt(Math.random() * i), x = target[--i], target[i] = target[j], target[j] = x) {
        return target
    }
}

random
從數(shù)組中隨機(jī)抽選一個(gè)元素出來(lái)

function random (target) {
    return target[Math.floor(Math.random() * target.length)]
}

flatten
對(duì)數(shù)組進(jìn)行平坦化處理

function flatten (target) {
    var result = []
    target.forEach((item) => {
        if (Array.isArray(item)) {
            result = result.concat(flatten[item])
        } else {
            result.push(item)
        }
    })
    return result
}

unique
對(duì)數(shù)組進(jìn)行去重操作。(一維數(shù)組)

function unique (target) {
    return Array.form(new Set(target))
}
function unique (target) {
    var result = []
    loop: for (var i = 0, n = target.length; i < n; i++) {
        for (var x = i + 1; x < n; x++) {
            if (target[x] === target[i]) {
                continue loop
            }
        }
        result.push(target[i])
    }
    return result
}

compact
過(guò)濾數(shù)組中的nullundefined,但不影響原數(shù)組

function compact (target) {
    return target.filter((el) => {
        return el !== null
    })
}

日期

isLeapYear
判斷是否為閏年

function isLeapYear (date) {
    return new Date(date.getFullYear(), 2, 0).getDate() === 29
}

getDaysInMonth
獲取當(dāng)前月份的天數(shù)

function getDaysInMonth (date) {
    return new Date(date.getFullYear(), date.getMonth() + 1, 0).getDate()
}
類工廠

JS對(duì)類的支持

function Instance () {}
var instance = new Instance()

new操作時(shí)發(fā)生:

創(chuàng)建一個(gè)空對(duì)象instance

instance.proto__ = instanceClass.prototype

將構(gòu)造器函數(shù)里面的 this = instance

執(zhí)行構(gòu)造器里面的代碼

判定有沒(méi)有返回值,沒(méi)有返回值默認(rèn) undefined,如果返回值為復(fù)合數(shù)據(jù)類型,則直接返回,否則返回this。

ES5屬性描述符

新增加的API:

Object.keys // 用于收集當(dāng)前對(duì)象的遍歷屬性(不包括原型鏈上的),以數(shù)組形式返回
Object.getOwnPropertyNames // 用于收集當(dāng)前對(duì)象不可遍歷屬性與可遍歷屬性(不包括原型鏈上的),以數(shù)組形式返回
Object.getPrototypeOf 
Object.defineProperty
Object.defineProperties
Object.getOwnPropertyDescriptor
Object.create
Object.scal // 不準(zhǔn)刪除已有的本地屬性,內(nèi)部實(shí)現(xiàn)就是遍歷一下,把每個(gè)本地屬性的configurabel改為false
Object.freeze // 原有本地屬性不讓修改,內(nèi)部實(shí)現(xiàn)就是遍歷一下,把每個(gè)本地屬性的writeable也該為false
Object.perventExtensions // 阻止添加本地屬性,如果本地屬性被刪除,也無(wú)法再加回來(lái)
Object.isSealed // 判斷一個(gè)對(duì)象是否被鎖定。鎖定,意味著無(wú)法擴(kuò)展。
Object.isFrozen
Object.isExtensible

模擬Object.defineProperty

if (typeof Object.defineProperty !== "function") {
    Object.defineProperty = function (obj, prop, desc) {
        if ("value" in desc) {
            obj[prop] = desc.value
        }
        if ("get" in desc) {
            obj.__defineGetter__(prop, desc.get)
        }
        if ("set" in desc) {
            obj.__defineSetter__(prop, desc.set)
        }
        return obj
    }
}

模擬Object.defineProperties

if (typeof Object.defineProperties !== "function") {
    Object.defineProperties = functionb (obj, descs) {
        for (var prop in descs) {
            if (descs.hsaOwnProperty(prop)) {
                Object.defineProperty(obj, prop, descs[prop])
            }
        }
    }
}

模擬Object.create
作用:用于創(chuàng)建一個(gè)子類的原型
第一個(gè)參數(shù)為父類的原型,第二個(gè)是子類另外要添加的屬性的配置對(duì)象

if (typeof Object.create !== "funcion") {
    Object.create = function (prototype, descs) {
        fnctino F () {}

        F.prototype = prototype
        var obj = new F()
        if (descs !== null) {
            Object.defineProperties(obj, descs)
        }
        return obj
    }
}

IE下模擬Object.create

var createEmpty
var supprotsProto = Object.prototype.__proto__ = null
if (supprotsProto || typeof document === "undefined") {
    createEmpty = function () {
        return {
            "__proto__": null
        }
    }
} else {
    // 因?yàn)闊o(wú)法讓一個(gè)對(duì)象繼承自一個(gè)不存在的東西,它最后肯定要回溯到Object.prototype,
    // 那么就從一個(gè)新執(zhí)行環(huán)境中盜取一個(gè)Object.prototype,把它的所有原型屬性都砍掉,這樣它的實(shí)例就
    // 既沒(méi)有特殊屬性,也沒(méi)有什么原型屬性。只剩下一個(gè)__proto__,值為null
    createEmpty = (() => {
        var iframe = document.createElement("iframe")
        var parent = document.body || document.documentElement
        iframe.style.display = "none"
        parent.appendChild(iframe)
        iframe.src = "javascript:"
        var mepty = iframe.contentWindow.Object.prototype
        parent.removeChild(iframe)
        iframe = null
        delete empty.constructor
        delete empty.hasOwnProperty
        delete empty.propertyIsEnumerable
        delete empty.isPrototypeOf
        delete empty.toLocaleString
        delete empty.toString
        delete empty.valueOf
        empty.__proto__ = null

        function Empty () {}
        Empty.prototype = empty

        return function () {
            return new Empty()
        }
    })()
}
異步處理

對(duì)于JavaScript這樣單線程的東西唯一的解耦方法就是提供異步API。
異步API,簡(jiǎn)單的說(shuō):不會(huì)立即執(zhí)行的方法。

setTimeout 與setInterval

如果回調(diào)的執(zhí)行時(shí)間大于間隔時(shí)間,那么瀏覽器會(huì)繼續(xù)執(zhí)行它們,導(dǎo)致真正的間隔時(shí)間比原來(lái)的大一點(diǎn).

它們存在一個(gè)最小的時(shí)鐘間隔,在IE6~IE8中為15.6ms,后來(lái)精準(zhǔn)到10ms,IE10為4ms,其它瀏覽器相仿.

有關(guān)零秒延遲,此回調(diào)將會(huì)放到一個(gè)能立即執(zhí)行的時(shí)段進(jìn)行觸發(fā),JavaScript代碼大體上自頂向下執(zhí)行,但中間穿插著有關(guān)DOM渲染,事件回應(yīng)等異步代碼它們將組成一個(gè)隊(duì)列,零秒延遲將會(huì)實(shí)現(xiàn)插隊(duì)操作

不寫(xiě)第二個(gè)參數(shù),瀏覽器自動(dòng)配時(shí)間,在IE,F(xiàn)ireFox中,第一次可能給個(gè)很大數(shù)字,100ms上下,往后會(huì)縮小到最小時(shí)間間隔,Safari,Chrome,Opera則多為10ms上下,F(xiàn)ireFox中,setInterval不寫(xiě)第二個(gè)參數(shù),會(huì)當(dāng)作setTimeout處理,只執(zhí)行一次。

支持額外參數(shù),從第三個(gè)參數(shù)起,作為回調(diào)的傳參傳入

setTimeout方法的時(shí)間參數(shù)若為極端值(如負(fù)數(shù),0,或者極大的正數(shù)),會(huì)立即執(zhí)行。

算出最小間隔時(shí)間

function test (count, ms) {
    var c = 1
    var time = [new Date() * 1]
    var id = setTimeout(() => {
        time.push(new Date() * 1)
        c += 1
        if (c <= count) {
            setTimeout(arguments.callee, ms)
        } else {
            clearTimeout(id)
            var t1 = time.length
            var av1 = 0
            for (var i = 1; i < t1; i++) {
                var n = time[i] - time[i - 1] // 收集每次與上一次相差的時(shí)間數(shù)
                av1 += n
            }
            console.log(av1 / count) // 求平均值
        }
    }, ms)
}

window.onload = () => {
    var id = setTimeout(() => {
        test(100, 1)
        clearTimeout(id)
    }, 3000)
}

如果閑最短時(shí)間間隔太大,可以改造一下setTimeout。
方法:利用image死鏈時(shí)立即執(zhí)行onerror回調(diào)的情況進(jìn)行改造。

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

Deferred

是一個(gè)雙鏈參數(shù)加工的流水線模型。雙鏈?zhǔn)侵杆鼉?nèi)部把回調(diào)分成兩種,一種叫成功回調(diào),用于正常的執(zhí)行,一種叫錯(cuò)誤回調(diào),用于出錯(cuò)時(shí)執(zhí)行。各自組成兩個(gè)隊(duì)列

添加回調(diào)時(shí)是一組組添加的,每組回調(diào)的參數(shù)都是上一組回調(diào)的處理結(jié)果,當(dāng)然只有第一組的參數(shù)是用戶傳入的。

流水線的解釋,每個(gè)回調(diào)可能不是緊挨著執(zhí)行,有時(shí)需要耗些時(shí)間,可能是異步API引起的,也可能是調(diào)用了如wait這樣的方法。假若出錯(cuò),由后一組的錯(cuò)誤回調(diào)捕獲處理,沒(méi)有問(wèn)題嘗試再轉(zhuǎn)回成功隊(duì)列。

var Deferred = function (canceller) {
    this.chain = []
    this.id = setTimeout("1")
    this.fired = -1
    this.paused = 0
    this.canceller = canceller
    this.silentlyCancelled = false
    this.chained = false
}

function curry (fn, scope, args) {
    return function () {
        var argsv = [].concat.apply(args, arguments)
        return fn.apply(scope, argsv)
    }
} 

Deferred.prototype = {
    // 3種狀態(tài),未觸發(fā),觸發(fā)成功,觸發(fā)失敗
    state: function () {
        if (this.fired === -1) { // 未觸發(fā)
            return "unfired"
        } else if (this.fired === 0) { // 觸發(fā)成功
            return "sucess"
        } else { // 觸發(fā)失敗
            retur "error"
        }
    },

    // 取消觸發(fā),類似于ajax的abort
    cancel: function (e) {
        if (this.fired === -1) { // 只有未觸發(fā)時(shí)才能cancel掉
            if (this.canceller) {
                this.canceller(this)
            } else {
                this.silentlyCancelled = ture
            }
            if (this.fired === -1) {
                if (!(e instanceof Error)) {
                    e = new Error(e + "")
                }
                this.errback(e)
            }
        } else if ((this.fired === 0) && (this.results[0] instaceof Deferred)) {
            this.results[0].cancel(e)
        }
    },

    // 決定是用那個(gè)隊(duì)列 
    _resback: function (res) {
        this.fired = ((res instanceof Error) ? 1 : 0)
        this.results[this.fired] = res
        if (this.paused === 0) {
            this._fire()
        }
    },

    // 判斷是否觸發(fā)過(guò)
    _check: function () {
        if (this.fired != -1) {
            if (!this.silentlyCancelled) {
                throw new "此方法已經(jīng)被調(diào)用過(guò)!"
            }
            this.silentlyCancelled = false
            return
        }
    },

    // 觸發(fā)成功隊(duì)列
    callback: function (res) {
        this._check()
        if (res instanceof Deferred) {
            throw new Error("Deferred instances can only be chained if they are the result of a callback")
        }
        this._resback(res)
    },

    // 觸發(fā)錯(cuò)誤隊(duì)列
    errback: function (res) {
        this._check()
        if (res instanceof Deferred) {
            throw new Error("Deferred instances can only be chained if they are the result of a ballback")
        }
        if (!(res instanceof Error)) {
            res = new Error(res + "")
        }
        this._resback(res)
    },

    // 同時(shí)添加成功與錯(cuò)誤回調(diào)
    addBoth: function (a, b) {
        b = b || a
        return this.addCallbacks(a, b)
    },

    // 添加成功回調(diào)
    addCallback: function (fn) {
        if (argynebts.length > 1) {
            var args = [].slice.call(argumnets, 1)
            fn = curry(fn, window, args)
        }
        return this.addCallbacks(fn, null)
    },

    // 添加錯(cuò)誤回調(diào)
    addErrback: function (fn) {
        if (arguments.length > 1) {
            var args = [].slice.call(arguments, 1)
            fn = curry(fn, window,argus)
        }
        return this.addCallbacks(null, fn)
    },

    // 同時(shí)添加成功回調(diào)與錯(cuò)誤回調(diào),后來(lái)Promise的then方法就是參考它設(shè)計(jì)
    addCallbacks: function (cb, eb) {
        if (this.chained) {
            throw new Error("Chained Deferreds can not be re-used")
        }
        if (this.finalized) {
            throw new Error("Finalized Deferreds can not be re-used")
        }
        this.chain.push([cb, eb])
        if (this.fired >= 0) {
            this._fire()
        }
        return this
    },

    // 將隊(duì)列的回調(diào)依次觸發(fā)
    _fire: function () {
        var chain = this.chain
        var fired = this.fired
        var res = this.results(fired)
        var self = this
        var cb = null
        while (chain.length > 0 && this.paused === 0) {
            var pair = chain.shift()
            var f = pair[fired]
            if (f === null) {
                continue
            }
            try {
                res = f(res)
                fired = ((res instanceof Eorror ? 1 : 0))
                if (res instanceof Deferred) {
                    cb = function (res) {
                        self.paused--
                        self_resback(res)
                    }
                    this.paused++
                }
            } catch (err) {
                fired = 1
                if (!(err instanceof Error)) {
                    try {
                        err = new Error(err + "")    
                    } catch (e) {
                        alert(e)
                    }
                }
                res = err
            }
        }
        this.fired = fired
        this.result[fired] = res
        if (cb && this.paused) {
            res.addBoth(cb)
            res.chained = true
        }
    }
}

觸發(fā)這些回調(diào)時(shí)通過(guò)callback,與ertback方法,通常放到XMLHttpRequres對(duì)象的回調(diào)中執(zhí)行它們。查看XMLHttpRequesetstatus(狀態(tài)碼),即便是成功返回還是服務(wù)器錯(cuò)誤,決定調(diào)用Deferred對(duì)象的callback還是ertback,將返回值傳入到它們里面

JS Deferred

JS Deferred實(shí)現(xiàn)形態(tài)基本奠定了后來(lái)成為Promise/A的范式

每一個(gè)回調(diào)都至少涉及一個(gè)Deferred

github源碼:jsdeferred

function Deferred () {
    return (this instanceof Deferred) ? this.init() : new Deferred()
}
Deferred.ok = function (x) {
    return x
}
Deferred.ng = function (x) {
    throw x
}

Deferred.wait = function (n) {
    var d = new Deferred()
    var t = new Date()
    var id = setTImeout(function () {
        d.call((new Date()).getTime() - t.getTime())
    }, n * 1000)
    d.canceller = function () {
        clearTimeout(id)
    }
    return d
}

Deferred.register = function (name, fun) {
    this.prototype[name] = function () {
        var a = arguments
        return this.next(fcuntion () {
            return fun.apply(this, a)
        })
    }
}

Deferred.parallel = function (dl) {
    var isArray = false // 它可以放一個(gè)數(shù)組或?qū)ο螅騈個(gè)函數(shù),或Deferred對(duì)象做參數(shù)
    if (arguments.length > 1) {
        dl = Array.prototype.slice.call(arguments)
        isArray = true
    } else if (Array.isArray && Array.isArray(dl) || typeof dl.length === "number") {
        isArray = true
    }
    // 并歸用的Deferred
    var ret = new Deferred()
    // 收集結(jié)果
    var value = {}
    // 計(jì)數(shù)器
    var num = 0
    for (var i in dl) {
        if (dl.hasOwnPrototpye(i)) {
            (funcion (d, i) {
                // 通通轉(zhuǎn)成Deferred對(duì)象
                if (typeof d === "function") {
                    dl[i] = d = Deferred.next(d)  // 轉(zhuǎn)換為Deferred對(duì)象
                }
                d.next(function (v) { // 添加兩個(gè)回調(diào),next與error
                    values[i] = v
                    if (--num <= 0) {
                        if (isArray) {
                            values.length = dl.length
                            values = Array.prototype.slice.call(values, 0)
                        }
                        ret.call(values)
                    }
                }).error(funciton (e) {
                    ret.fail(e)
                })
                num++
            })(dl[i], i)
        }
    }
    //  如果里面沒(méi)有內(nèi)容立即執(zhí)行
    if (!num) {
        Deferred.next(function () {
            ret.call()
        })
        ret.canceller = function () {
            for (var i in dl) 
                if (dl.hasOwnProperty(i)) {
                    dl[i].cancel()
                }
        }
    }
    return ret
}

Deferred.register("wait", Deferred.wait)

// IE的提速
Deferred.next_faster_way_readystatechange = (typeof window === "object") && (localtion.protocol == "http:") && window.VBArray && funciton (fun) { // MSIE
    var d = new Deferred()
    var t = (new Date()).get()
    // 瀏覽器的發(fā)請(qǐng)求數(shù)是有限的在IE6,IE7中為2-4。IE8,IE9為6
    // 如果超出這數(shù)目,可能造成阻塞,必須待這幾個(gè)處理完之后才繼續(xù)處理
    // 因此這里添加一個(gè)閥值,如果上次與這次間隔超過(guò)150還沒(méi)處理完
    // 那么久退化到原始的setTimeout方法
    if (t - arguments.callee._perv_timeout_called < 150) {
        var cancel = false
        // 創(chuàng)建一個(gè)script節(jié)點(diǎn),加載一個(gè)不存在的資源來(lái)引發(fā)onerror
        // 由于舊版本IE不區(qū)分onerror與onload,都只會(huì)觸發(fā)onredaystatechange
        // 只要造成異步效果,讓用戶有足夠時(shí)間綁定回調(diào)就行
        var script = document.createElement("script")
        script.type = "text/javascript"
        script.src = "data:text/javascript"
        script.onreaydstatechange = function () {
            if (!cancel) {
                d.canceller()
                d.call()
            }
        }
        // 清掉事件與移出DOM樹(shù)
        d.canceller = function () {
            if (!cancel) {
                cancel = true
                script.onreaydstatechange = null
                document.body.removeChild(scirpt)
            }
        }
        // Deferred最好延遲到domReady或onload后執(zhí)行
        document.body.appendChild(scirpt)
    } else {
        arguments.callee._prev_timeout_called = t
        var id = setTimeout(function () {
            d.call()
        }, 0)
        d.canceller = function () {
            clearTimeout(id)
        }
    }
    if (fun) {
        d.callback.on = fun
    }
    return d
}

// 標(biāo)準(zhǔn)瀏覽器的提速
Deferred.next_faster_way_Image = (tyupeof window === "object") && (typeof(Image) !== "undefined") && !window.opera && document.addEventListener && function (fun) {
    // 用于opera外的標(biāo)準(zhǔn)瀏覽器
    var d = new Deferred()
    var img = new Image()
    // 創(chuàng)建一個(gè)image加載一個(gè)不存在的圖片(為了防止萬(wàn)分之一的圖片存在的情況,onload也綁上了)
    var handler = function () {
        d.canceller()
        d.call()
    }
    img.addEventListener("load", handler, false)
    img.addEventListener("error", handler, false)
    d.canceller = function () {
        img.removeEventListener("load", handler, false)
        img.removeEventListener("error", handler, false)
    }
    img.src = "data:image/png," + Math.random()
    if (fun) {
        d.callback.ok = fun
    }
    return d
}

Deferred.prototype = {
    init: function () {
        this._next = null
        this.callback = {
            ok: Deferred.ok
            ng: Deferred.ng
        }
        return this
    },

    next: function (fun) {
        return this._post("ok", fun)
    },

    error: function (fun) {
        return this._post("ng", fun)
    },

    call: function (val) {
        return this._fire("ok", val)
    },

    fail: function (err) {
        return this._fire("ng", err)
    },

    cancel: function () {
        (this.canceller || function () {})()
        return this.init()
    },

    _post: function (okng, fun) {
        this._next = new Deferred()
        this._next.callback[okng] = fun
        return this._next
    },

    _fire: function (okng, value) {
        var next = "ok" // 每次都嘗試從成功隊(duì)列執(zhí)行
        try { // 決定是ing成功的回調(diào)還是錯(cuò)誤的回調(diào)
            value = this.callback[okng].call(this, value)
        } catch (e) {
            next = "ng"
            value = e
        } 
        if (value instanceof Deferred) {
            value._next = this._next // 把`_next`對(duì)象進(jìn)行轉(zhuǎn)移,防止它在setTimeout中執(zhí)行。
        } else { // 執(zhí)行鏈表中的下一個(gè)Deferred的_fire
            if (this._next) {
                this._next.fire(next, value)
            }
        }
        return this
    }
}

Deferred鏈的實(shí)現(xiàn)
它每綁定一個(gè)回調(diào)函數(shù)就需要一個(gè)全新的Deferred對(duì)象,從而形成一個(gè)Deferred鏈,兩個(gè)Deferred能連到一塊,取決于兩個(gè)東西:

當(dāng)前Deferred實(shí)例在_fire方法執(zhí)行callback時(shí)得到的屬性

_next屬性

JSDeferred的并歸結(jié)果
parallel 可以實(shí)現(xiàn)多個(gè)嵌套請(qǐng)求.
它里面存在一個(gè)數(shù)組,用于收集一個(gè)階段N個(gè)并行執(zhí)行的回調(diào)的結(jié)果,同時(shí)應(yīng)該還有一個(gè)計(jì)數(shù)器,如果回調(diào)都成功執(zhí)行了開(kāi)始執(zhí)行“回調(diào)的回調(diào)”,這個(gè)回調(diào)是框架提供的,然后處理所有收集到的結(jié)果,放進(jìn)用戶綁定的后續(xù)回調(diào)中。

JSDeferred的性能提速
JSDeferred的每一個(gè)對(duì)象都允許自動(dòng)執(zhí)行它綁定的回調(diào),不需要手動(dòng)調(diào)用call,fail方法。但它們不是立即執(zhí)行,而是異步的,它需要等待用戶nexterrot綁定好所需要的回調(diào).

Promise/A 與 mmDeferred

Promise/A屬于Promise規(guī)范,而Promise規(guī)范則又隸屬于CommonJS

Promise/A一個(gè)帶有then方法的對(duì)象,它擁有3個(gè)狀態(tài)。pending,fulfilled,rejected
一開(kāi)始是pending,執(zhí)行then方法后,當(dāng)前回調(diào)被執(zhí)行,會(huì)進(jìn)入fulfiledrejected狀態(tài)

then方法可傳入兩個(gè)函數(shù),一個(gè)是成功執(zhí)行時(shí)執(zhí)行,第一個(gè)失敗時(shí)執(zhí)行,分別叫做onFulfill,onRejectthen還有第3個(gè)參數(shù)叫做onNotify,它不會(huì)改變對(duì)象的狀態(tài)。
then方法在添加onFufillonReject會(huì)返回一個(gè)新的Promise對(duì)象,這樣一來(lái),就能形成一個(gè)Promise

為了防止Promise鏈還沒(méi)有形成就被用戶觸發(fā)回調(diào),強(qiáng)烈要求使用setTimeoutsetInmmediate,process.nextTick等異步API來(lái)提供足夠的構(gòu)建時(shí)間。

此外,在實(shí)現(xiàn)Promise/A+時(shí),漸漸歸納成添加all,any等方法,來(lái)并歸結(jié)果或處理競(jìng)態(tài)狀態(tài)。

function Deferred () {
    return (this instanceof Deferred) ? this.init() : new Deferred()
}
Deferred.ok = function (x) {
    return x
}
Deferred.ng = function (x) {
    throw x
}
Deferred.prototype = {
    init () {
        this.callback = {
            resolve: Deferred.ok,
            reject: Deferred.ng,
            notify: Deferred.ok,
            ensure: Deferred.ok
        }

        this.state = "pending"
        this.dirty = false
        this.promise = {
            then (onResolve, onReject, onNotify) {
                return this._post(onResolve, onReject, onNotify)
            },
            otherwise (onReject) {
                return this._post(null, onReject, null)
            },
            ensure (onEnsure) {
                return this._post(0, 0, 0, onEnsure)
            },
            _next: null
        }
        return this
    },
    _post (fn0, fn1, fn2, fn3) {
        var deferred
        if (!this.dirty) {
            deferred = this
        } else {
            deferred = this.promise._next = new Deferred()
        }
        var index = -1
        var fns = argument
        "resolve,reject,notify, ensure".replace(/w+/g, (method) => {
            var fn = fns[++index]
            if (typeof fn === "function") {
                deferred.callback[method] = fn
                deferred.dirty = true
            }
        })
        return deferred.promise
    },
    _fire (method, value) {
        var next = "resolve"
        try {
            if (this.state == "pending" || method === "notify") {
                var fn = thi.callback[method]
                value = fn.call(this, value)
                if (method !== "notify") {
                    this.state = method
                } else {
                    next = "notify"
                }
            }
        } catch (e) {
            next = "reject"
            value = e
        }
        var ensure = this.callback.encure
        if (Deferred.ok !=== ensure) {
            try {
                encure.call(this)
            } catch (e) {
                next = "reject"
                value = e
            }
        }

        if (Deferred.isPromise(value)) {
            value._next = this.promise._next
        } else {
            if (this.promise._next) {
                this.promise._next._fire(next, value)
            }
        }
        return this
    }
}
"resoluve,reject,notify".replace(/w+/g, (method) => {
    Deferred.prototpe[method] = (val) => {
        if (!this.dirty) {
            setTimeout(() => {
                this._fire(method, val)
            }, 0)
        } else {
            return this._fire(method, val)
        }
    }
})

Deferred.isPromise = function (obj) {
    return !!(obj && typeof obj.then === "function")
}

function some (any, promises) {
    var deferred = Deferred()
    var n = 0
    var result = []
    var end
    function loop (promise, index) {
        promise.then((ret) => {
            if (!end) {
                result[index]     = ret // 保證回調(diào)的順序
                n++
                if (any || n >= promises.length) {
                    deferred.resolve(ang ? ret : result)
                    end = true
                }
            }
        }, (e) => {
            end = true
            deferred.reject(e)
        })
    }
    for (var i = 0, l = promises.length; i < l; i++) {
        loop(promises[i], i)
    }
    return deferred.promise
}

Deferred.all = function () {
    return some(false, arguments)    
}
Deferred.any = function () {
    return some(true, arguments)
}
Deferred.nextTick = function (fn) {
    setTimeout(fn, 0)
}

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/88481.html

相關(guān)文章

  • 一步步搭建JavaScript框架——初始化項(xiàng)目

    摘要:雖然還不夠,但是開(kāi)始了。一步步搭建框架項(xiàng)目名稱一開(kāi)始我做的次是是的一開(kāi)始什么也沒(méi)做,除了從和上注冊(cè)了一個(gè)叫做的庫(kù)然后在我們還沒(méi)有開(kāi)始寫(xiě)代碼的時(shí)候版本就已經(jīng)是這個(gè)速度好快。。生成項(xiàng)目框架為了簡(jiǎn)化這一個(gè)痛苦的過(guò)程,我們還是用。 從開(kāi)始打算寫(xiě)一個(gè)MV*,到一個(gè)簡(jiǎn)單的demo,花了幾天的時(shí)間,雖然很多代碼都是復(fù)制/改造過(guò)來(lái)的,然而It Works(nginx的那句話會(huì)讓人激動(dòng)有木有)。現(xiàn)在他叫...

    omgdog 評(píng)論0 收藏0
  • JavaScript框架學(xué)習(xí)筆記(一)

    摘要:基本的學(xué)習(xí)思路是跟著框架設(shè)計(jì)這本書(shū),甚至可以說(shuō)是這本書(shū)的讀書(shū)筆記。也參考很多網(wǎng)上解讀的博客和學(xué)習(xí)資料。當(dāng)然,最重要的資料還是框架的源代碼。后來(lái)由于開(kāi)發(fā)者反對(duì),新興的框架都在命名空間上構(gòu)建。 JavaScript框架學(xué)習(xí)筆記(一) 我為什么要學(xué)習(xí)框架 更深入的理解工具,以后用起來(lái)更順手而且也能做一定的工具取舍,學(xué)習(xí)理解新工具也就更快, 對(duì)提升js水平也很有幫助,框架有很多解決坑的經(jīng)典思...

    Shonim 評(píng)論0 收藏0
  • 2017 年崛起的 JS 項(xiàng)目

    摘要:通過(guò)對(duì)比各項(xiàng)目過(guò)去個(gè)月在上新增數(shù)量,來(lái)評(píng)估其在年度的受關(guān)注程度,進(jìn)而選出年度領(lǐng)域崛起的明星項(xiàng)目。也許正因?yàn)樯鲜鲎詈笠稽c(diǎn),在中國(guó)擁有大量的擁躉。不僅被中國(guó)最大的電商平臺(tái)阿里巴巴使用,也獲得了與這些公司青睞。 共 4741 字,讀完需 8 分鐘,速讀 2 分鐘。我有幸參與了該項(xiàng)目的部分中文版翻譯、校對(duì)工作,感謝 Sacha Grief,Micheal Ramberu 的統(tǒng)計(jì)整理,以及 Fr...

    gaara 評(píng)論0 收藏0
  • 100 行代碼實(shí)現(xiàn)的 JavaScript MVC 樣式框架

    摘要:應(yīng)用以一個(gè)缺省的開(kāi)始,基于哈希值的代碼加載應(yīng)用視圖并且將對(duì)象模型應(yīng)用于視圖模板。當(dāng)哈希值變化時(shí),這個(gè)代理都會(huì)被調(diào)用。英文原文譯文出處行代碼實(shí)現(xiàn)的樣式框架譯者妖怪姐無(wú)若船老大 Download JavaScript-Mvc.zip - 4.6 KB JavaScript Mvc on Github Live Demo 介紹 使用過(guò)JavaScript框架(如AngularJS, B...

    hikui 評(píng)論0 收藏0
  • Cabloy.js:基于EggBorn.js開(kāi)發(fā)的一款頂級(jí)Javascript全棧業(yè)務(wù)開(kāi)發(fā)框架

    摘要:文檔官網(wǎng)文檔演示是什么是一款頂級(jí)全棧開(kāi)發(fā)框架。不重復(fù)造輪子,而是采用業(yè)界最新的開(kāi)源技術(shù),進(jìn)行全棧開(kāi)發(fā)的最佳組合。漸進(jìn)式開(kāi)發(fā)由于模塊的高度內(nèi)聚,可以將業(yè)務(wù)以模塊的形式沉淀,在多個(gè)項(xiàng)目中重復(fù)使用,既可貢獻(xiàn)到開(kāi)源社區(qū),也可部署到公司內(nèi)部私有倉(cāng)庫(kù)。 文檔 官網(wǎng) && 文檔 演示 PC:https://admin.cabloy.com Mobile: showImg(https://seg...

    tomlingtm 評(píng)論0 收藏0
  • 前端進(jìn)階之路: 前端架構(gòu)設(shè)計(jì)(1)-代碼核心

    摘要:可能很多人和我一樣首次聽(tīng)到前端架構(gòu)這個(gè)詞第一反應(yīng)是前端還有架構(gòu)這一說(shuō)呢在后端開(kāi)發(fā)領(lǐng)域系統(tǒng)規(guī)劃和可擴(kuò)展性非常關(guān)鍵因此架構(gòu)師備受重視早在開(kāi)發(fā)工作啟動(dòng)之前他們就被邀請(qǐng)加入到項(xiàng)目中而且他們會(huì)跟客戶討論即將建成的平臺(tái)的架構(gòu)要求使用還什么技術(shù)棧內(nèi)容類型 可能很多人和我一樣, 首次聽(tīng)到前端架構(gòu)這個(gè)詞, 第一反應(yīng)是: 前端還有架構(gòu)這一說(shuō)呢? 在后端開(kāi)發(fā)領(lǐng)域, 系統(tǒng)規(guī)劃和可擴(kuò)展性非常關(guān)鍵, 因此架構(gòu)師備...

    DevYK 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<