精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

Rust 編譯為 WebAssembly 在前端項目中的使用

開發 項目管理
為了保持構建速度非常快,web-sys?將每個Web接口都封裝在一個Cargo特性后面。在API文檔中找到我們要使用的類型或方法;它將列出必須啟用的特性才能訪問該API。

前言

最近,加大了對Rust相關文章的輸出。在評論區或者私信區有一些不同的聲音說:“Rust沒有前途,然后...."。其實呢,看一個技術是否有需要學習的動力。想必大家的底層理由都是「一切都是向錢看」,畢竟在國內大家都是業務為主,想自己純手搞一套符合自己的技術框架和范式,這是不切實際的。(當然也不能一桿子打死,還是有很多技術大牛的)現在大家糾結或者對這個技術屬于觀望態度,無非就是在平時開發工作中沒有涉及到的點。

同時,由于國內技術的「滯后性」,有一些應用場景其實還是處于蠻荒的狀態。(不是崇洋媚外,事實確實如此)。所以,在一些可以用到新的技術點的方向上,國內還是處于藍海階段。

所以,本著對該技術的獨有關注度,我還是選擇義無反顧的投身到學習和實際中。「沖破黎明之前的黑暗,你會擁有太陽,而晨曦中第一縷陽光也是為你而耀眼」。

圖片圖片

而具體,Rust到底能給你帶來點啥,我們之前有文章講過,這里就不在贅述了。

Last but not leaset,由于現在本人暫時專注于前端領域居多,所以我更多關注Rust能為前端帶來點啥。而說到Rust和前端,第一點的聯想就是:WebAssembly。(如果,不了解何為WebAssembly,可以參考我們之前的文章瀏覽器第四種語言-WebAssembly,里面的例子是用Emscripten寫的)

其實,我們之前寫過如何用C寫wasm,也寫過WebAssembly-C與JS互相操作等文章。但是,由于一些不可言喻的原因擱置了。

我們今天將使用Rust創建一個WebAssembly Hello World程序。我們將深入了解由wasm-bindgen生成的代碼,以及它們如何共同協作來幫助我們進行開發。我們還將使用wabt來探索生成的wasm代碼。這將使我們更好地理解Rust WebAssembly,并為我們的開發奠定良好的基礎。

好了,天不早了,干點正事哇。

我們能所學到的知識點

  1. 前置知識點
  2. 項目搭建
  3. 原理探析
  4. 內容拓展

1. 前置知識點

「前置知識點」,只是做一個概念的介紹,不會做深度解釋。因為,這些概念在下面文章中會有出現,為了讓行文更加的順暢,所以將本該在文內的概念解釋放到前面來。「如果大家對這些概念熟悉,可以直接忽略」同時,由于閱讀我文章的群體有很多,所以有些知識點可能「我視之若珍寶,爾視只如草芥,棄之如敝履」。以下知識點,請「酌情使用」。

安裝Rust

如果是你一個Rust萌新,我們也給你提供Rust環境配置和入門指南。

如果,想獨立完成安裝,可以到Rust 安裝頁面跟著教程安裝。

在安裝成功Rust后,它會安裝一個名為rustup的工具,這個工具能讓我們管理多個不同版本的 Rust。默認情況下,它會安裝用于慣常 Rust 開發的 stable 版本 Rust Release。

Rustup 會安裝

  • Rust 的編譯器 rustc
  • Rust 的包管理工具 cargo
  • Rust 的標準庫 rust-std
  • 以及一些有用的文檔 rust-docs

因為,我本機已經安裝好了Rust。我們可以通過rustup --version來查看rustup的版本。以下是我本機的rustup版本信息。下文中所有的代碼,都基于該版本。

rustup --version
rustup 1.26.0 (5af9b9484 2023-04-05)

安裝WebAssembly二進制工具包(wabt)

圖片圖片

這些工具旨在用于開發工具鏈或其他系統,這些系統希望「操作WebAssembly文件」。與WebAssembly規范解釋器不同(該解釋器旨在盡可能簡單、聲明性和“規范性”),這些工具是用C/C++編寫的,并設計成更容易集成到其他系統中。這些工具不旨在提供優化平臺或更高級的編譯目標;相反,它們旨在實現與規范的完全適應和遵從。

我們可以利用brew來在Mac環境下安裝。

圖片圖片

2. 項目搭建

2.1 安裝wasm-bindgen

