<span id="mktg5"></span>

<i id="mktg5"><meter id="mktg5"></meter></i>

        <label id="mktg5"><meter id="mktg5"></meter></label>
        最新文章專題視頻專題問答1問答10問答100問答1000問答2000關鍵字專題1關鍵字專題50關鍵字專題500關鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關鍵字專題關鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
        問答文章1 問答文章501 問答文章1001 問答文章1501 問答文章2001 問答文章2501 問答文章3001 問答文章3501 問答文章4001 問答文章4501 問答文章5001 問答文章5501 問答文章6001 問答文章6501 問答文章7001 問答文章7501 問答文章8001 問答文章8501 問答文章9001 問答文章9501
        當前位置: 首頁 - 科技 - 知識百科 - 正文

        seajs1.3.0源碼解析之module依賴有序加載_javascript技巧

        來源:懂視網 責編:小采 時間:2020-11-27 21:05:23
        文檔

        seajs1.3.0源碼解析之module依賴有序加載_javascript技巧

        seajs1.3.0源碼解析之module依賴有序加載_javascript技巧:這里是seajs loader的核心部分,有些IE兼容的部分還不是很明白,主要是理解各個模塊如何依賴有序加載,以及CMD規范。 代碼有點長,需要耐心看: 代碼如下: /** * The core of loader */ ;(function(seajs, util, config) { //
        推薦度:
        導讀seajs1.3.0源碼解析之module依賴有序加載_javascript技巧:這里是seajs loader的核心部分,有些IE兼容的部分還不是很明白,主要是理解各個模塊如何依賴有序加載,以及CMD規范。 代碼有點長,需要耐心看: 代碼如下: /** * The core of loader */ ;(function(seajs, util, config) { //

        這里是seajs loader的核心部分,有些IE兼容的部分還不是很明白,主要是理解各個模塊如何依賴有序加載,以及CMD規范。

        代碼有點長,需要耐心看:

        代碼如下:
        /**
        * The core of loader
        */
        ;(function(seajs, util, config) {
        // 模塊緩存
        var cachedModules = {}
        // 接口修改緩存
        var cachedModifiers = {}
        // 編譯隊列
        var compileStack = []
        // 模塊狀態
        var STATUS = {
        'FETCHING': 1, // The module file is fetching now. 模塊正在下載中
        'FETCHED': 2, // The module file has been fetched. 模塊已下載
        'SAVED': 3, // The module info has been saved. 模塊信息已保存
        'READY': 4, // All dependencies and self are ready to compile. 模塊的依賴項都已下載,等待編譯
        'COMPILING': 5, // The module is in compiling now. 模塊正在編譯中
        'COMPILED': 6 // The module is compiled and module.exports is available. 模塊已編譯
        }


        function Module(uri, status) {
        this.uri = uri
        this.status = status || 0

        // this.id is set when saving
        // this.dependencies is set when saving
        // this.factory is set when saving
        // this.exports is set when compiling
        // this.parent is set when compiling
        // this.require is set when compiling
        }


        Module.prototype._use = function(ids, callback) {
        //轉換為數組,統一操作
        util.isString(ids) && (ids = [ids])
        // 使用模塊系統內部的路徑解析機制來解析并返回模塊路徑
        var uris = resolve(ids, this.uri)

        this._load(uris, function() {
        // Loads preload files introduced in modules before compiling.
        // 在編譯之前,再次調用preload預加載模塊
        // 因為在代碼執行期間,隨時可以調用seajs.config配置預加載模塊
        preload(function() {
        // 編譯每個模塊,并將各個模塊的exports作為參數傳遞給回調函數
        var args = util.map(uris, function(uri) {
        return uri ? cachedModules[uri]._compile() : null
        })

        if (callback) {
        // null使回調函數中this指針為window
        callback.apply(null, args)
        }
        })
        })
        }

        // 主模塊加載依賴模塊(稱之為子模塊),并執行回調函數
        Module.prototype._load = function(uris, callback) {
        // 過濾uris數組
        // 情況一:緩存中不存在該模塊,返回其uri
        // 情況二:緩存中存在該模塊,但是其status < STATUS.READY(即還沒準備好編譯)
        var unLoadedUris = util.filter(uris, function(uri) {
        return uri && (!cachedModules[uri] ||
        cachedModules[uri].status < STATUS.READY)
        })

        var length = unLoadedUris.length
        // 如果length為0,表示依賴項為0或者都已下載完成,那么執行回調編譯操作
        if (length === 0) {
        callback()
        return
        }

        var remain = length

        for (var i = 0; i < length; i++) {
        // 閉包,為onFetched函數提供上下文環境
        (function(uri) {
        // 創建模塊對象
        var module = cachedModules[uri] ||
        (cachedModules[uri] = new Module(uri, STATUS.FETCHING))
        //如果模塊已下載,那么執行onFetched,否則執行fetch操作(請求模塊)
        module.status >= STATUS.FETCHED ? onFetched() : fetch(uri, onFetched)

        function onFetched() {
        // cachedModules[uri] is changed in un-correspondence case
        module = cachedModules[uri]
        // 如果模塊狀態為SAVED,表示模塊的依賴項已經確定,那么下載依賴模塊
        if (module.status >= STATUS.SAVED) {
        // 從模塊信息中獲取依賴模塊列表,并作循環依賴的處理
        var deps = getPureDependencies(module)
        // 如果存在依賴項,繼續下載
        if (deps.length) {
        Module.prototype._load(deps, function() {
        cb(module)
        })
        }
        // 否則直接執行cb
        else {
        cb(module)
        }
        }
        // Maybe failed to fetch successfully, such as 404 or non-module.
        // In these cases, just call cb function directly.
        // 如果下載模塊不成功,比如404或者模塊不規范(代碼出錯),導致此時模塊狀態可能為fetching,或者fetched
        // 此時直接執行回調函數,在編譯模塊時,該模塊就只會返回null
        else {
        cb()
        }
        }

        })(unLoadedUris[i])
        }

        function cb(module) {
        // 更改模塊狀態為READY,當remain為0時表示模塊依賴都已經下完,那么執行callback
        (module || {}).status < STATUS.READY && (module.status = STATUS.READY)
        --remain === 0 && callback()
        }
        }


        Module.prototype._compile = function() {
        var module = this
        // 如果該模塊已經編譯過,則直接返回module.exports
        if (module.status === STATUS.COMPILED) {
        return module.exports
        }

        // Just return null when:
        // 1. the module file is 404.
        // 2. the module file is not written with valid module format.
        // 3. other error cases.
        // 這里是處理一些異常情況,此時直接返回null
        if (module.status < STATUS.SAVED && !hasModifiers(module)) {
        return null
        }
        // 更改模塊狀態為COMPILING,表示模塊正在編譯
        module.status = STATUS.COMPILING

        // 模塊內部使用,是一個方法,用來獲取其他模塊提供(稱之為子模塊)的接口,同步操作
        function require(id) {
        // 根據id解析模塊的路徑
        var uri = resolve(id, module.uri)
        // 從模塊緩存中獲取模塊(注意,其實這里子模塊作為主模塊的依賴項是已經被下載下來的)
        var child = cachedModules[uri]

        // Just return null when uri is invalid.
        // 如果child為空,只能表示參數填寫出錯導致uri不正確,那么直接返回null
        if (!child) {
        return null
        }

        // Avoids circular calls.
        // 如果子模塊的狀態為STATUS.COMPILING,直接返回child.exports,避免因為循環依賴反復編譯模塊
        if (child.status === STATUS.COMPILING) {
        return child.exports
        }
        // 指向初始化時調用當前模塊的模塊。根據該屬性,可以得到模塊初始化時的Call Stack.
        child.parent = module
        // 返回編譯過的child的module.exports
        return child._compile()
        }
        // 模塊內部使用,用來異步加載模塊,并在加載完成后執行指定回調。
        require.async = function(ids, callback) {
        module._use(ids, callback)
        }
        // 使用模塊系統內部的路徑解析機制來解析并返回模塊路徑。該函數不會加載模塊,只返回解析后的絕對路徑。
        require.resolve = function(id) {
        return resolve(id, module.uri)
        }
        // 通過該屬性,可以查看到模塊系統加載過的所有模塊。
        // 在某些情況下,如果需要重新加載某個模塊,可以得到該模塊的 uri, 然后通過 delete require.cache[uri] 來將其信息刪除掉。這樣下次使用時,就會重新獲取。
        require.cache = cachedModules

        // require是一個方法,用來獲取其他模塊提供的接口。
        module.require = require
        // exports是一個對象,用來向外提供模塊接口。
        module.exports = {}
        var factory = module.factory

        // factory 為函數時,表示模塊的構造方法。執行該方法,可以得到模塊向外提供的接口。
        if (util.isFunction(factory)) {
        compileStack.push(module)
        runInModuleContext(factory, module)
        compileStack.pop()
        }
        // factory 為對象、字符串等非函數類型時,表示模塊的接口就是該對象、字符串等值。
        // 如:define({ "foo": "bar" });
        // 如:define('I am a template. My name is {{name}}.');
        else if (factory !== undefined) {
        module.exports = factory
        }

        // 更改模塊狀態為COMPILED,表示模塊已編譯
        module.status = STATUS.COMPILED
        // 執行模塊接口修改,通過seajs.modify()
        execModifiers(module)
        return module.exports
        }


        Module._define = function(id, deps, factory) {
        var argsLength = arguments.length
        // 根據傳入的參數個數,進行參數匹配

        // define(factory)
        // 一個參數的情況:
        // id : undefined
        // deps : undefined(后面會根據正則取出依賴模塊列表)
        // factory : function
        if (argsLength === 1) {
        factory = id
        id = undefined
        }
        // define(id || deps, factory)
        // 兩個參數的情況:

        else if (argsLength === 2) {
        // 默認情況下 :define(id, factory)
        // id : '...'
        // deps : undefined
        // factory : function
        factory = deps
        deps = undefined

        // define(deps, factory)
        // 如果第一個參數為數組 :define(deps, factory)
        // id : undefined
        // deps : [...]
        // factory : function
        if (util.isArray(id)) {
        deps = id
        id = undefined
        }
        }

        // Parses dependencies.
        // 如果deps不是數組(即deps未指定值),那么通過正則表達式解析依賴
        if (!util.isArray(deps) && util.isFunction(factory)) {
        deps = util.parseDependencies(factory.toString())
        }

        // 元信息,之后會將信息傳遞給對應的module對象中
        var meta = { id: id, dependencies: deps, factory: factory }
        var derivedUri

        // Try to derive uri in IE6-9 for anonymous modules.
        // 對于IE6-9,嘗試通過interactive script獲取模塊的uri
        if (document.attachEvent) {
        // Try to get the current script.
        // 獲取當前的script
        var script = util.getCurrentScript()
        if (script) {
        // 將當前script的url進行unpareseMap操作,與模塊緩存中key保持一致
        derivedUri = util.unParseMap(util.getScriptAbsoluteSrc(script))
        }

        if (!derivedUri) {
        util.log('Failed to derive URI from interactive script for:',
        factory.toString(), 'warn')

        // NOTE: If the id-deriving methods above is failed, then falls back
        // to use onload event to get the uri.
        }
        }

        // Gets uri directly for specific module.
        // 如果給定id,那么根據id解析路徑
        // 顯然如果沒指定id:
        // 對于非IE瀏覽器而言,則返回undefined(derivedUri為空)
        // 對于IE瀏覽器則返回CurrentScript的src
        // 如果指定id:
        // 則均返回有seajs解析(resolve)過的路徑url
        var resolvedUri = id ? resolve(id) : derivedUri
        // uri存在的情況,進行模塊信息存儲
        if (resolvedUri) {
        // For IE:
        // If the first module in a package is not the cachedModules[derivedUri]
        // self, it should assign to the correct module when found.
        if (resolvedUri === derivedUri) {
        var refModule = cachedModules[derivedUri]
        if (refModule && refModule.realUri &&
        refModule.status === STATUS.SAVED) {
        cachedModules[derivedUri] = null
        }
        }
        // 存儲模塊信息
        var module = save(resolvedUri, meta)

        // For IE:
        // Assigns the first module in package to cachedModules[derivedUrl]
        if (derivedUri) {
        // cachedModules[derivedUri] may be undefined in combo case.
        if ((cachedModules[derivedUri] || {}).status === STATUS.FETCHING) {
        cachedModules[derivedUri] = module
        module.realUri = derivedUri
        }
        }
        else {
        // 將第一個模塊存儲到firstModuleInPackage
        firstModuleInPackage || (firstModuleInPackage = module)
        }
        }
        // uri不存在的情況,在onload回調中進行模塊信息存儲,那里有個閉包
        else {
        // Saves information for "memoizing" work in the onload event.
        // 因為此時的uri不知道,所以將元信息暫時存儲在anonymousModuleMeta中,在onload回調中進行模塊save操作
        anonymousModuleMeta = meta
        }

        }

        // 獲取正在編譯的模塊
        Module._getCompilingModule = function() {
        return compileStack[compileStack.length - 1]
        }

        // 從seajs.cache中快速查看和獲取已加載的模塊接口,返回值是module.exports數組
        // selector 支持字符串和正則表達式
        Module._find = function(selector) {
        var matches = []

        util.forEach(util.keys(cachedModules), function(uri) {
        if (util.isString(selector) && uri.indexOf(selector) > -1 ||
        util.isRegExp(selector) && selector.test(uri)) {
        var module = cachedModules[uri]
        module.exports && matches.push(module.exports)
        }
        })

        return matches
        }

        // 修改模塊接口
        Module._modify = function(id, modifier) {
        var uri = resolve(id)
        var module = cachedModules[uri]
        // 如果模塊存在,并且處于COMPILED狀態,那么執行修改接口操作
        if (module && module.status === STATUS.COMPILED) {
        runInModuleContext(modifier, module)
        }
        // 否則放入修改接口緩存中
        else {
        cachedModifiers[uri] || (cachedModifiers[uri] = [])
        cachedModifiers[uri].push(modifier)
        }

        return seajs
        }


        // For plugin developers
        Module.STATUS = STATUS
        Module._resolve = util.id2Uri
        Module._fetch = util.fetch
        Module.cache = cachedModules


        // Helpers
        // -------
        // 正在下載的模塊列表
        var fetchingList = {}
        // 已下載的模塊列表
        var fetchedList = {}
        // 回調函數列表
        var callbackList = {}
        // 匿名模塊元信息
        var anonymousModuleMeta = null
        var firstModuleInPackage = null
        // 循環依賴棧
        var circularCheckStack = []

        // 批量解析模塊的路徑
        function resolve(ids, refUri) {
        if (util.isString(ids)) {
        return Module._resolve(ids, refUri)
        }

        return util.map(ids, function(id) {
        return resolve(id, refUri)
        })
        }

        function fetch(uri, callback) {
        // fetch時,首先將uri按map規則轉換
        var requestUri = util.parseMap(uri)
        // 在fethedList(已下載的模塊列表)中查找,有的話,直接返回,并執行回調函數
        // TODO : 為什么這一步,fetchedList可能會存在該模?
        if (fetchedList[requestUri]) {
        // See test/issues/debug-using-map
        cachedModules[uri] = cachedModules[requestUri]
        callback()
        return
        }
        // 在fetchingList(正在在下載的模塊列表)中查找,有的話,只需添加回調函數到列表中去,然后直接返回
        if (fetchingList[requestUri]) {
        callbackList[requestUri].push(callback)
        return
        }
        // 如果走到這一步,表示該模塊是第一次被請求,
        // 那么在fetchingList插入該模塊的信息,表示該模塊已經處于下載列表中,并初始化該模塊對應的回調函數列表
        fetchingList[requestUri] = true
        callbackList[requestUri] = [callback]

        // Fetches it
        // 獲取該模塊,即發起請求
        Module._fetch(
        requestUri,

        function() {
        // 在fetchedList插入該模塊的信息,表示該模塊已經下載完成
        fetchedList[requestUri] = true

        // Updates module status
        var module = cachedModules[uri]
        // 此時status可能為STATUS.SAVED,之前在_define中已經說過
        if (module.status === STATUS.FETCHING) {
        module.status = STATUS.FETCHED
        }

        // Saves anonymous module meta data
        // 因為是匿名模塊(此時通過閉包獲取到uri,在這里存儲模塊信息)
        // 并將anonymousModuleMeta置為空
        if (anonymousModuleMeta) {
        save(uri, anonymousModuleMeta)
        anonymousModuleMeta = null
        }

        // Assigns the first module in package to cachedModules[uri]
        // See: test/issues/un-correspondence
        if (firstModuleInPackage && module.status === STATUS.FETCHED) {
        cachedModules[uri] = firstModuleInPackage
        firstModuleInPackage.realUri = uri
        }
        firstModuleInPackage = null

        // Clears
        // 在fetchingList清除模塊信息,因為已經該模塊fetched并save
        if (fetchingList[requestUri]) {
        delete fetchingList[requestUri]
        }

        // Calls callbackList
        // 依次調用回調函數,并清除回調函數列表
        if (callbackList[requestUri]) {
        util.forEach(callbackList[requestUri], function(fn) {
        fn()
        })
        delete callbackList[requestUri]
        }

        },

        config.charset
        )
        }

        function save(uri, meta) {
        var module = cachedModules[uri] || (cachedModules[uri] = new Module(uri))

        // Don't override already saved module
        // 此時status可能有兩個狀態:
        // STATUS.FETCHING,在define里面調用(指定了id),存儲模塊信息
        // STATUS.FETCHED,在onload的回調函數里調用,存儲模塊信息
        if (module.status < STATUS.SAVED) {
        // Lets anonymous module id equal to its uri
        // 匿名模塊(即沒有指定id),用它的uri作為id
        module.id = meta.id || uri
        // 將依賴項(數組)解析成的絕對路徑,存儲到模塊信息中
        module.dependencies = resolve(
        util.filter(meta.dependencies || [], function(dep) {
        return !!dep
        }), uri)
        // 存儲factory(要執行的模塊代碼,也可能是對象或者字符串等)
        module.factory = meta.factory

        // Updates module status
        // 更新模塊狀態為SAVED,(注意此時它只是擁有了依賴項,還未全部下載下來(即還未READY))
        module.status = STATUS.SAVED
        }

        return module
        }

        // 根據模塊上下文執行模塊代碼
        function runInModuleContext(fn, module) {
        // 傳入與模塊相關的兩個參數以及模塊自身
        // exports用來暴露接口
        // require用來獲取依賴模塊(同步)(編譯)
        var ret = fn(module.require, module.exports, module)
        // 支持返回值暴露接口形式,如:
        // return {
        // fn1 : xx
        // ,fn2 : xx
        // ...
        // }
        if (ret !== undefined) {
        module.exports = ret
        }
        }
        // 判斷模塊是否存在接口修改
        function hasModifiers(module) {
        return !!cachedModifiers[module.realUri || module.uri]
        }
        // 修改模塊接口
        function execModifiers(module) {
        var uri = module.realUri || module.uri
        var modifiers = cachedModifiers[uri]
        // 內部變量 cachedModifiers 就是用來存儲用戶通過 seajs.modify 方法定義的修改點
        // 查看該uri是否又被modify更改過
        if (modifiers) {
        // 對修改點統一執行factory,返回修改后的module.exports
        util.forEach(modifiers, function(modifier) {
        runInModuleContext(modifier, module)
        })
        // 刪除 modify 方法定義的修改點 ,避免再次執行
        delete cachedModifiers[uri]
        }
        }

        //獲取純粹的依賴關系,得到不存在循環依賴關系的依賴數組
        function getPureDependencies(module) {
        var uri = module.uri
        // 對每個依賴項進行過濾,對于有可能形成循環依賴的進行剔除,并打印出警告日志
        return util.filter(module.dependencies, function(dep) {
        // 首先將被檢查模塊的uri放到循環依賴檢查棧中,之后的檢查會用到
        circularCheckStack = [uri]
        //接下來檢查模塊uri是否和其依賴的模塊存在循環依賴
        var isCircular = isCircularWaiting(cachedModules[dep])
        if (isCircular) {
        // 如果循環,則將uri放到循環依賴檢查棧中
        circularCheckStack.push(uri)
        // 打印出循環警告日志
        printCircularLog(circularCheckStack)
        }

        return !isCircular
        })
        }

        function isCircularWaiting(module) {
        // 如果依賴模塊不存在,那么返回false,因為此時也無法獲得依賴模塊的依賴項,所以這里無法做判斷
        // 或者如果模塊的狀態值等于saved,也返回false,因為模塊狀態為saved的時候代表該模塊的信息已經有了,
        // 所以盡管形成了循環依賴,但是require主模塊時,同樣可以正常編譯,返回主模塊接口(好像nodejs會返回undefined)
        if (!module || module.status !== STATUS.SAVED) {
        return false
        }
        // 如果不是以上的情況,那么將依賴模塊的uri放到循環依賴檢查棧中,之后的檢查會用到
        circularCheckStack.push(module.uri)
        // 再次取依賴模塊的依賴模塊
        var deps = module.dependencies

        if (deps.length) {
        // 通過循環依賴檢查棧,檢查是否存在循環依賴(這里是第一層依賴模塊檢查,與主模塊循環依賴的情況)
        if (isOverlap(deps, circularCheckStack)) {
        return true
        }
        // 如果不存在上述情形,那么進一步查看,依賴模塊的依賴模塊,查看他們是否存在對循環依賴檢查棧中的uri的模塊存在循環依賴
        // 這樣的話,就遞歸了,循環依賴檢查棧就像形成的一條鏈,當前模塊依次對主模塊,主模塊的主模塊...直到最頂上的主模塊,依次進行判斷是否存在依賴
        for (var i = 0; i < deps.length; i++) {
        if (isCircularWaiting(cachedModules[deps[i]])) {
        return true
        }
        }
        }
        // 如果不存在循環依賴,那么pop出之前已經push進的模塊uri,并返回false
        circularCheckStack.pop()
        return false
        }
        // 打印出循環警告日志
        function printCircularLog(stack, type) {
        util.log('Found circular dependencies:', stack.join(' --> '), type)
        }
        //判斷兩個數組是否有重復的值
        function isOverlap(arrA, arrB) {
        var arrC = arrA.concat(arrB)
        return arrC.length > util.unique(arrC).length
        }
        // 從配置文件讀取是否有需要提前加載的模塊
        // 如果有預先加載模塊,首先設置預加載模塊為空(保證下次不必重復加載),并加載預加載模塊并執行回調,如果沒有則順序執行
        function preload(callback) {
        var preloadMods = config.preload.slice()
        config.preload = []
        preloadMods.length ? globalModule._use(preloadMods, callback) : callback()
        }


        // Public API
        // 對外暴露的API
        // ----------
        // 全局模塊,可以認為是頁面模塊,頁面中的js,css文件都是通過它來載入的
        // 模塊初始狀態就是COMPILED,uri就是頁面的uri
        var globalModule = new Module(util.pageUri, STATUS.COMPILED)

        // 頁面js,css文件加載器
        seajs.use = function(ids, callback) {
        // Loads preload modules before all other modules.
        // 預加載模塊
        preload(function() {
        globalModule._use(ids, callback)
        })

        // Chain
        return seajs
        }


        // For normal users
        // 供普通用戶調用
        seajs.define = Module._define
        seajs.cache = Module.cache
        seajs.find = Module._find
        seajs.modify = Module._modify


        // For plugin developers
        // 供開發者使用
        seajs.pluginSDK = {
        Module: Module,
        util: util,
        config: config
        }

        })(seajs, seajs._util, seajs._config)

        聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

        文檔

        seajs1.3.0源碼解析之module依賴有序加載_javascript技巧

        seajs1.3.0源碼解析之module依賴有序加載_javascript技巧:這里是seajs loader的核心部分,有些IE兼容的部分還不是很明白,主要是理解各個模塊如何依賴有序加載,以及CMD規范。 代碼有點長,需要耐心看: 代碼如下: /** * The core of loader */ ;(function(seajs, util, config) { //
        推薦度:
        標簽: 加載 js 詳解
        • 熱門焦點

        最新推薦

        猜你喜歡

        熱門推薦

        專題
        Top
        主站蜘蛛池模板: 亚洲国产婷婷六月丁香| 日本v片免费一区二区三区| 久久一区二区三区免费| 无码人妻精品中文字幕免费| 亚洲综合另类小说色区| 亚洲视频在线免费| 成人免费午夜在线观看| 亚洲乱码在线卡一卡二卡新区| 一级黄色免费网站| 最近最新MV在线观看免费高清| 国产亚洲AV夜间福利香蕉149| 一级特黄特色的免费大片视频| 亚洲 另类 无码 在线| 亚洲伊人tv综合网色| 七次郎成人免费线路视频| 日本亚洲国产一区二区三区| 久久精品国产免费| 亚洲网站视频在线观看| 毛片免费vip会员在线看| 亚洲av中文无码乱人伦在线咪咕| 午夜精品免费在线观看| 亚洲伊人久久大香线蕉| 最好看的中文字幕2019免费| 亚洲中文字幕在线第六区| 久久久免费的精品| 亚洲一区二区三区写真| 亚洲性日韩精品国产一区二区| 成人黄网站片免费视频| 亚洲中文字幕久久精品无码喷水 | 亚洲youwu永久无码精品| 高清在线亚洲精品国产二区| a级毛片在线视频免费观看| 亚洲一线产区二线产区精华| 国产精品免费AV片在线观看| 亚洲精品亚洲人成人网| 精品国产免费人成电影在线观看| 国产精品亚洲专区无码唯爱网| 国产亚洲视频在线播放| 黄页网站免费观看| 成人免费乱码大片A毛片| 亚洲国产精品一区二区久|