Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 国产精品九九,91精品免费高清在线,一区二区视屏

          整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          Javascript 模塊化指北

          Javascript 模塊化指北

          隨著 Web 技術的蓬勃發展和依賴的基礎設施日益完善,前端領域逐漸從瀏覽器擴展至服務端(Node.js),桌面端(PC、Android、iOS),乃至于物聯網設備(IoT),其中 JavaScript 承載著這些應用程序的核心部分,隨著其規?;蛷碗s度的成倍增長,其軟件工程體系也隨之建立起來(協同開發、單元測試、需求和缺陷管理等),模塊化編程的需求日益迫切。

          JavaScript 對模塊化編程的支持尚未形成規范,難以堪此重任;一時間,江湖俠士挺身而出,一路披荊斬棘,從刀耕火種過渡到面向未來的模塊化方案;

          更多關于我的文章和項目,歡迎關注 @x-cold

          概念

          模塊化編程就是通過組合一些__相對獨立可復用的模塊__來進行功能的實現,其最核心的兩部分是__定義模塊__和__引入模塊__;

          • 定義模塊時,每個模塊內部的執行邏輯是不被外部感知的,只是導出(暴露)出部分方法和數據;
          • 引入模塊時,同步 / 異步去加載待引入的代碼,執行并獲取到其暴露的方法和數據;

          刀耕火種

          盡管 JavaScript 語言層面并未提供模塊化的解決方案,但利用其可__面向對象__的語言特性,外加__設計模式__加持,能夠實現一些簡單的模塊化的架構;經典的一個案例是利用單例模式模式去實現模塊化,可以對模塊進行較好的封裝,只暴露部分信息給需要使用模塊的地方;

          // Define a module
          var moduleA=(function ($, doc) {
           var methodA=function() {};
           var dataA={};
           return {
           methodA: methodA,
           dataA: dataA
           };
          })(jQuery, document);
          // Use a module
          var result=moduleA.mehodA();
          

          直觀來看,通過立即執行函數(IIFE)來聲明依賴以及導出數據,這與當下的模塊化方案并無巨大的差異,可本質上卻有千差萬別,無法滿足的一些重要的特性;

          • 定義模塊時,聲明的依賴不是強制自動引入的,即在定義該模塊之前,必須手動引入依賴的模塊代碼;
          • 定義模塊時,其代碼就已經完成執行過程,無法實現按需加載;
          • 跨文件使用模塊時,需要將模塊掛載到全局變量(window)上;

          AMD & CMD 二分天下

          題外話:由于年代久遠,這兩種模塊化方案逐漸淡出歷史舞臺,具體特性不再細聊;

          為了解決”刀耕火種”時代存留的需求,AMD 和 CMD 模塊化規范問世,解決了在瀏覽器端的異步模塊化編程的需求,__其最核心的原理是通過動態加載 script 和事件監聽的方式來異步加載模塊;__

          AMD 和 CMD 最具代表的兩個作品分別對應 require.js 和 sea.js;其主要區別在于依賴聲明和依賴加載的時機,其中 require.js 默認在聲明時執行, sea.js 推崇懶加載和按需使用;另外值得一提的是,CMD 規范的寫法和 CommonJS 極為相近,只需稍作修改,就能在 CommonJS 中使用。參考下面的 Case 更有助于理解;

          // AMD
          define(['./a','./b'], function (moduleA, moduleB) {
           // 依賴前置
           moduleA.mehodA();
           console.log(moduleB.dataB);
           // 導出數據
           return {};
          });
           
          // CMD
          define(function (requie, exports, module) {
           // 依賴就近
           var moduleA=require('./a');
           moduleA.mehodA(); 
           // 按需加載
           if (needModuleB) {
           var moduleB=requie('./b');
           moduleB.methodB();
           }
           // 導出數據
           exports={};
          });
          

          CommonJS

          2009 年 ry 發布 Node.js 的第一個版本,CommonJS 作為其中最核心的特性之一,適用于服務端下的場景;歷年來的考察和時間的洗禮,以及前端工程化對其的充分支持,CommonJS 被廣泛運用于 Node.js 和瀏覽器;

          // Core Module
          const cp=require('child_process');
          // Npm Module
          const axios=require('axios');
          // Custom Module
          const foo=require('./foo');
          module.exports={ axios };
          exports.foo=foo;
          

          規范

          • module (Object): 模塊本身
          • exports (*): 模塊的導出部分,即暴露出來的內容
          • require (Function): 加載模塊的函數,獲得目標模塊的導出值(基礎類型為復制,引用類型為淺拷貝),可以加載內置模塊、npm 模塊和自定義模塊

          實現

          1、模塊定義

          默認任意 .node .js .json 文件都是符合規范的模塊;

          2、引入模塊

          首先從緩存(require.cache)優先讀取模塊,如果未命中緩存,則進行路徑分析,然后按照不同類型的模塊處理:

          • 內置模塊,直接從內存加載;
          • 外部模塊,首先進行文件尋址定位,然后進行編譯和執行,最終得到對應的導出值;

          其中在編譯的過程中,Node對獲取的JavaScript文件內容進行了頭尾包裝,結果如下:

          (function (exports, require, module, __filename, __dirname) {
           var circle=require('./circle.js');
           console.log('The area of a circle of radius 4 is ' + circle.area(4));
          });
          

          特性總結

          • 同步執行模塊聲明和引入邏輯,分析一些復雜的依賴引用(如循環依賴)時需注意;
          • 緩存機制,性能更優,同時限制了內存占用;
          • Module 模塊可供改造的靈活度高,可以實現一些定制需求(如熱更新、任意文件類型模塊支持);

          ES Module(推薦使用)

          ES Module 是語言層面的模塊化方案,由 ES 2015 提出,其規范與 CommonJS 比之 ,導出的值都可以看成是一個具備多個屬性或者方法的對象,可以實現互相兼容;但寫法上 ES Module 更簡潔,與 Python 接近;

          import fs from 'fs';
          import color from 'color';
          import service, { getArticles } from '../service'; 
          export default service;
          export const getArticles=getArticles;
          

          主要差異在于:

          • ES Module 會對靜態代碼分析,即在代碼編譯時進行模塊的加載,在運行時之前就已經確定了依賴關系(可解決循環引用的問題);
          • ES Module 關鍵字:import export 以及獨有的 default 關鍵字,確定默認的導出值;
          • ES Module 中導出的值是一個 只讀的值的引用 ,無論基礎類型和復雜類型,而在 CommonJS 中 require 的是值的拷貝,其中復雜類型是值的淺拷貝;
          // a.js
          export let a=1;
          export function caculate() {
           a++;
          };
          // b.js
          import { a, caculate } from 'a.js';
          console.log(a); // 1
          caculate();
          console.log(a); // 2
          a=2; // Syntax Error: "a" is read-only
          

          UMD

          通過一層自執行函數來兼容各種模塊化規范的寫法,兼容 AMD / CMD / CommonJS 等模塊化規范,貼上代碼勝過千言萬語,需要特別注意的是 ES Module 由于會對靜態代碼進行分析,故這種運行時的方案無法使用,此時通過 CommonJS 進行兼容;

          (function (global, factory) {
           if (typeof exports==='object') { 
           module.exports=factory();
           } else if (typeof define==='function' && define.amd) {
           define(factory);
           } else {
           this.eventUtil=factory();
           }
          })(this, function (exports) {
           ? // Define Module
           Object.defineProperty(exports, "__esModule", {
           value: true
           });
           exports.default=42;
          });
          

          構建工具中的實現

          為了在瀏覽器環境中運行模塊化的代碼,需要借助一些模塊化打包的工具進行打包( 以 webpack 為例),定義了項目入口之后,會先快速地進行依賴的分析,然后將所有依賴的模塊轉換成瀏覽器兼容的對應模塊化規范的實現;

          模塊化的基礎

          從上面的介紹中,我們已經對其規范和實現有了一定的了解;在瀏覽器中,要實現 CommonJS 規范,只需要實現 module / exports / require / global 這幾個屬性,由于瀏覽器中是無法訪問文件系統的,因此 require 過程中的文件定位需要改造為加載對應的 JS 片段(webpack 采用的方式為通過函數傳參實現依賴的引入)。具體實現可以參考:tiny-browser-require。

          webpack 打包出來的代碼快照如下,注意看注釋中的時序;

          (function (modules) {
           // The module cache
           var installedModules={};
           // The require function
           function __webpack_require__(moduleId) {}
           return __webpack_require__(0); // ---> 0
          })
          ({
           0: function (module, exports, __webpack_require__) {
           // Define module A
           var moduleB=__webpack_require__(1); // ---> 1
           },
           1: function (module, exports, __webpack_require__) {
           // Define module B
           exports={}; // ---> 2
           }
          });
          

          實際上,ES Module 的處理同 CommonJS 相差無幾,只是在定義模塊和引入模塊時會去處理 __esModule 標識,從而兼容其在語法上的差異。

          異步和擴展

          1、瀏覽器環境下,網絡資源受到較大的限制,因此打包出來的文件如果體積巨大,對頁面性能的損耗極大,因此需要對構建的目標文件進行拆分,同時模塊也需要支持動態加載;

          webpack 提供了兩個方法 require.ensure() 和 import() (推薦使用)進行模塊的動態加載,至于其中的原理,跟上面提及的 AMD & CMD 所見略同,import() 執行后返回一個 Promise 對象,其中所做的工作無非也是動態新增 script 標簽,然后通過 onload / onerror 事件進一步處理。

          2、由于 require 函數是完全自定義的,我們可以在模塊化中實現更多的特性,比如通過修改 require.resolve 或 Module._extensions 擴展支持的文件類型,使得 css / .jsx / .vue / 圖片等文件也能為模塊化所使用;

          附錄1:特性一覽表

          附錄2:參考

          • AMD 模塊化規范: https://github.com/amdjs/amdjs-api/wiki/AMD
          • CMD 模塊定義規范:https://github.com/seajs/seajs/issues/242
          • webpack 模塊相關文檔: https://webpack.js.org/concepts/modules/
          • 瀏覽器加載 CommonJS 模塊的原理與實現:http://www.ruanyifeng.com/blog/2015/05/commonjs-in-browser.html

          作者:x-cold

          本文主要理理js模塊化相關知識。
          涉及到內聯腳本、外聯腳本、動態腳本、阻塞、
          defer、async、CommonJS、AMD、CMD、UMDES Module。順帶探究下Vite。

          內聯腳本

          假設你是一個前端新手,現在入門,那么我們創建一個html頁面,需要新建一個index.html文件:

          <!DOCTYPE html>
          <html>
          <head>
            <title>test</title>
          </head>
          <body>
            <p id="content">hello world</p>
          </body>
          </html>

          如果需要在頁面中執行javascript代碼,我們就需要在 HTML 頁面中插入 <script> 標簽。

          有2種插入方式:
          1、放在
          <head>
          2、放在<body>

          比如,點擊hello world之后,在hello world后面加3個感嘆號的功能,我們在head中加入script標簽,并給hello world綁定點擊事件:

          <!DOCTYPE html>
          <html>
          <head>
            <title>test</title>
            <script>
              function myFunction() {
                document.getElementById('content').innerHTML='hello world!!!'
              }
            </script>
          </head>
          
          <body>
            <p id="content" onclick="myFunction()">hello world</p>
          </body>
          </html>

          如果加在body中,一般放在body的最后面:

          <!DOCTYPE html>
          <html>
          <head>
            <title>test</title>
          </head>
          
          <body>
            <p id="content" onclick="myFunction()">hello world</p>
            <script>
              function myFunction() {
                document.getElementById('content').innerHTML='hello world!!!'
              }
            </script>
          </body>
          </html>

          簡單的邏輯我們可以用這2種方式寫,這種方式叫做內聯腳本。

          外聯腳本

          當邏輯復雜時,我們可以把上面的script標簽中的代碼抽取出來,比如在html的同級目錄創建一個js文件夾,里面新建一個a.js的文件。

          a.js中寫上面script標簽中的代碼:

          function myFunction() {
            document.getElementById('content').innerHTML='hello world!!!'
          }

          上面的script標簽則可以改成:

          <script src="./js/a.js"></script>

          阻塞

          上面的2種寫法,瀏覽器在加載html時,遇到script標簽,會停止解析html。
          內聯腳本會立刻執行;外聯腳本會先下載再立刻執行。
          等腳本執行完畢才會繼續解析html。
          (html解析到哪里,頁面就能顯示到哪里,用戶也能看到哪里)

          比如下面的代碼:

          <p>...content before script...</p>
          
          <script src="./js/a.js"></script>
          
          <p>...content after script...</p>

          解析到第一個p標簽,我們能看到...content before script...顯示在了頁面中,然后瀏覽器遇到script標簽,會停止解析html,而去下載a.js并執行,執行完a.js才會繼續解析html,然后頁面中才會出現...content after script...

          我們可以通過Chrome的Developer Tools分析一下index.html加載的時間線:

          這會導致2個問題:
          1、腳本無法訪問它下面的dom;
          2、如果頁面頂部有個笨重的腳本,在它執行完之前,用戶都看不到完整的頁面。

          對于問題2,我們可以把腳本放在頁面底部,這樣它可以訪問到上面的dom,且不會阻塞頁面的顯示:

          <body>
            ...all content is above the script...
          
            <script src="./js/a.js"></script>
          </body>

          但這不是最好的辦法,我們接著往下看。

          defer

          我們給script標簽加defer屬性,就像下面這樣:

          <p>...content before script...</p>
          
          <script defer src="./js/a.js"></script>
          
          <p>...content after script...</p>

          defer 特性告訴瀏覽器不要等待腳本。于是,瀏覽器將繼續解析html,腳本會并行下載,然后等 DOM 構建完成后,腳本才會執行。

          這樣script標簽不再阻塞html的解析。

          這時再看時間線:

          需要注意的是,具有 defer 特性的腳本保持其相對順序。

          比如:

          <script defer src="./js/a.js"></script>
          <script defer src="./js/b.js"></script>

          上面的2個腳本會并行下載,但是不論哪個先下載完成,都是先執行a.js,a.js執行完才會執行b.js。
          這時,如果b.js依賴a.js,這種寫法將很有用。

          另外需要注意的是,defer 特性僅適用于外聯腳本,即如果 script標簽沒有 src屬性,則會忽略 defer 特性。

          async

          我們可以給script標簽加async屬性,就像下面這樣:

          <script async src="./js/a.js"></script>

          這會告訴瀏覽器,該腳本完全獨立。
          獨立的意思是,DOM 和其他腳本不會等待它,它也不會等待其它東西。async 腳本就是一個會在加載完成時立即執行的完全獨立的腳本。

          這時再看時間線:

          可以看到,雖然下載a.js不阻塞html的解析,但是執行a.js會阻塞。

          還需要注意多個async時的執行順序,比如下面這段代碼:

          <p>...content before script...</p>
          
          <script async src="./js/a.js"></script>
          <script async src="./js/b.js"></script>
          
          <p>...content after script...</p>

          兩個p標簽的內容會立刻顯示出來,a.js和b.js則并行下載,且下載成功后立刻執行,所以多個async時的執行順序是誰先下載成功誰先執行。
          一些比較獨立的腳本,比如性能監控,就很適合用這種方式加載。

          另外,和defer一樣,async 特性也僅適用于外聯腳本。

          動態腳本

          我們可以動態地創建一個script標簽并append到文檔中。

          let script=document.createElement('script')
          script.src='/js/a.js'
          document.body.append(script)

          append后腳本就會立刻開始加載,表現默認和加了async屬性一致。
          我們可以顯示的設置
          script.async=false來改變這個默認行為,那么這時表現就和加了defer屬性一致。

          上面的這些寫法,當script標簽變多時,容易導致全局作用域污染,還要維護書寫順序,要解決這個問題,需要一種將 JavaScript 程序拆分為可按需導入的單獨模塊的機制,即js模塊化,我們接著往下看。

          CommonJS

          很長一段時間 JavaScript 沒有模塊化的概念,直到 Node.js 的誕生,把 JavaScript 帶到服務端,這時,CommonJS誕生了。

          CommonJS定義了三個全局變量:

          require,exports,module

          require 讀入并執行一個 js 文件,然后返回其 exports 對象;
          exports 對外暴露模塊的接口,可以是任何類型,指向 module.exports;
          module 是當前模塊,exports 是 module 上的一個屬性。

          Node.js 使用了CommonJS規范。

          比如:

          // a.js
          let name='Lily'
          export.name=name
          
          // b.js
          let a=require('a.js')
          console.log(a.name) // Lily

          由于CommonJS不適合瀏覽器端,于是出現了AMD和CMD規范。

          AMD

          AMD(Asynchronous Module Definition) 是 RequireJS 在推廣過程中對模塊定義的規范化產出。

          基本思想是,通過 define 方法,將代碼定義為模塊。當這個模塊被 require 時,開始加載依賴的模塊,當所有依賴的模塊加載完成后,開始執行回調函數,返回該模塊導出的值。

          使用時,需要先引入require.js:

          <script src="require.js"></script>
          <script src="a.js"></script>

          然后可以這樣寫:

          // a.js
          define(function() {
              let name='Lily'
              return {
                  name
              }
          })
          // b.js
          define(['a.js'], function(a) {
              let name='Bob'
              console.log(a.name) // Lily
              return {
                  name
              }
          })

          CMD

          CMD(Common Module Definition) 是 Sea.js 在推廣過程中對模塊定義的規范化產出。

          使用時,需要先引入sea.js:

          <script src="sea.js"></script>
          <script src="a.js"></script>

          然后可以這樣寫:

          // a.js
          define(function(require, exports, module) {
              var name='Lily'
              exports.name=name
          })
          
          // b.js
          define(function(require, exports, module) {
              var name='Bob'
              var a=require('a.js')
              console.log(a.name) // 'Lily'
              exports.name=name
          })

          UMD

          UMD (Universal Module Definition) 目的是提供一個前后端跨平臺的解決方案(兼容全局變量、AMD、CMD和CommonJS)。

          實現很簡單,判斷不同的環境,然后以不同的方式導出模塊:

          (function (root, factory) {
              if (typeof define==='function' && (define.amd || define.cmd)) {
                  // AMD、CMD
                  define([], factory);
              } else if (typeof module !=='undefined' && typeof exports==='object') {
                  // Node、CommonJS
                  module.exports=factory();
              } else {
                  // 瀏覽器全局變量
                  root.moduleName=factory();
            }
          }(this, function () {
              // 只需要返回一個值作為模塊的export
              // 這里我們返回了一個空對象
              // 你也可以返回一個函數
              return {};
          }));

          ES Module

          AMD 和 CMD 是社區的開發者們制定的模塊加載方案,并不是語言層面的標準。從 ES6 開始,在語言標準的層面上,實現了模塊化功能,而且實現得相當簡單,完全可以取代上文的規范,成為瀏覽器和服務器通用的模塊解決方案。

          ES6 的模塊自動采用嚴格模式。模塊功能主要由兩個命令構成:export和import。

          export命令用于規定模塊的對外接口;
          import命令用于輸入其他模塊提供的功能。

          比如上面的代碼,我們可以這樣寫:

          // a.js
          const name='Lily'
          
          export {
            name
          }
          
          // 等價于
          export const name='Lily'
          
          // b.js
          import { name } from 'a.js'
          console.log(name) // Lily
          
          // b.js
          import * as a from 'a.js'
          console.log(a.name) // Lily

          此外,還可以用export default默認導出的寫法:

          // a.js
          const name='Lily'
          
          export default {
            name
          }
          
          // b.js
          import a from 'a.js'
          console.log(a.name) // Lily

          如果只想運行a.js,可以只import:

          // b.js
          import 'a.js'

          我們可以給script標簽加type=module讓瀏覽器以 ES Module 的方式加載腳本:

          <script type="module" src="./js/b.js"></script>

          這時,script標簽會默認有defer屬性(也可以設置成async),支持內聯和外聯腳本。

          這時我們運行打開index.html,會發現瀏覽器報錯了:

          這是因為 type=module 的 script 標簽加強了安全策略,瀏覽器加載不同域的腳本資源時,如果服務器未返回有效的 Allow-Origin 相關 CORS 頭,會禁止加載改腳本。而這里啟動的index.html是一個本地文件(地址是file://路徑),將會遇到 CORS 錯誤,需要通過一個服務器來啟動 HTML 文件。

          Vite

          在瀏覽器支持 ES Module 之前,我們用工具實現JavaScript模塊化的開發,比如webpack、Rollup 和 Parcel 。但是當項目越來越大后,本地熱更新越來越慢,而 Vite 旨在利用ESM解決上述問題。

          Vite使用簡單,可以去官網(https://cn.vitejs.dev/)看看。

          總結

          老的規范了解即可,未來是ES Module的,用Vite可以極大的提升開發時的體驗,生產環境用Rollup打包。

          ommonJS、AMD、 CMD 都是 JavaScript 模塊化的規范。其中 CommonJS 側重于服務器端 JavaScript 模塊化規范,著名的 NodeJS 就是這種規范的實現;AMD(異步模塊定義)和 CMD(通用模塊定義)偏向于瀏覽器端 JavaScript 模塊化規范:RequireJS 遵循 AMD,SeaJS 則遵循 CMD。

          遵循這些規范,便可在需要時加載某些模塊,使得大量龐雜的代碼得以良好的組織和管理。模塊化還使得我們在管理和使用代碼不那么混亂,更方便與他人合作。

          CommonJS

          CommonJS 規范是出現的比較早,是一個偏向于服務器端的規范,NodeJS 便采用該規范。根據 CommonJS 規范,一個單獨的文件就是一個模塊。加載模塊使用 require 方法,您可以通過 require('something') 來加載模塊。該方法讀取一個文件并執行,最后返回文件內部 exports 的對象。因此,在 NodeJS 中,定義一個模塊就是寫一個新的 JavaScript 文件,最后要將文件的內容 exports 出來。

          不過,這種方法更適合服務端,因為在服務器端通過讀取本地磁盤加載模塊,同步加載速度很快。如果在客戶端,由于網絡等不穩定因素,同步加載模塊代碼有可能會阻塞,會影響 require 后代碼的執行。有沒有異步加載模塊的規范呢?

          AMD

          CommonJS 解決了 JavaScript 模塊化的問題,并可以用在瀏覽器中。但 CommonJS 是同步加載模塊,即用到模塊時即時加載,現加載現用,這種同步機制導致在瀏覽器端會出現各種問題:性能、可用性、調試和跨域等。

          鑒于瀏覽器的特殊情況,又出現了一個規范,這個規范呢可以實現異步加載依賴模塊,并且會提前加載那,這就是 AMD 規范,即 Asynchronous Module Definition,這種異步模塊定義規范,RequireJs 實現了這一規范:先定義所有依賴,然后在加載完成后的回調函數中執行,語法類似 require([module], callback)

          AMD 雖然實現了異步加載,但是必須開始就把所有依賴寫出來,其并不符合書寫的邏輯順序,能不能像 CommonJS 那樣用的時候在 require,并且還支持異步加載呢?

          CMD

          CMD ,Common Module Definition, 淘寶的玉伯實現了 SeaJs 并遵循該規范。CMD則是依賴就近,用的時候再 require。類似這樣:

          define(function(require, exports, module){
              var a=require('module a')
          ? ? a.doSomething()
          ? ? var b=require('module b') // 依賴可以就近加載
          ? ? b.doSomething()
          })

          AMD 和 CMD 最大的不同是對依賴模塊的執行時機不同,AMD 是提前執行,CMD 是延遲執行。不過 RequireJS 從 2.0 開始,也可以延遲執行。AMD 依賴前置,JavaScript 代碼可以方便知道依賴模塊有哪些,立即加載;而 CMD 推崇就近依賴,需要使用把模塊變為字符串解析一遍后才知道有哪些依賴,這是一些人詬病 CMD 的點,犧牲性能來換取開發的便利性,不過實際上運行中,解析模塊犧牲的時間幾乎可以忽略。


          主站蜘蛛池模板: 一区二区三区高清在线| 清纯唯美经典一区二区| 中文字幕一区二区区免| 午夜影院一区二区| 亚洲国产精品一区二区第一页| 成人精品一区二区三区电影| 亚洲A∨无码一区二区三区| 中文乱码精品一区二区三区 | 国模一区二区三区| 亚洲一区在线观看视频| 久久精品道一区二区三区| 精品国产不卡一区二区三区 | 久久免费国产精品一区二区| 一区二区三区精品高清视频免费在线播放 | 亚洲色无码一区二区三区| 国产精品乱码一区二区三区 | 无码一区18禁3D| 国产精品久久一区二区三区 | 国产精品视频无圣光一区| 日韩中文字幕精品免费一区| 亚洲熟妇av一区| 在线精品一区二区三区| 亚洲熟女综合色一区二区三区| 亚洲香蕉久久一区二区| 国产日本一区二区三区| 国产免费一区二区三区| 狠狠做深爱婷婷久久综合一区| 国产伦精品一区二区三区四区 | 国产AV一区二区三区无码野战| 久久99国产精品一区二区| 色噜噜AV亚洲色一区二区| 精品国产亚洲一区二区在线观看 | 天堂va在线高清一区| 无码人妻精品一区二区三区久久久 | 久久精品国产亚洲一区二区三区| 成人乱码一区二区三区av| 亚洲av无码不卡一区二区三区| 亚洲天堂一区二区三区| 影院成人区精品一区二区婷婷丽春院影视| 亚洲午夜一区二区电影院| 狠狠综合久久av一区二区|