我們可以通過cargo install --list來查看在$HOME/.cargo/bin位置安裝過的Rust二進制文件。

在一些其他的教程中可以不使用wasm-bindgen構建Hello World程序,但是在本文中,我們將使用它,因為它在Rust WebAssembly開發中是必不可少的。

cargo install wasm-bindgen-cli

Rust WebAssembly允許我們將WebAssembly模塊有針對性地插入到現有的JavaScript應用程序中,尤其是在「性能關鍵的代碼路徑」中。我們可以將wasm-bindgen視為一種工具,它通過生成用于JavaScript和WebAssembly之間高效交互的「粘合代碼」和綁定來幫助我們實現絲滑的交互體驗。

2.2 創建Rust WebAssembly項目

巴拉拉小魔仙,念誦如下咒語,構建一個Rust WebAssembly項目。

cargo new hello_world --lib

上面的代碼是使用Cargo工具創建一個新的Rust項目,項目的名稱是hello_world,并且指定它是一個庫(--lib)。這將創建一個包含基本項目結構的文件夾,其中包括一個Cargo.toml文件和一個src文件夾。

+-- Cargo.toml
+-- src
    +-- lib.rs
  • Cargo.toml文件用于管理項目的依賴和配置
  • src文件夾包含項目的Rust源代碼文件
  • 項目名稱hello_world是一個示例名稱,我們可以根據自己的需求為項目指定不同的名稱。

2.3 修改Cargo.toml配置項

使用宇宙最強IDE -VScode,打開Cargo.toml文件。我們應該會看到以下內容。

[package]
name = "hello_world"
version = "0.1.0"
authors = ["789"]
edition = "2021"

[dependencies]

將其修改成下面的內容

[package]
name = "hello_world"
version = "0.1.0"
authors = ["789"]
edition = "2021"

[lib]
crate-type = ["cdylib"]

[dependencies]
wasm-bindgen = "0.2"

上面的大部分字段大家都能看懂,其中lib項的配置,這里稍微解釋一下:

crate-type = ["cdylib"]: 這一行「指定了生成的庫的類型」。在這里,crate-type 設置為["cdylib"],這表示我們正在創建一個動態鏈接庫(C-compatible dynamic library)。這用于編譯一個供其他編程語言加載的動態庫。此輸出類型將在Linux上創建*.so文件,在macOS上創建*.dylib文件,在Windows上創建*.dll文件。

這種類型的庫可以被其他編程語言調用,因為它們與C語言兼容。這對于與WebAssembly(Wasm)互操作性很重要,因為Wasm通常需要與C語言接口進行交互。因此,cdylib 表示該庫是一個可供其他語言使用的動態鏈接庫。

2.4 編輯lib.rs

打開src/lib.rs文件。將其更改為以下內容:

extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;

// 導入 'window.alert'
#[wasm_bindgen]
extern "C" {
    fn alert(s: &str);
}

// 導出一個 'helloworld' 函數
#[wasm_bindgen]
pub fn helloworld(name: &str) {
    alert(&format!("Hello World : {}!", name));
}

我們簡單解釋一下核心代碼:

  1. extern crate wasm_bindgen;: 這一行聲明了對wasm_bindgen庫的依賴。wasm_bindgen是一個Rust庫,用于構建Wasm模塊并提供與JavaScript的互操作性。在 Rust 當中,庫被稱為crates,因為我們使用的是一個外部庫,所以有 extern。
  2. use wasm_bindgen::prelude::*;: 這一行導入了wasm_bindgen庫的預導出(prelude)模塊中的所有內容,以便在后續代碼中使用。

在 Rust 中調用來自 JavaScript 的外部函數

#[wasm_bindgen]
extern "C" {
    fn alert(s: &str);
}

#[wasm_bindgen]: 在 #[] 中的內容叫做 "屬性",并以某種方式改變下面的語句。#[wasm_bindgen]是一個「屬性標記」,用于指定與WebAssembly互操作相關的特性。

extern "C" { fn alert(s: &str); }: 這里聲明了一個「外部函數」alert,它使用extern "C" 指定了C ABI(應用二進制接口),這意味著它「可以與C語言進行交互」。「這個alert函數沒有在Rust中實現,而是在JavaScript中實現,用于在瀏覽器中顯示警告框」。

在 JavaScript 中調用的 Rust 函數

#[wasm_bindgen]
pub fn helloworld(name: &str) {
    alert(&format!("Hello World : {}!", name));
}

