色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

您好,歡迎來電子發燒友網! ,新用戶?[免費注冊]

您的位置:電子發燒友網>源碼下載>數值算法/人工智能>

Module的加載實現

大小:0.3 MB 人氣: 2017-09-28 需要積分:1

  本文主要介紹如何在瀏覽器和Node之中加載ES6模塊,以及實際開發中經常遇到的一些問題(比如循環加載)。

  瀏覽器加載

  傳統方法

  在HTML網頁中,瀏覽器通過

  《!-- 頁面內嵌的腳本 --》《type=“application/java”》// module code《/》《!-- 外部腳本 --》《type=“application/java”src=“path/to/myModule.js”》《/》

  上面的代碼中,由于瀏覽器腳本的默認語言是Java,因此type=”application/ java”可以省略。

  默認情況下,瀏覽器同步加載Java腳本,即渲染引擎遇到《》標簽就會停下來,等到腳本執行完畢再繼續向下渲染。如果是外部腳本,還必須加入腳本下載的時間。

  如果腳本體積很大,下載和執行的時間就會很長,因此造成瀏覽器堵塞,用戶會感覺到瀏覽器“卡死”了,沒有任何響應。這顯然是很不好的體驗,所以瀏覽器允許腳本異步加載,下面就是兩種異步加載的語法。

  《src=“path/to/myModule.js”defer》《/》《src=“path/to/myModule.js”async》《/》

  上面的代碼中,《》標簽打開defer或async屬性,腳本就會異步加載。渲染引擎遇到這一行命令就會開始下載外部腳本,但不會等它下載和執行,而是直接執行后面的命令。

  defer與async的區別是,前者要等到整個頁面正常渲染結束才會執行,而后者一旦下載完成,渲染引擎就會中斷渲染,執行這個腳本以后再繼續渲染。用一句話來說,defer是“渲染完再執行”,async是“下載完就執行”。另外,如果有多個defer腳本,則會按照它們在頁面出現的順序加載,而多個async腳本是不能保證加載順序的。

  加載規則

  瀏覽器加載ES6模塊時也使用《》標簽,但是要加入type=”module”屬性。

  《type=“module”src=“foo.js”》《/》

  上面的代碼在網頁中插入了一個模塊foo.js,由于type屬性設為module,所以瀏覽器知道這是一個ES6模塊。

  對于帶有type=”module”的《》,瀏覽器都是異步加載的,不會造成瀏覽器堵塞,即等到整個頁面渲染完再執行模塊腳本,等同于打開了《》標簽的defer屬性。

  《type=“module”src=“foo.js”》《/》《!-- 等同于 --》《type=“module”src=“foo.js”defer》《/》

  《》標簽的async屬性也可以打開,這時只要加載完成,渲染引擎就會中斷渲染立即執行。執行完成后,再恢復渲染。

  《type=“module”src=“foo.js”async》《/》

  ES6模塊也允許內嵌在網頁中,語法行為與加載外部腳本完全一致。

  《type=“module”》import utils from “。/utils.js”; // other code《/》

  對于外部的模塊腳本(上例是foo.js),有幾點需要注意。

  代碼是在模塊作用域之中運行,而不是在全局作用域中運行。模塊內部的頂層變量是外部不可見的。

  模塊腳本自動采用嚴格模式,無論有沒有聲明use strict。

  模塊之中可以使用import命令加載其他模塊(.js后綴不可省略,需要提供絕對URL或相對URL),也可以使用export命令輸出對外接口

  在模塊之中,頂層的this關鍵字返回undefined,而不是指向window。也就是說,在模塊頂層使用this關鍵字是無意義的。

  同一個模塊如果加載多次,將只執行一次。

  下面是一個示例模塊。

  importutils from ‘https://example.com/js/utils.js’; constx = 1; console.log(x === window.x);//falseconsole.log( this=== undefined); //truedeletex; //句法錯誤,嚴格模式禁止刪除變量

  利用頂層的this等于undefined這個語法點,可以監測當前代碼是否在ES6模塊之中。

  constisNotModule = this!== undefined;ES6模塊與CommonJS模塊的差異

  討論Node加載ES6模塊之前,必須了解ES6模塊與CommonJS模塊的差異,具體的兩大差異如下。

  CommonJS模塊輸出的是一個值的復制,ES6模塊輸出的是值的引用。

  CommonJS模塊是運行時加載,ES6模塊是編譯時輸出接口。

  第二個差異是因為CommonJS加載的是一個對象(即module.exports屬性),該對象只有在腳本運行結束時才會生成。而ES6模塊不是對象,它的對外接口只是一種靜態定義,在代碼靜態解析階段就會生成。

  下面重點解釋第一個差異。

  CommonJS模塊輸出的是值的復制,也就是說,一旦輸出一個值,模塊內部的變化就影響不到這個值。請看下面這個模塊文件lib.js的例子。

  // lib.jsvarcounter = 3; functionincCounter(){counter++; } module.exports = { counter: counter, incCounter: incCounter, };

  上面的代碼輸出內部變量counter和改寫這個變量的內部方法incCounter。然后,在main.js里面加載這個模塊。

  // main.jsvar mod= require( ‘。/lib’); console. log( mod.counter); // 3mod.incCounter(); console. log( mod.counter); // 3

  上面的代碼說明,lib.js模塊加載以后,它的內部變化就影響不到輸出的mod.counter了。這是因為mod.counter是一個原始類型的值,會被緩存。除非寫成一個函數,否則得到內部變動后的值。

  // lib.jsvarcounter = 3; functionincCounter(){counter++; } module.exports = { getcounter() {returncounter }, incCounter: incCounter, };

  上面的代碼中,輸出的counter屬性實際上是一個取值器函數。現在再執行main.js就可以正確讀取內部變量counter的變動了。

  $ node main.js 34

  ES6模塊的運行機制與CommonJS不一樣。JS引擎對腳本靜態分析的時候,遇到模塊加載命令import就會生成一個只讀引用。等到腳本真正執行時,再根據這個只讀引用到被加載的模塊中取值。換句話說,ES6的import有點像Unix系統的“符號連接”,原始值變了,import加載的值也會跟著變。因此,ES6模塊是動態引用,并且不會緩存值,模塊里面的變量綁定其所在的模塊。

  還是以上面的代碼為例。

  // lib.jsexportletcounter = 3; exportfunction incCounter() { counter++; } // main.jsimport { counter, incCounter } from ‘。/lib’; console. log(counter); // 3incCounter(); console.log(counter); // 4

  上面的代碼說明,ES6模塊輸入的變量counter是活的,完全反應其所在模塊lib.js內部的變化。

  再舉一個出現在export一節中的例子。

  //m1.js exportvarfoo = ‘bar’; setTimeout (() =》 foo = ‘baz’, 500); // m2.jsimport{foo}from‘。/m1.js’; console.log(foo); setTimeout(() =》 console.log(foo), 500);

  上面的代碼中,m1.js的變量foo在剛加載時是bar,過了500ms又變為baz。

  來看一下m2.js能否正確讀取這個變化。

  $ babel-node m2.js bar baz

  上面的代碼表明,ES6模塊不會緩存運行結果,而是動態地去被加載的模塊取值,并且變量總是綁定其所在的模塊。

  由于ES6輸入的模塊變量只是一個“符號連接”,所以這個變量是只讀的,對它進行重新賦值會報錯。

  // lib.jsexport letobj = {}; // main.jsimport { obj } from‘。/lib’; obj.prop = 123; // OKobj = {}; // TypeError

  上面的代碼中,main.js從lib.js輸入變量obj,可以對obj添加屬性,但是重新賦值就會報錯。因為變量obj指向的地址是只讀的,不能重新賦值,這就好比main.js創造了一個名為obj的const變量。

  最后,export通過接口輸出的是同一個值。不同的腳本加載這個接口得到的都是同樣的實例。

  // mod.jsfunctionC(){this.sum = 0; this.add = function(){this.sum += 1; }; this.show =function(){console.log( this.sum); }; } export letc = newC();

  上面的腳本mod.js輸出的是一個C的實例。不同的腳本加載這個模塊得到的都是同一個實例。

  // x.jsimport{c} from ‘。/mod’; c.add(); // y.jsimport{c} from ‘。/mod’; c.show(); // main.jsimport‘。/x’; import‘。/y’;

  現在執行main.js,輸出的是1。

  $ babel-node main.js 1

  這就證明了x.js和y.js加載的都是C的同一個實例。

  Node加載

  概述

  Node對ES6模塊的處理比較麻煩,因為它有自己的CommonJS模塊格式,與ES6模塊格式是不兼容的。目前的解決方案是,將兩者分開,ES6模塊和CommonJS采用各自的加載方案。

  在靜態分析階段,一個模塊腳本只要有一行import或export語句,Node就會認為該腳本為ES6模塊,否則就為CommonJS模塊。如果不輸出任何接口,但是希望被Node認為是ES6模塊,可以在腳本中加上如下語句。

  export{};

  上面的命令并不是輸出一個空對象,而是不輸出任何接口的ES6標準寫法。

  如果不指定絕對路徑,Node加載ES6模塊會依次尋找以下腳本,與require()的規則一致。

  import‘。/foo’; // 依次尋找// 。/foo.js// 。/foo/package.json// 。/foo/index.jsimport‘baz’; // 依次尋找// 。/node_modules/baz.js// 。/node_modules/baz/package.json// 。/node_modules/baz/index.js// 尋找上一級目錄// 。。/node_modules/baz.js// 。。/node_modules/baz/package.json// 。。/node_modules/baz/index.js// 再上一級目錄

  ES6模塊之中,頂層的this指向undefined,CommonJS模塊的頂層this指向當前模塊,這是兩者的一個重大差異。

  import命令加載CommonJS模塊

  Node采用CommonJS模塊格式,模塊的輸出都定義在module.exports屬性上面。在Node環境中,使用import命令加載CommonJS模塊,Node會自動將module.exports屬性當作模塊的默認輸出,即等同于export default。

  下面是一個CommonJS模塊。

  //a.js module. exports= { foo: ‘hello’, bar: ‘world’}; //等同于 exportdefault{ foo: ‘hello’, bar:‘world’};

  import命令加載上面的模塊,module.exports會被視為默認輸出。

  // 寫法一 importbaz from‘。/a’; // baz = {foo: ‘hello’, bar: ‘world’}; // 寫法二 import{defaultasbaz} from‘。/a’; // baz = {foo: ‘hello’, bar: ‘world’};

  如果采用整體輸入的寫法(import * as xxx from someModule),default會取代module.exports作為輸入的接口。

  import* as baz from ‘。/a’; //baz = { //get default() { returnmodule. exports;}, //get foo() {returnthis. default.foo}.bind(baz), //get bar() { returnthis. default.bar}.bind(baz) //}

  上面的代碼中,this.default取代了module.exports。需要注意的是,Node會自動為baz添加default屬性,通過baz.default獲取module.exports。

  // b.jsmodule.exports = null; // es.jsimport foo from‘。/b’; // foo = null;import * asbar from‘。/b’;// bar = {default:null};

  上面的代碼中,es.js采用第二種寫法時,要通過bar.default這樣的寫法才能獲取module.exports。

  下面是另一個例子。

  // c.jsmodule.exports = functiontwo(){ return 2; };// es.jsimport foo from‘。/c’; foo(); // 2import * asbar from‘。/c’; bar. default(); // 2bar(); // throws, bar is not a function

  上面的代碼中,bar本身是一個對象,不能當作函數調用,只能通過bar.default調用。

  CommonJS模塊的輸出緩存機制在ES6加載方式下依然有效。

  //foo.js module. exports= 123; setTimeout(_ =》module. exports= null);

  上面的代碼中,對于加載foo.js的腳本,module.exports將一直是123,而不會變成null。

  由于ES6模塊是編譯時確定輸出接口,CommonJS模塊是運行時確定輸出接口,所以采用import命令加載CommonJS模塊時,不允許采用下面的寫法。

  import{readfile} from‘fs’;

  上面的寫法不正確,因為fs是CommonJS格式,只有在運行時才能確定readfile接口,而import命令要求編譯時就確定這個接口。解決方法就是改為整體輸入。

  import * asexpress from‘express’; constapp = express. default(); import expressfrom‘express’; constapp = express();

  require命令加載ES6模塊

  采用require命令加載ES6模塊時,ES6模塊的所有輸出接口都會成為輸入對象的屬性。

  //es.js letfoo = { bar: ‘my-default’}; exportdefaultfoo; foo = null; //cjs.js constes_namespace = require( ‘。/es’); console.log(es_namespace. default); //{ bar: ‘my-default’}

  上面的代碼中,default接口變成了es_namespace.default屬性。另外,由于存在緩存機制,es.js對foo的重新賦值沒有在模塊外部反映出來。

  下面是另一個例子。

  // es.jsexport let foo = {bar: ‘my-default’}; export {foo asbar}; export functionf(){}; exportclassc{}; // cjs.jsconstes_namespace = require( ‘。/es’); // es_namespace = {// get foo() {return foo;}// get bar() {return foo;}// get f() {return f;}// get c() {return c;}// }循環加載

  “循環加載”(circular dependency)指的是,a腳本的執行依賴b腳本,而b腳本的執行又依賴a腳本。

  // a.jsvarb = require( ‘b’); // b.jsvara = require( ‘a’);

  通常,“循環加載”表示存在強耦合,如果處理不好,還可能導致遞歸加載,使得程序無法執行,因此應該避免出現這種現象。

  但是實際上,這是很難避免的,尤其是依賴關系復雜的大項目中很容易出現a依賴b,b依賴c,c又依賴a這樣的情況。這意味著,模塊加載機制必須考慮“循環加載”的情況。

  對于Java語言來說,目前最常見的兩種模塊格式CommonJS和ES6在處理“循環加載”時的方法是不一樣的,返回的結果也不一樣。

  CommonJS模塊的加載原理

  介紹ES6如何處理“循環加載”之前,先介紹目前最流行的CommonJS模塊格式的加載原理。

  CommonJS的一個模塊就是一個腳本文件。require命令第一次加載該腳本時就會執行整個腳本,然后在內存中生成一個對象。

  { id: ‘。。.’, exports: { 。。.}, loaded: true, 。。.}

  上面的代碼就是Node內部加載模塊后生成的一個對象。該對象的id屬性是模塊名,exports屬性是模塊輸出的各個接口,loaded屬性是一個布爾值,表示該模塊的腳本是否執行完畢。其他還有很多屬性,這里都省略了。

  以后需要用到這個模塊時就會到exports屬性上面取值。即使再次執行require命令,也不會再次執行該模塊,而是到緩存之中取值。也就是說,CommonJS模塊無論加載多少次,都只會在第一次加載時運行一次,以后再加載時就返回第一次運行的結果,除非手動清除系統緩存。

  CommonJS模塊的循環加載

  CommonJS模塊的重要特性是加載時執行,即腳本代碼在require的時候就會全部執行。一旦出現某個模塊被“循環加載”,就只輸出已經執行的部分,還未執行的部分不會輸出。

  讓我們來看一下Node官方文檔(nodejs.org/api/modules.html#modules_cycles)里面的例子。腳本文件a.js代碼如下。

  exports.done = false; varb = require( ‘。/b.js’); console.log( ‘在 a.js 之中,b.done = %j’, b.done); exports.done = true; console.log( ‘a.js 執行完畢’);

  上面的代碼之中,a.js腳本先輸出一個done變量,然后加載另一個腳本文件b.js。注意,此時a.js代碼就停在這里,等待b.js執行完畢再往下執行。

  再看b.js的代碼。

  exports.done = false; vara = require( ‘。/a.js’); console.log( ‘在 b.js 之中,a.done = %j’, a.done); exports.done = true; console.log( ‘b.js 執行完畢’);

  上面的代碼中,b.js執行到第二行就會加載a.js,這時就發生了“循環加載”,系統會去a.js模塊對應對象的exports屬性中取值,可是因為a.js還沒有執行完,因此從exports屬性中只能取回已經執行的部分,而不是最后的值。

  a.js已經執行的部分只有以下一行。

  exports. done= false;

  因此,對于b.js來說,它從a.js只輸入一個變量done,值為false。

  然后,b.js接著執行,等到全部執行完畢,再把執行權交還給a.js。于是,a.js接著執行,直到執行完畢。下面,我們來寫一個腳本main.js驗證這個過程。

  vara = require( ‘。/a.js’); varb = require( ‘。/b.js’); console.log( ‘在 main.js 之中, a.done=%j, b.done=%j’, a.done, b.done);

  執行main.js,運行結果如下。

  $ node main.js

  在 b.js 之中,a.done = false

  b.js 執行完畢

  在 a.js 之中,b.done = true

  a.js 執行完畢

  在 main.js 之中, a.done=true, b.done=true

  上面的代碼證明了兩件事。第一,在b.js之中,a.js沒有執行完畢,只執行了第一行。第二,reimain.js執行到第二行時不會再次執行b.js,而是輸出緩存的b.js的執行結果,即它的第四行。

  exports. done= true;

  總之,CommonJS輸入的是被輸出值的復制,而不是引用。

  另外,由于CommonJS模塊遇到循環加載時返回的是當前已經執行的部分的值,而不是代碼全部執行后的值,兩者可能會有差異。所以,輸入變量的時候必須非常小心。

  vara = require( ‘a’); // 安全的寫法varfoo = require( ‘a’).foo; // 危險的寫法exports.good =function(arg){returna.foo( ‘good’, arg); // 使用的是a.foo的最新值}; exports.bad =function(arg){returnfoo( ‘bad’, arg); // 使用的是一個部分加載時的值};

  上面的代碼中,如果發生循環加載,require(‘a’).foo的值很可能會被改寫,改用require(‘a’)會更保險一點。

  ES6模塊的循環加載

  ES6處理“循環加載”與CommonJS有本質的不同。ES6模塊是動態引用,如果使用import從一個模塊中加載變量(即import foo from ‘foo’),那么,變量不會被緩存,而是成為一個指向被加載模塊的引用,需要開發者保證在真正取值的時候能夠取到值。

  請看下面這個例子。

  // a.js如下import {bar} from ‘。/b.js’; console. log( ‘a.js’); console. log(bar); exportletfoo =‘foo’; // b.jsimport {foo} from ‘。/a.js’; console. log( ‘b.js’); console. log(foo); exportletbar =‘bar’;

  上面的代碼中,a.js加載b.js,b.js又加載a.js,構成循環加載。執行a.js,結果如下。

  $ babel-node a .jsb .jsundefined a .jsBar

  上面的代碼中,由于a.js的第一行是加載b.js,所以先執行的是b.js。而b.js的第一行又是加載a.js,這時由于a.js已經開始執行,所以不會重復執行,而是繼續執行b.js,因此第一行輸出的是b.js。

  接著,b.js要打印變量foo,這時a.js還沒有執行完,取不到foo的值,因此打印出來的是undefined。b.js執行完便會開始執行a.js,這時便會一切正常。

  再來看一個稍微復雜的例子(摘自 Axel Rauschmayer 的Exploring ES6,具體內容請查看exploringjs.com/es6/ch_modules.html)。

  // a.jsimport{bar} from ‘。/b.js’;export functionfoo(){console.log( ‘foo’); bar(); console.log( ‘執行完畢’); } foo(); // b.jsimport{foo} from ‘。/a.js’;export functionbar(){console.log( ‘bar’);if(Math.random() 》 0.5) { foo(); } }

  按照CommonJS規范,上面的代碼是無法執行的。a先加載b,然后b又加載a,這時a還沒有任何執行結果,所以輸出結果為null,即對于b.js來說,變量foo的值等于null,后面的foo()就會報錯。

  但是,ES6可以執行上面的代碼。

  $ babel-node a.js foo bar 執行完畢 // 執行結果也有可能是foo bar foo bar 執行完畢 執行完畢

  上面的代碼中,a.js之所以能夠執行,原因就在于ES6加載的變量都是動態引用其所在模塊的。只要引用存在,代碼就能執行。

  下面,我們來詳細分析這段代碼的運行過程。

  // a.js// 這一行建立一個引用,// 從`b.js`引用`bar`import{bar} from ‘。/b.js’;exportfunctionfoo(){// 執行時第一行輸出fooconsole.log( ‘foo’); // 到 b.js 執行 barbar(); console.log( ‘執行完畢’); } foo(); // b.js// 建立`a.js`的`foo`引用import{foo} from ‘。/a.js’;exportfunctionbar(){// 執行時,第二行輸出barconsole.log( ‘bar’); // 遞歸執行foo,一旦隨機數// 小于等于0.5,就停止執行if(Math.random() 》 0.5) { foo(); } }

  再來看ES6模塊加載器SystemJS(github.com/ModuleLoader/es6-module-loader/blob/master/ docs/circular-references-bindings.md)給出的一個例子。

  // even.jsimport{ odd } from ‘。/odd’ export var counter = 0;export functioneven(n){counter++; returnn == 0|| odd(n - 1); } // odd.jsimport{ even } from ‘。/even’;exportfunctionodd(n){returnn != 0&& even(n - 1); }

  上面的代碼中,even.js里面的函數even有一個參數n,只要該參數不等于0,結果就會減1,傳入加載的odd()。odd.js也會進行類似操作。

  運行上面這段代碼,結果如下。

  $ babel-node 》 import * asm from‘。/even.js’; 》 m.even( 10); true》 m.counter 6》 m.even(20) true》 m.counter 17

  上面的代碼中,參數n從10變為0的過程中,even()一共會執行6次,所以變量counter等于6。第二次調用even()時,參數n從20變為0,even()一共會執行11次,加上前面的6次,所以變量counter等于17。

  這個例子要是改寫成CommonJS,則會報錯,根本無法執行。

  // even.jsvarodd = require( ‘。/odd’); varcounter = 0; exports.counter = counter; exports.even = function(n){counter++; returnn == 0|| odd(n - 1); } // odd.jsvareven =require( ‘。/even’).even; module.exports = function(n){returnn != 0&& even(n - 1); }

  上面的代碼中,even.js加載odd.js,而odd.js又加載even.js,形成“循環加載”。這時,執行引擎就會輸出even.js已經執行的部分(不存在任何結果),所以在odd.js之中,變量even等于null,后面再調用even(n-1)就會報錯。

  $ node 》 varm = require( ‘。/even’); 》 m.even( 10) TypeError: even isnota functionES6模塊的轉碼

  瀏覽器目前還不支持ES6模塊,為了實現立刻使用,我們可以將其轉為ES5的寫法。除了Babel可以用來轉碼,還有以下兩個方法也可以用來轉碼。

  ES6 module transpiler

  ES6 module transpiler(github.com/esnext/es6-module-transpiler)是square公司開源的一個轉碼器,可以將ES6模塊轉為CommonJS模塊或AMD模塊,從而在瀏覽器中使用。

  首先,安裝這個轉碼器。

  $ npm install -g es6- module-transpiler

  然后,使用compile-modules convert命令將ES6模塊文件轉碼。

  $ compile-modules convert file1 .jsfile2 .js```

  -o參數可以指定轉碼后的文件名。

  $ compile-modules convert -o out.jsfile1 .js

  SystemJS

  第二種解決方法使用了SystemJS(github.com/systemjs/systemjs)。它是一個墊片庫(polyfill),可以在瀏覽器內加載ES6模塊、AMD模塊和CommonJS模塊,將其轉為ES5格式。它在后臺調用的是Google的Traceur轉碼器。

  使用時,先在網頁內載入system.js文件。

  《src=“system.js”》《/》

  然后,使用System.import方法加載模塊文件。

  《》System.import(‘。/app.js’); 《/》```

  上面代碼中的。/app指的是當前目錄下的app.js文件。它可以是ES6模塊文件,System.import會自動將其轉碼。

  需要注意的是,System.import使用異步加載,返回一個Promise對象,可以針對這個對象編程。下面是一個模塊文件。

  // app/es6-file.js:export classq{constructor() { this.es6 = ‘hello’; } }

  然后,在網頁內加載這個模塊文件。

  《》System.import(‘app/es6-file’).then(function(m){console.log(newm.q().es6); // hello}); 《/》

  上面的代碼中,System.import方法返回的是一個Promise對象,所以可以用then方法指定回調函數。

非常好我支持^.^

(0) 0%

不好我反對

(0) 0%

Module的加載實現下載

相關電子資料下載

      發表評論

      用戶評論
      評價:好評中評差評

      發表評論,獲取積分! 請遵守相關規定!

      ?
      主站蜘蛛池模板: 久久天堂网| 99热6精品视频6| 久久99热成人精品国产| 99热这里只有精品视频2| 无码任你躁久久久久久久| 可以看的黄页的网站| 国产精品永久在线| 扒开美女下面粉嫩粉嫩冒白浆| 亚洲精品无码不卡在线播HE| 日本少妇无码精品12P| 麻豆AV久久无码精品九九| 国内卡一卡二卡三免费网站| 超碰免费视频公开观看| 最新国产精品福利2020| 亚洲伊人精品| 亚洲91av| 无码中文字幕热热久久| 青青久在线视频免费观看| 老师的脚奴| 久久99这里只有精品| 国产亚洲精品久久精品69| 干丝袜美女| 被肉日常np高h| 99久久国产露脸国语对白| 中文字幕人成乱码中国| 一本道久在线综合色姐| 亚洲精品一区三区三区在线观看| 兽皇VIDEO另类HD| 日日噜噜大屁股熟妇| 秋霞网在线伦理免费| 欧美精品色视频| 美女岔开腿露出粉嫩花苞| 久久精品无码成人国产毛| 精品国产乱码久久久久久软件 | 入禽太深免费观看| 欧美另类jizzhd| 嫩草AV久久伊人妇女| 蜜桃传媒视频| 美女扒开尿孔| 免费撕开胸罩吮胸视频| 免费在线观看国产|