#[wasm_bindgen] pub fn helloworld(name: &str): 這是一個Rust函數helloworld,它被標記為wasm_bindgen,這意味著它「可以被JavaScript調用」。這個函數接受一個「字符串參數」name,然后調用「之前聲明」的alert函數,以顯示帶有Hello World消息的彈框,并在消息中包括name參數的內容。

2.5 編譯代碼

在命令行中輸入以下命令:

cargo build --target wasm32-unknown-unknown

如果未安裝對應的庫,控制臺會給出提示。

圖片圖片

那我們就照貓畫虎的操作一下:

rustup target add wasm32-unknown-unknown?

  1. cargo build: 這是 Cargo 工具的命令,用于構建 Rust 項目。它會編譯項目的源代碼并生成可執行文件或庫文件,具體取決于項目的類型。
  2. --target wasm32-unknown-unknown: 這部分是構建的目標參數。--target 標志用于指定要構建的目標平臺。在這里,wasm32-unknown-unknown 是指定了 WebAssembly 目標平臺。這告訴 Cargo 生成「適用于 WebAssembly 的二進制文件」,而不是生成本地平臺的二進制文件。

當運行這個命令后,Cargo 會使用 Rust 編譯器(Rustc)以及與 WebAssembly 相關的工具鏈,將 Rust 代碼編譯為 WebAssembly 格式的二進制文件。這個生成的 Wasm 文件可以在瀏覽器中運行,或與其他支持 WebAssembly 的環境一起使用。

運行結果如下:

cargo build --target wasm32-unknown-unknown 命令的「默認輸出位置」是在項目的 target 目錄下,具體位置是:

target/wasm32-unknown-unknown/debug/

在這個目錄下,我們會找到生成的 WebAssembly 文件(通常是一個 .wasm 文件),以及其他與編譯過程相關的文件。

圖片圖片

2.6 構建 Web服務器

既然,我們通過上述的魔法,將Rust程序編譯為了可以在瀏覽器環境下引用執行的格式。「為了這口醋,我們還專門包頓餃子」。

我們需要一個Web服務器來測試我們的WebAssembly程序。我們將使用Webpack,我們需要創建三個文件:index.js、package.json和webpack.config.js。

下面的代碼,我們最熟悉不過了,就不解釋了。

index.js

// 直接引入了,剛才編譯后的文件
const rust = import('./pkg/hello_world.js');

rust
  .then(m => m.helloworld('World!'))
  .catch(console.error);

package.json

{
  "scripts": {
    "build": "webpack",
    "serve": "webpack-dev-server"
  },

  "devDependencies": {
    "@wasm-tool/wasm-pack-plugin": "0.4.2",
    "text-encoding": "^0.7.0",
    "html-webpack-plugin": "^3.2.0",
    "webpack": "^4.29.4",
    "webpack-cli": "^3.1.1",
    "webpack-dev-server": "^3.1.0"
  }
}

webpack.config.js

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack');
const WasmPackPlugin = require("@wasm-tool/wasm-pack-plugin");

module.exports = {
    entry: './index.js',
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'index.js',
    },
    plugins: [
        new HtmlWebpackPlugin(),
        new WasmPackPlugin({
            crateDirectory: path.resolve(__dirname, ".")
        }),
        // 讓這個示例在不包含`TextEncoder`或`TextDecoder`的Edge瀏覽器中正常工作。
        new webpack.ProvidePlugin({
            TextDecoder: ['text-encoding', 'TextDecoder'],
            TextEncoder: ['text-encoding', 'TextEncoder']
        })
    ],
    mode: 'development'
};

安裝指定的依賴。

npm install webpack --save-dev
npm install webpack-cli --save-dev
npm install webpack-dev-server --save-dev
npm install html-webpack-plugin --save-dev
npm install @wasm-tool/wasm-pack-plugin --save-dev
npm install text-encoding --save-dev

2.7 構建&運行程序

使用npm run build構建程序。

使用npm run serve運行Hello World程序

在瀏覽器中打開localhost:8080,我們將看到一個顯示 Hello World! 的彈窗。

圖片圖片

到目前為止,我們已經構建了一個wasm并且能夠和js實現功能交互的項目。其實,到這里已經完成了,我們這篇文章的使命。但是,在這里戛然而止,感覺缺失點啥。所以,我們繼續深挖上面的項目的實現原理。

3. 原理探析

在使用cargo和wasm_bindgen編譯源代碼時,會在pkg文件中「自動生成」以下文件:

  • "hello_world_bg.wasm"
  • "hello_world.js"
  • "hello_world.d.ts"
  • "package.json"

這些文件也可以通過使用以下wasm-bindgen命令手動生成:

wasm-bindgen target/wasm32-unknown-unknown/debug/hello_world.wasm --out-dir ./pkg

瀏覽器調用順序

以下顯示了當我們在瀏覽器中訪問localhost:8080時發生的函數調用序列。

  1. index.js
  2. hello_world.js (調用hello_world_bg.js)
  3. helloworld_bg.wasm

index.js

const rust = import('./pkg/hello_world.js');

rust
  .then(m => m.helloworld('World!'))
  .catch(console.error);

index.js 導入了 hello_world.js 并調用其中的 helloworld 函數。

hello_world.js

下面是hello_world.js的內容,在其中它調用了helloworld_bg.wasm

import * as wasm from "./hello_world_bg.wasm";
import { __wbg_set_wasm } from "./hello_world_bg.js";
__wbg_set_wasm(wasm);
export * from "./hello_world_bg.js";

hello_world_bg.js

// ...省去了部分代碼
export function helloworld(name) {
    const ptr0 = passStringToWasm0(name, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
    const len0 = WASM_VECTOR_LEN;
    wasm.helloworld(ptr0, len0);
}

hello_world_bg.js 文件是由wasm-bindgen自動生成的,它包含了用于將DOM和JavaScript函數導入到Rust中的JavaScript粘合代碼。它還在生成的WebAssembly函數上向JavaScript公開了API。

Rust WebAssembly專注于將WebAssembly與現有的JavaScript應用程序集成在一起。為了實現這一目標,我們需要在JavaScript和WebAssembly函數之間「傳遞不同的值、對象或結構。這并不容易,因為需要協調兩個不同系統的不同對象類型」。

更糟糕的是,當前WebAssembly僅支持「整數」和「浮點數」,不支持字符串。這意味著我們不能簡單地將字符串傳遞給WebAssembly函數。

要將字符串傳遞給WebAssembly,我們需要「將字符串轉換為數字」(請注意在webpack.config.js中指定的TextEncoderAPI),將這些數字放入WebAssembly的內存空間中,最后「返回一個指向字符串的指針」給WebAssembly函數,以便在JavaScript中使用它。在最后,我們需要釋放WebAssembly使用的字符串內存空間。

如果我們查看上面的JavaScript代碼,這正是自動執行的操作。helloworld函數首先調用passStringToWasm。

  • 這個函數在WebAssembly中「創建一些內存空間」,將我們的字符串轉換為數字,將數字寫入內存空間,并返回一個指向字符串的指針。

圖片圖片

  • 然后將指針傳遞給wasm.helloworld來執行JavaScript的alert。最后,wasm.__wbindgen_free釋放了內存。

如果只是傳遞一個簡單的字符串,我們可能可以自己處理,但考慮到當涉及到更復雜的對象和結構時,這個工作會很快變得非常復雜。這說明了wasm-bindgen在Rust WebAssembly開發中的重要性。

反編譯wasm到txt

在前面的步驟中,我們注意到wasm-bindgen生成了一個hello_world.js文件,其中的函數調用到我們生成的hello_world_bg.wasm中的WebAssembly代碼。

基本上,hello_world.js充當其他JavaScript(如index.js)與生成的WebAssembly的helloworld_bg.wasm之間的橋梁。

我們可以通過輸入以下命令進一步探索helloworld_bg.wasm:

wasm2wat hello_world_bg.wasm > hello_world.txt

這個命令使用wabt將WebAssembly轉換為WebAssembly文本格式,并將其保存到一個hello_world.txt文件中。打開helloworld.txt文件,然后查找$helloworld函數。這是我們在src/lib.rs中定義的helloworld函數的生成WebAssembly函數。

$helloworld函數

圖片圖片

在helloworld.txt中查找以下行:

(export "helloworld" (func $helloworld))

這一行導出了wasm.helloworld供宿主調用的WebAssembly函數。我們通過hello_world_bg.js中的wasm.helloworld來調用這個WebAssembly函數。

圖片圖片

接下來,查找以下行:

(import "./hello_world_bg.js" "__wbg_alert_9ea5a791b0d4c7a3" (func $hello_world::alert::__wbg_alert_9ea5a791b0d4c7a3::h93c656ecd0e94e40 (type 4)))

這對應于在hello_world_bg.js中生成的以下JavaScript函數:

export function __wbg_alert_9ea5a791b0d4c7a3() { return logError(function (arg0, arg1) {
    alert(getStringFromWasm0(arg0, arg1));
}, arguments) };

這是wasm-bindgen提供的「粘合部分」,幫助我們在WebAssembly中使用JavaScript函數或DOM。

最后,讓我們看看wasm-bindgen生成的其他文件。

hello_world.d.ts

這個.d.ts文件包含JavaScript粘合的TypeScript類型聲明,如果我們的現有JavaScript應用程序正在使用TypeScript,它會很有用。我們可以對調用WebAssembly函數進行「類型檢查」,或者讓我們的IDE提供自動完成。如果我們不使用TypeScript,可以安全地忽略這個文件。

package.json

package.json文件包含有關生成的JavaScript和WebAssembly包的元數據。它會自動從我們的Rust代碼中填充所有npm依賴項,并使我們能夠發布到npm。

4. 內容拓展

再次看一下以下代碼:

hello_world_bg.js

function helloworld(name) {
    const ptr0 = passStringToWasm0(name, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
    const len0 = WASM_VECTOR_LEN;
    wasm.helloworld(ptr0, len0);
}

該代碼用于分配和釋放內存,這一切都是「由程序自動處理」的。不需要垃圾回收器或完整的框架引擎,使得使用Rust編寫的WebAssembly應用程序或模塊變得小巧且優化。其他需要垃圾回收器的語言將需要包含用于其底層框架引擎的wasm代碼。因此,無論它們有多么優化,其大小都不會小于Rust提供的大小。這使得Rust WebAssembly成為一個不錯的選擇,如果我們需要將小型WebAssembly模塊集成或注入到JavaScript Web應用程序中。

除了Hello World之外,還有一些其他需要注意的事項:

web-sys

使用wasm-bindgen,我們可以通過使用extern在Rust WebAssembly中調用JavaScript函數。請記住src/lib.rs中的以下代碼:

#[wasm_bindgen]
extern "C" {
    fn alert(s: &str);
}

Web具有大量API,從DOM操作到WebGL再到Web Audio等等。因此,如果我們的Rust WebAssembly程序增長,并且我們需要對Web API進行多次不同的調用,我們將需要花時間編寫大量的extern代碼。

?

web-sys充當wasm-bindgen的前端,為所有Web API提供原始綁定。

?

這意味著如果我們使用web-sys,可以節省時間,而不必編寫extern代碼。

圖片圖片

引入web-sys

將web-sys添加為Cargo.toml的依賴項:

[dependencies]
wasm-bindgen = "0.2"

[dependencies.web-sys]
version = "0.3"
features = [
]

為了保持構建速度非常快,web-sys將每個Web接口都封裝在一個Cargo特性后面。在API文檔中找到我們要使用的類型或方法;它將列出必須啟用的特性才能訪問該API。

例如,如果我們要查找window.resizeTo函數,我們會在API文檔中搜索resizeTo。我們將找到web_sys::Window::resize_to函數,它需要啟用Window特性。要訪問該函數,我們在Cargo.toml中啟用Window特性:

[dependencies.web-sys]
version = "0.3"
features = [
  "Window"
]

調用這個方法:

use wasm_bindgen::prelude::*;
use web_sys::Window;

#[wasm_bindgen]
pub fn make_the_window_small() {
    // 調整窗口大小為500px x 500px。
    let window = web_sys::window().unwrap();
    window.resize_to(500, 500)
        .expect("無法調整窗口大小");
}

這段代碼的目的是調整瀏覽器窗口的大小為500x500像素,并演示了如何使用web-sys和啟用的Cargo特性來調用Web API。

責任編輯:武曉燕 來源: 前端柒八九
相關推薦

2024-09-30 09:25:29

2023-06-15 15:21:43

2022-06-22 10:04:29

JavaScriptRust語言

2023-04-21 10:08:00

版本工具依賴關系

2015-10-12 16:37:39

前端編碼雙向編譯

2018-01-27 21:19:06

前端Rust Service

2016-10-28 15:01:35

Cookie前端實踐

2021-12-27 10:46:07

WebAPIserver簽名

2017-01-09 07:05:26

谷歌編程語言

2017-06-15 10:36:35

WebAssembly計算模塊

2021-06-11 09:00:00

語言WebWebAssembly

2009-06-24 17:34:58

使用JSF的經驗

2021-08-18 08:00:00

Emscripten開發技術

2021-05-18 13:05:31

LinuxRust復用器

2023-09-22 14:33:24

微軟Rust開發工具

2022-06-02 08:01:11

云原生工具

2020-10-27 14:15:42

SpringBoot

2019-01-03 09:45:20

Go 前端 Web

2024-05-16 11:45:19

Rust項目代碼

2019-03-25 10:30:19

開發技能代碼
點贊
收藏

51CTO技術棧公眾號

国产精品分类| 色999韩欧美国产综合俺来也| 国产99精品在线观看| 欧美激情精品久久久久久蜜臀| 国产在线观看免费播放| 看黄在线观看| 国产精品蜜臀av| 国产二区一区| 中文字幕理论片| 欧美日韩免费| 夜夜躁日日躁狠狠久久88av| 国产资源中文字幕| 国内激情视频在线观看| 中文字幕亚洲欧美在线不卡| 国产精品免费区二区三区观看 | 国产无套内射久久久国产| 国产精品秘入口| 成人网男人的天堂| 国产精品三级久久久久久电影| 精品无码m3u8在线观看| 日韩精品一区二区三区免费观影| 欧美成人a∨高清免费观看| 爆乳熟妇一区二区三区霸乳| 激情av在线播放| 国产精品免费视频观看| 精品免费视频123区| 91美女精品网站| 香蕉久久夜色精品国产| 欧美成人性生活| 国产视频三区四区| 另类ts人妖一区二区三区| 欧美日韩国产一级二级| 免费无码av片在线观看| 国产在线拍揄自揄拍视频 | 欧美国产综合视频| www.天堂在线| 美女一区二区视频| 日本精品久久中文字幕佐佐木| 国产一级二级三级视频| 国产高清一区| 在线精品高清中文字幕| 国产吞精囗交久久久| 国产成人精品亚洲线观看| 91精品婷婷国产综合久久性色| 五月天婷婷激情视频| 九色porny丨国产首页在线| 一区二区三区在线观看动漫| 亚洲一区二区在线观| 国产鲁鲁视频在线观看免费| 2019国产精品| 久久国产日韩欧美| 五月天婷婷在线播放| 成人av网站免费观看| 91在线观看网站| aa视频在线免费观看| 久久国产三级精品| 国产日韩欧美视频在线| 一区二区的视频| 久久精品国产秦先生| 国产精品影院在线观看| 中文字幕激情视频| 看国产成人h片视频| 国产日韩在线视频| 国产喷水福利在线视频| 国产一区二区精品在线观看| 91精品视频免费看| av中文字幕免费| 国产成人精品免费一区二区| 国产高清不卡av| 视频污在线观看| 久久日韩精品一区二区五区| 奇米888一区二区三区| 成av人电影在线观看| 亚洲国产激情av| 黄瓜视频免费观看在线观看www | 国产色产综合产在线视频 | 久久久久亚洲| 欧美精品免费在线| 日本特黄一级片| 免费看亚洲片| 国产精品视频自拍| 国产美女裸体无遮挡免费视频| 国产一区二区免费在线| 国产精品久久久久av福利动漫| 性感美女一级片| 国产欧美精品一区| 91制片厂免费观看| 超碰在线资源| 日本韩国精品一区二区在线观看| 国产精品区在线| 日本一区二区乱| 亚洲精品电影久久久| 青娱乐国产视频| 欧美国产91| 欧美中文在线视频| 国产乱码久久久久| 粉嫩嫩av羞羞动漫久久久| 欧美极品日韩| 国产最新在线| 欧美日在线观看| 午夜免费看毛片| 国产精品毛片视频| 色综合亚洲精品激情狠狠| 久久久久久久久久久久久久免费看 | 午夜激情视频在线播放| 在线免费观看欧美| 国产精品美女久久久久久免费 | 国产在线精品视频| 免费在线成人av| 黄av在线播放| 91久久免费观看| 人妻 丝袜美腿 中文字幕| 国产欧美日韩影院| 欧美激情区在线播放| 在线视频精品免费| av一区二区三区四区| 一区二区三区四区免费视频| 白浆在线视频| 欧美一区二区啪啪| 自拍偷拍你懂的| 国产日韩欧美| 国产高清自拍一区| 好操啊在线观看免费视频| 欧美综合欧美视频| 久久久久久久久免费看无码| 欧美视频日韩| 成人福利网站在线观看| 国产中文在线观看| 欧美日韩视频免费播放| 亚洲最大视频网| 亚洲91视频| 成人av资源在线播放| 国产h在线观看| 一本大道久久精品懂色aⅴ| 精品伦一区二区三区| 亚洲精品一二三区区别| 国产精品人成电影在线观看| 蜜桃视频久久一区免费观看入口| 亚洲色图丝袜美腿| 中文字幕av不卡在线| 精品国产一区一区二区三亚瑟 | av成人在线看| 国产一区二区免费| 在线精品免费视| 99久久综合精品| 131美女爱做视频| 9l视频自拍九色9l视频成人| 欧美日本亚洲视频| 亚洲av无码国产精品久久不卡 | 神马久久资源| 亚洲免费福利视频| 黄色片网站在线免费观看| 99久久精品国产导航| 国产69精品久久久久久久| 秋霞午夜一区二区三区视频| 美女性感视频久久久| 午夜久久久久久噜噜噜噜| 亚洲欧美日韩中文字幕一区二区三区 | 国产视频一区二区| 日韩欧美一二三区| 久草精品视频在线观看| 97成人超碰视| 五十路熟女丰满大屁股| 亚洲精品蜜桃乱晃| 国产成人综合久久| 1769视频在线播放免费观看| 欧美人妖巨大在线| 天天综合天天做| 成人va在线观看| 成人免费观看视频在线观看| 精品一区二区三区在线| 国产欧美精品在线播放| v片在线观看| 精品国产乱码久久久久久久 | 国产日韩在线播放| 最新黄网在线观看| 亚洲二区在线播放视频| 美女又爽又黄免费视频| 国产精品久久三| av影片在线播放| 99视频精品| 五月天亚洲综合情| 欧美成人精品午夜一区二区| 久久久久这里只有精品| 嫩草研究院在线| 欧美人狂配大交3d怪物一区| 久久综合激情网| 国产亚洲欧洲997久久综合| 五月天丁香花婷婷| 亚洲人成毛片在线播放女女| 日本在线成人一区二区| 美女国产精品久久久| 5566成人精品视频免费| 日本精品一区二区三区在线播放| 日韩欧美二区三区| 日韩电影在线观看一区二区| 自拍偷在线精品自拍偷无码专区| 白丝校花扒腿让我c| 久久精品官网| 男人c女人视频| 色综合中文网| 高清av免费一区中文字幕| 成人爽a毛片免费啪啪| 久久人人爽人人爽爽久久| 天天综合网在线| 91麻豆精品国产91久久久使用方法 | 国产精品人人做人人爽人人添| 日本wwwwwww| 奇米四色…亚洲| 国产主播自拍av| 国产精品久久久久一区二区三区厕所| 狠狠色噜噜狠狠狠狠色吗综合| 欧美a视频在线| 91大神在线播放精品| 黄av在线播放| 中文日韩在线视频| 四虎精品在线| 日韩女优电影在线观看| 中文无码精品一区二区三区| 黑人精品xxx一区| 91精品一区二区三区蜜桃| 久久精品人人做| 中文字幕乱码一区| 国产精品99久久久久久宅男| 亚洲人辣妹窥探嘘嘘| 国产精品资源| 国产欧美日韩网站| 欧美一区视频| av不卡在线免费观看| 欧美色爱综合| 品久久久久久久久久96高清| 西野翔中文久久精品字幕| 国产精品成人一区二区三区| 国产不卡精品| 91美女片黄在线观| 国产一区影院| 国产精品免费视频xxxx| 日本精品裸体写真集在线观看| 欧美综合在线第二页| av在线中出| 久久久久久久久国产精品| 伦理在线一区| 久久久久久有精品国产| 青青草视频在线免费直播| 欧美大片欧美激情性色a∨久久| 精品视频在线一区二区| 最近2019年中文视频免费在线观看| 国产午夜视频在线观看| 亚洲欧美一区二区三区久久| 日本私人网站在线观看| 亚洲老头同性xxxxx| 香蕉久久一区二区三区| 国产视频久久久久| 欧美色综合一区二区三区| 日韩精品视频中文在线观看| 污污网站在线免费观看| 国产午夜精品理论片a级探花| 五月天婷婷在线观看| 亚洲欧美精品一区| 国产三级在线看| 中文字幕日韩高清| 日韩精品成人av| 欧美精品手机在线| 久久不射影院| 欧美在线观看视频| 在线日本欧美| 成人国产在线视频| 伊色综合久久之综合久久| 国模精品一区二区三区| 欧美男男gaytwinkfreevideos| 日本高清久久一区二区三区| 久久美女视频| 蜜桃视频一区二区在线观看| 亚洲国产精品一区制服丝袜| 欧美成人xxxxx| 日本美女视频一区二区| 中文字幕第66页| 成人国产亚洲欧美成人综合网| 国产一级二级视频| 国产偷国产偷亚洲高清人白洁| 女性裸体视频网站| 亚洲一区二区欧美激情| 亚洲熟女综合色一区二区三区| 欧美日本在线观看| 欧性猛交ⅹxxx乱大交| 亚洲日本aⅴ片在线观看香蕉| 免费看美女视频在线网站| 欧美极品第一页| 欧美大片免费| 91精品黄色| 首页亚洲中字| 黑人巨大国产9丨视频| 国产日韩一区二区三区在线播放| 亚洲36d大奶网| 成人午夜视频福利| 少妇的滋味中文字幕bd| 亚洲五码中文字幕| 中文字幕一区二区三区免费看| 欧美mv和日韩mv的网站| 韩国中文字幕2020精品| 欧美华人在线视频| 不卡亚洲精品| 久久久久九九九| 亚洲一区二区三区无吗| 欧美视频第一区| 国v精品久久久网| 天堂资源在线视频| 懂色av影视一区二区三区| 国产精品自产拍| 日韩二区三区在线| 青青青国内视频在线观看软件| 国产精品免费福利| 亚洲精品无吗| 久久99久久99精品| 久久99在线观看| 中文字幕免费在线播放| 成人欧美一区二区三区| 老熟妇仑乱一区二区av| 精品粉嫩超白一线天av| 免费网站成人| 国产精品美女久久久久av超清| 久久激情av| 日本a级片在线播放| 美女网站视频久久| 亚洲精品色午夜无码专区日韩| 亚洲成av人在线观看| 成人h动漫精品一区二区无码| 综合av色偷偷网| 日韩在线影院| 久久伊人一区二区| 日韩午夜一区| 一级少妇精品久久久久久久| 亚洲欧美一区二区三区国产精品| 国产又粗又猛又爽又| 亚洲精品乱码久久久久久金桔影视| 亚洲无线看天堂av| 91影视免费在线观看| 91麻豆精品国产91久久久平台| 毛片av免费在线观看| 26uuu精品一区二区三区四区在线| 久久久国产精华液| 日韩精品在线看片z| av网站在线免费| 91中文精品字幕在线视频| 国产精品国产三级国产在线观看| www.这里只有精品| 国产精品久久久久久亚洲毛片| 国产天堂第一区| 亚洲一级黄色av| 成人看片网页| 午夜精品视频在线观看一区二区| 日韩成人一区二区| 我不卡一区二区| 欧美日韩在线直播| 毛片在线播放a| 91黄在线观看| 亚洲香蕉网站| 国产一级黄色录像| 精品国产乱码久久久久久天美 | 国产福利一区二区三区视频在线| 色偷偷www8888| 日韩三级精品电影久久久| 青春草在线视频| 久久精品magnetxturnbtih| 亚洲欧美日韩一区在线观看| 蜜臀av一区二区三区有限公司| 在线观看国产一区二区| 一区二区高清不卡| 97人人澡人人爽| 在线欧美日韩| 久久精品成人av| 欧美日韩在线观看一区二区| 国产美女在线观看| 国产精品视频免费一区| 亚洲欧美日韩精品一区二区 | 精品日韩在线| 国内自拍第二页| 亚洲一区二区欧美激情| 青青视频在线观| 成人综合国产精品| 亚洲二区精品| 精品成人无码一区二区三区| 制服丝袜日韩国产| sm性调教片在线观看| 亚洲成人网上| 国产91高潮流白浆在线麻豆| 欧美精品一二三四区| 久久久精品国产亚洲| 欧美在线关看| 午夜精品免费看| 婷婷中文字幕一区三区| www.在线视频.com| 国产精品久久久久久久久久久久冷| 久久中文在线| 久久久久久久久久久97| 中文字幕不卡av| 免费萌白酱国产一区二区三区| 中国黄色片免费看| 亚洲国产你懂的| 日本蜜桃在线观看|