色五月色开心色婷婷色丁香,五月婷婷丁香花综合网,婷婷丁香五月激情综合在线,五月婷婷六月丁香动漫,婷婷丁香五月激情综合在线,丁香花中文字幕在线观看,播五月色五月开心五月网,开心激情综合网,狠狠色丁香婷婷综合最新地址,丁香视频在线观看,狠狠做六月爱婷婷综合av,久久激情五月丁香伊人

ARTICLE DETAIL

資訊詳情

深耕商務(wù)建站與企業(yè)官網(wǎng)運(yùn)營(yíng)的一線實(shí)戰(zhàn)洞察。

WebAssembly圖像處理加速實(shí)戰(zhàn):主線程卡頓的真相與優(yōu)化方案

WebAssembly圖像處理加速實(shí)戰(zhàn):主線程卡頓的真相與優(yōu)化方案 用 WebAssembly 給前端圖像處理加速結(jié)果低端機(jī)上該卡還是卡主線程居然還在等先說(shuō)結(jié)論如果你只是把圖像處理函數(shù)用 C/C 編譯成 WebAssembly然后繼續(xù)在主線程里同步調(diào)用那你大概率還是會(huì)卡。而且卡的感受可能和純 JavaScript 版本沒(méi)有本質(zhì)區(qū)別只是卡的時(shí)間稍微短了一點(diǎn)。真正的問(wèn)題不在于“WASM 有沒(méi)有加速”而在于“你到底把什么留在了主線程上”。這篇文章會(huì)從 WebAssembly 圖像處理的基本原理開(kāi)始帶著大家做一個(gè)完整的灰度化 高斯模糊實(shí)戰(zhàn)然后分析為什么低端機(jī)上依然會(huì)卡最后給出工程上真正可行的優(yōu)化方案。內(nèi)容比較長(zhǎng)適合以下讀者聽(tīng)說(shuō)過(guò) WebAssembly 但還沒(méi)實(shí)際用過(guò)的前端開(kāi)發(fā)者。想用 WASM 做圖像處理、濾鏡、截圖工具、Canvas 性能優(yōu)化的開(kāi)發(fā)者。已經(jīng)做了 WASM 接入但發(fā)現(xiàn)頁(yè)面在低端機(jī)/老舊機(jī)型上依然卡頓的人。準(zhǔn)備面試時(shí)聊到 WebAssembly、Web Worker、OffscreenCanvas 的候選人。文章里的代碼都可以直接復(fù)制到本地工程跑我會(huì)盡量把細(xì)節(jié)交代清楚。1. 為什么“圖像處理”會(huì)讓人想到 WebAssembly1.1 JavaScript 做圖像處理的瓶頸在哪里先看一個(gè)最常見(jiàn)的圖像處理場(chǎng)景前端把一張圖片繪制到 Canvas 上然后通過(guò)getImageData拿到像素?cái)?shù)據(jù)再進(jìn)行濾鏡、灰度、模糊、邊緣檢測(cè)等操作最后再putImageData回去。const canvas document.getElementById(canvas); const ctx canvas.getContext(2d); const image new Image(); image.onload () { // 繪制原圖 ctx.drawImage(image, 0, 0, width, height); // 獲取像素?cái)?shù)據(jù) const imageData ctx.getImageData(0, 0, width, height); const data imageData.data; // 遍歷像素做處理 for (let i 0; i data.length; i 4) { const gray 0.299 * data[i] 0.587 * data[i 1] 0.114 * data[i 2]; data[i] gray; data[i 1] gray; data[i 2] gray; } ctx.putImageData(imageData, 0, 0); };這個(gè)循環(huán)在筆者的理解里是最典型的“看著簡(jiǎn)單跑起來(lái)難受”的代碼。對(duì)于一張 1920×1080 的圖片總像素點(diǎn)是 207 萬(wàn)RGBA 字節(jié)數(shù)是 829 萬(wàn)。循環(huán) 829 萬(wàn)次還要做浮點(diǎn)乘法和數(shù)組賦值JavaScript 引擎即使有 JIT 優(yōu)化也扛不住頻繁的裝箱、類型判斷和垃圾回收壓力。一幀能做完還好如果還要疊加多個(gè)濾鏡主線程就會(huì)明顯卡頓。1.2 WebAssembly 適合解決哪一類問(wèn)題WebAssembly 是一種可以在瀏覽器中運(yùn)行的二進(jìn)制指令格式它能提供的核心價(jià)值是接近原生的數(shù)值計(jì)算性能。類型固定沒(méi)有 JavaScript 的動(dòng)態(tài)類型開(kāi)銷。內(nèi)存管理更可控不依賴 JavaScript 的 GC??蓮?fù)用 C/C/Rust 等語(yǔ)言的成熟圖像處理庫(kù)。對(duì)于“純計(jì)算密集、循環(huán)次數(shù)多、數(shù)據(jù)類型單一”的任務(wù)比如像素遍歷、矩陣運(yùn)算、卷積濾波WebAssembly 確實(shí)能帶來(lái)肉眼可見(jiàn)的加速。1.3 誤區(qū)不是把函數(shù)換成 WASM 就萬(wàn)事大吉很多人對(duì) WebAssembly 的期待是只要把函數(shù)編譯成 WASM原來(lái)卡的問(wèn)題就自動(dòng)解決了。但實(shí)際上WebAssembly 只是把你的一部分計(jì)算搬到了更高效的指令層。它沒(méi)有改變以下事實(shí)你還是拿到了一整塊像素?cái)?shù)據(jù)。你還是得把處理結(jié)果繪回到 Canvas。如果你在主線程上同步執(zhí)行無(wú)論計(jì)算多快主線程都被占住了。如果內(nèi)存拷貝、數(shù)據(jù)傳遞、渲染這一步開(kāi)銷占比很高WASM 帶來(lái)的收益可能被抵消。尤其是低端機(jī)CPU 單核性能弱、GPU 渲染能力有限、瀏覽器本身的內(nèi)存管理效率也一般主線程一旦被長(zhǎng)時(shí)間占用頁(yè)面就會(huì)出現(xiàn)明顯的掉幀甚至觸發(fā)瀏覽器“腳本運(yùn)行時(shí)間過(guò)長(zhǎng)”的提示。所以我們要做的不是“用 WASM 替換 JS”而是理解整個(gè)圖像處理鏈路的瓶頸在哪里再針對(duì)性地優(yōu)化。2. 環(huán)境準(zhǔn)備與工具鏈2.1 整體技術(shù)棧本文實(shí)戰(zhàn)部分使用以下組合C 語(yǔ)言編寫(xiě)圖像處理核心函數(shù)。Emscripten 將 C 編譯為 .wasm 文件。JavaScript 負(fù)責(zé)加載 WASM 模塊、調(diào)用導(dǎo)出函數(shù)、讀寫(xiě)像素?cái)?shù)據(jù)。Canvas 負(fù)責(zé)圖像繪制和結(jié)果展示。Web Worker 負(fù)責(zé)真正把繁重計(jì)算移出主線程。如果你對(duì) Rust 更熟悉用wasm-bindgen也可以但本文以 Emscripten 為例因?yàn)樗腸call/cwrap交互方式對(duì)前端新手更友好C 代碼也最容易讀懂。2.2 Emscripten 環(huán)境安裝Emscripten 的安裝官方推薦使用emsdk管理工具。# 克隆 emsdk 倉(cāng)庫(kù) git clone https://github.com/emscripten-core/emsdk.git cd emsdk # Windows 執(zhí)行 emsdk.batmacOS/Linux 執(zhí)行 ./emsdk ./emsdk install latest ./emsdk activate latest # 激活環(huán)境變量 source ./emsdk_env.sh這里的latest指的是當(dāng)前 Emscripten 最新版本具體版本號(hào)會(huì)因?yàn)闀r(shí)間變化而不一樣。安裝完成后執(zhí)行emcc --version能輸出版本信息就說(shuō)明環(huán)境可用。2.3 項(xiàng)目結(jié)構(gòu)為了不把工程搞復(fù)雜我們準(zhǔn)備一個(gè)最簡(jiǎn)結(jié)構(gòu)wasm-image-process/ ├── src/ │ └── image_processor.c ├── public/ │ ├── index.html │ ├── main.js │ ├── worker.js │ └── image_processor.wasm # 編譯后生成 ├── build.sh └── package.json其中public目錄可以直接用靜態(tài)服務(wù)器打開(kāi)。如果你本地沒(méi)有靜態(tài)服務(wù)器也可以用 Python 一行命令啟動(dòng)python3 -m http.server 80803. 用 C 語(yǔ)言實(shí)現(xiàn)圖像處理核心函數(shù)3.1 為什么用 C 編寫(xiě)而不是直接用 JavaScript在這個(gè)示例里我們選擇把“灰度化”和“高斯模糊”這兩個(gè)核心算法用 C 實(shí)現(xiàn)原因很簡(jiǎn)單像素循環(huán)是典型的密集計(jì)算C 的循環(huán)效率很高。卷積濾波需要大量乘加運(yùn)算C 沒(méi)有 JavaScript 的動(dòng)態(tài)類型開(kāi)銷。Emscripten 編譯后的 WASM 模塊可以導(dǎo)出清晰的函數(shù)接口前端調(diào)用成本低。3.2 C 代碼實(shí)現(xiàn)先看src/image_processor.c的完整代碼。// 文件路徑src/image_processor.c #include stdint.h #include stdlib.h #include string.h // 灰度化處理加權(quán)平均法 // data 是 RGBA 像素緩沖區(qū)width/height 為圖像尺寸 void grayscale(uint8_t *data, int width, int height) { int pixelCount width * height; for (int i 0; i pixelCount; i) { int index i * 4; uint8_t r data[index]; uint8_t g data[index 1]; uint8_t b data[index 2]; // 加權(quán)灰度公式人眼對(duì)綠色最敏感 uint8_t gray (uint8_t)(0.299f * r 0.587f * g 0.114f * b); data[index] gray; data[index 1] gray; data[index 2] gray; // alpha 通道保持不變 } } // 高斯模糊使用 3x3 卷積核分離式近似 // 為了簡(jiǎn)化這里采用一次 3x3 卷積 void gaussianBlur(uint8_t *data, int width, int height) { // 拷貝一份原始數(shù)據(jù)避免覆蓋影響后續(xù)計(jì)算 size_t size (size_t)width * height * 4; uint8_t *temp (uint8_t *)malloc(size); if (!temp) { return; } memcpy(temp, data, size); // 3x3 高斯核權(quán)重 const float kernel[3][3] { {1.0f / 16, 2.0f / 16, 1.0f / 16}, {2.0f / 16, 4.0f / 16, 2.0f / 16}, {1.0f / 16, 2.0f / 16, 1.0f / 16} }; for (int y 1; y height - 1; y) { for (int x 1; x width - 1; x) { for (int c 0; c 3; c) { // RGB 通道alpha 不參與模糊 int offset (y * width x) * 4 c; float sum 0.0f; for (int ky -1; ky 1; ky) { for (int kx -1; kx 1; kx) { int neighborOffset ((y ky) * width (x kx)) * 4 c; sum temp[neighborOffset] * kernel[ky 1][kx 1]; } } data[offset] (uint8_t)sum; } } } free(temp); }這段代碼的核心思路是grayscale遍歷每個(gè)像素把 RGB 三個(gè)通道按權(quán)重合成為一個(gè)灰度值。gaussianBlur先復(fù)制原圖數(shù)據(jù)再用 3×3 卷積核對(duì)每個(gè)像素的 RGB 通道做加權(quán)平均避免使用鄰域計(jì)算結(jié)果污染之后的像素。3.3 暴露給 JavaScript 的內(nèi)存操作函數(shù)C 代碼里還應(yīng)該提供內(nèi)存分配和釋放函數(shù)方便 JavaScript 從 WASM 堆中申請(qǐng)空間。// 提供給 JS 調(diào)用的內(nèi)存分配器 uint8_t *allocBuffer(int size) { return (uint8_t *)malloc(size); } void freeBuffer(uint8_t *ptr) { free(ptr); }3.4 編譯命令使用 Emscripten 編譯時(shí)要指定導(dǎo)出這兩個(gè)圖像處理函數(shù)和內(nèi)存函數(shù)。emcc src/image_processor.c \ -O3 \ -s WASM1 \ -s EXPORTED_FUNCTIONS[_grayscale, _gaussianBlur, _allocBuffer, _freeBuffer] \ -s EXPORTED_RUNTIME_METHODS[ccall, cwrap, HEAPU8, malloc, free] \ -o public/image_processor.wasm上面的參數(shù)含義-O3開(kāi)啟最高級(jí)優(yōu)化。-s WASM1生成 wasm 格式。EXPORTED_FUNCTIONS指定要導(dǎo)出的 C 函數(shù)注意 Emscripten 默認(rèn)會(huì)在函數(shù)名前加下劃線。EXPORTED_RUNTIME_METHODS把 JS 側(cè)常用的ccall、HEAPU8等方法暴露出來(lái)。如果編譯時(shí)提示缺少某些運(yùn)行時(shí)方法可以按報(bào)錯(cuò)信息追加到EXPORTED_RUNTIME_METHODS里。編譯完成之后public目錄下會(huì)多出一個(gè)image_processor.wasm文件這個(gè)文件可以直接被靜態(tài)服務(wù)器訪問(wèn)。4. 前端集成從加載 WASM 到渲染結(jié)果4.1 頁(yè)面結(jié)構(gòu)和樣式先寫(xiě)一個(gè)簡(jiǎn)單的頁(yè)面用來(lái)選圖片、點(diǎn)按鈕、展示處理結(jié)果。!-- 文件路徑public/index.html -- !DOCTYPE html html langzh-CN head meta charsetUTF-8 / meta nameviewport contentwidthdevice-width, initial-scale1.0 / titleWebAssembly 圖像處理 Demo/title style body { font-family: Arial, sans-serif; padding: 20px; background: #f7f8fa; } .container { display: flex; gap: 16px; flex-wrap: wrap; } .card { background: #fff; border-radius: 8px; padding: 16px; box-shadow: 0 2px 6px rgba(0,0,0,0.08); } canvas { max-width: 100%; border: 1px solid #ddd; border-radius: 4px; } button { margin: 6px 4px 6px 0; padding: 8px 14px; border-radius: 6px; border: none; background: #3b82f6; color: #fff; cursor: pointer; } button:disabled { background: #aaa; cursor: not-allowed; } .status { margin-top: 12px; color: #555; font-size: 14px; } /style /head body h2WebAssembly 圖像處理實(shí)踐/h2 input typefile idfileInput acceptimage/* / button idgrayscaleBtn灰度化/button button idblurBtn高斯模糊/button div classcontainer div classcard h3原圖/h3 canvas idsourceCanvas width480 height360/canvas /div div classcard h3處理結(jié)果/h3 canvas idoutputCanvas width480 height360/canvas /div /div div classstatus idstatus請(qǐng)選擇一張圖片/div script src./main.js/script /body /html這里用了兩個(gè)canvas一個(gè)繪制原始圖片一個(gè)繪制處理后的圖片方便對(duì)比。4.2 主線程調(diào)用 WASM 的代碼第一版這一版先直接在主線程里調(diào)用 WASM 函數(shù)功能上能跑但后面我們會(huì)發(fā)現(xiàn)它的性能問(wèn)題。// 文件路徑public/main.js let wasmModule null; let sourceCanvas document.getElementById(sourceCanvas); let outputCanvas document.getElementById(outputCanvas); let statusText document.getElementById(status); let fileInput document.getElementById(fileInput); let originalImageData null; // 加載 WASM 模塊 async function loadWasm() { const response await fetch(/image_processor.wasm); const bytes await response.arrayBuffer(); const result await WebAssembly.instantiate(bytes, {}); wasmModule result.instance.exports; statusText.textContent WASM 模塊加載成功請(qǐng)選擇圖片; } // 讀取圖片并繪制到 canvas fileInput.addEventListener(change, (e) { const file e.target.files[0]; if (!file) return; const img new Image(); const objectUrl URL.createObjectURL(file); img.onload () { const width Math.min(img.width, 640); const height Math.min(img.height, 480); sourceCanvas.width width; sourceCanvas.height height; outputCanvas.width width; outputCanvas.height height; const ctx sourceCanvas.getContext(2d); ctx.drawImage(img, 0, 0, width, height); originalImageData ctx.getImageData(0, 0, width, height); // 初始顯示原圖 const outputCtx outputCanvas.getContext(2d); outputCtx.putImageData(originalImageData, 0, 0); URL.revokeObjectURL(objectUrl); statusText.textContent 圖片尺寸${width} × ${height}總共 ${width * height} 像素; }; img.src objectUrl; }); // 調(diào)用 WASM 處理圖像 function processImage(type) { if (!originalImageData) { statusText.textContent 請(qǐng)先選擇圖片; return; } const width originalImageData.width; const height originalImageData.height; const data new Uint8ClampedArray(originalImageData.data); // 在 WASM 內(nèi)存中申請(qǐng)輸入輸出緩沖區(qū) const size data.length; const inputPtr wasmModule.allocBuffer(size); // 把像素?cái)?shù)據(jù)拷貝到 WASM 堆 wasmModule.HEAPU8.set(data, inputPtr); // 調(diào)用圖像處理函數(shù) if (type grayscale) { wasmModule.grayscale(inputPtr, width, height); } else if (type blur) { wasmModule.gaussianBlur(inputPtr, width, height); } // 從 WASM 堆中讀取結(jié)果 const resultData new Uint8ClampedArray( wasmModule.HEAPU8.buffer, inputPtr, size ); // 把結(jié)果放回 Canvas const outputImageData new ImageData(resultData, width, height); const outputCtx outputCanvas.getContext(2d); outputCtx.putImageData(outputImageData, 0, 0); // 釋放 WASM 內(nèi)存 wasmModule.freeBuffer(inputPtr); statusText.textContent 處理完成${type}; } document.getElementById(grayscaleBtn).addEventListener(click, () processImage(grayscale)); document.getElementById(blurBtn).addEventListener(click, () processImage(blur)); // 頁(yè)面加載時(shí)初始化 loadWasm();這段代碼的關(guān)鍵點(diǎn)逐一說(shuō)一下。wasmModule.allocBuffer(size)是在 WASM 堆中申請(qǐng)一塊內(nèi)存返回的是內(nèi)存偏移量也可以理解為指針值。wasmModule.HEAPU8.set(data, inputPtr)是把 JavaScript 側(cè)的像素?cái)?shù)據(jù)拷貝到 WASM 線性內(nèi)存中這樣 C 代碼才能讀取到。調(diào)用wasmModule.grayscale(inputPtr, width, height)后C 代碼會(huì)直接在 WASM 堆上修改像素?cái)?shù)據(jù)。最后再用new Uint8ClampedArray(wasmModule.HEAPU8.buffer, inputPtr, size)創(chuàng)建一個(gè)視圖直接讀取那塊內(nèi)存不需要再拷貝一次。new ImageData(resultData, width, height)把結(jié)果包裝成 Canvas 可識(shí)別的像素結(jié)構(gòu)。看起來(lái)邏輯完整功能也能跑通。但在性能上這版代碼存在不少問(wèn)題接下來(lái)我們用實(shí)際數(shù)據(jù)說(shuō)話。5. 性能實(shí)測(cè)為什么低端機(jī)上該卡還是卡5.1 用 performance.now 測(cè)量耗時(shí)為了更直觀地看到性能差異可以在按鈕事件里加上耗時(shí)統(tǒng)計(jì)。const start performance.now(); // 執(zhí)行處理... const end performance.now(); console.log(處理耗時(shí)${(end - start).toFixed(2)}ms); statusText.textContent 處理完成${type}耗時(shí) ${(end - start).toFixed(2)}ms;如果拿一張 1920×1080 的圖片做灰度化在配置較好的開(kāi)發(fā)機(jī)上WASM 版本可能只需要 20ms 左右而純 JS 版本可能需要 60ms 甚至更多。但在低端機(jī)上你會(huì)發(fā)現(xiàn)一個(gè)現(xiàn)象CPU 弱的情況下WASM 計(jì)算本身要花的時(shí)間變多了。更大的問(wèn)題在于從getImageData到putImageData的整條鏈路上渲染、內(nèi)存拷貝、Canvas 合成每一項(xiàng)都在消耗主線程時(shí)間。一旦圖片尺寸較大比如 2560×1440WASM 計(jì)算可能只需要幾十毫秒但整條鏈路加起來(lái)會(huì)超過(guò)一兩百毫秒這時(shí)候頁(yè)面已經(jīng)能感到明顯掉幀了。5.2 主線程為什么還會(huì)“等”這就是標(biāo)題里說(shuō)的“主線程居然還在等”的核心原因。很多人以為 WebAssembly 是“多線程”其實(shí)不是。WASM 模塊默認(rèn)運(yùn)行在調(diào)用它的同一個(gè)線程上。你的 JavaScript 調(diào)用wasmModule.grayscale()時(shí)主線程會(huì)把控制權(quán)交給 WASM 執(zhí)行WASM 計(jì)算期間主線程被完全阻塞不能處理點(diǎn)擊、滾動(dòng)、動(dòng)畫(huà)、輸入事件。低端機(jī)上 CPU 頻率低、緩存小、核心數(shù)少這種阻塞時(shí)間會(huì)被進(jìn)一步放大。5.3 性能瓶頸拆解一次完整的前端圖像處理耗時(shí)分布大致如下環(huán)節(jié)說(shuō)明是否可優(yōu)化圖片解碼由瀏覽器完成通常較慢可選不同解碼策略getImageData從 Canvas 讀取像素需要同步內(nèi)存拷貝大量消耗主線程數(shù)據(jù)拷貝到 WASM 堆HEAPU8.set全量拷貝可減少或避免WASM 計(jì)算灰度/模糊等核心算法可通過(guò) SIMD、多線程優(yōu)化從 WASM 堆讀取結(jié)果視圖讀取實(shí)際沒(méi)有額外拷貝可接受new ImageData創(chuàng)建像素?cái)?shù)據(jù)對(duì)象開(kāi)銷較大putImageData寫(xiě)回 Canvas觸發(fā)合成大量消耗主線程瀏覽器合成顯示由瀏覽器 compositor 完成可通過(guò) OffscreenCanvas 優(yōu)化你會(huì)發(fā)現(xiàn)“WASM 計(jì)算”只是其中一個(gè)環(huán)節(jié)。如果其他環(huán)節(jié)都擠在主線程上哪怕 WASM 計(jì)算只要 1ms整個(gè)鏈路的耗時(shí)依然可能高達(dá) 100ms。5.4 低端機(jī)上更容易暴露的問(wèn)題低端機(jī)的卡頓往往是疊加效應(yīng)導(dǎo)致的主線程越忙用戶點(diǎn)擊、滾動(dòng)的響應(yīng)越遲。Canvas 越大getImageData和putImageData的耗時(shí)越高。圖片解碼本身就慢加載大圖時(shí) UI 線程更容易阻塞。瀏覽器內(nèi)存不足時(shí)內(nèi)存頻繁申請(qǐng)和回收會(huì)進(jìn)一步拖慢整個(gè)頁(yè)面。所以只把計(jì)算從 JS 換成 WASM是一種“局部?jī)?yōu)化”它沒(méi)有解決“主線程被占用”這個(gè)根本問(wèn)題。6. 真正能落地的優(yōu)化方案把重活移出主線程6.1 Web Worker 是第一步Web Worker 可以創(chuàng)建一個(gè)獨(dú)立于主線程的后臺(tái)線程在 Worker 中執(zhí)行計(jì)算密集型任務(wù)不會(huì)阻塞 UI。把 WASM 加載、像素計(jì)算、內(nèi)存操作都移到 Worker 里主線程只負(fù)責(zé)傳數(shù)據(jù)、接收結(jié)果、渲染。6.2 OffscreenCanvas 解決渲染瓶頸OffscreenCanvas允許你在 Worker 里直接操作 Canvas不需要把像素?cái)?shù)據(jù)從 Worker 傳回主線程再putImageData。它可以把putImageData的耗時(shí)也挪出主線程。6.3 完整改造方案先改造 Worker。這一步的關(guān)鍵是Worker 內(nèi)部加載 WASM接收主線程發(fā)來(lái)的像素?cái)?shù)據(jù)處理完再通過(guò)postMessage把結(jié)果回傳。// 文件路徑public/worker.js let wasmModule null; // 在 Worker 內(nèi)加載 WASM注意這里的 fetch 路徑相對(duì)于當(dāng)前的 Worker 文件 async function loadWasm() { const response await fetch(/image_processor.wasm); const bytes await response.arrayBuffer(); const result await WebAssembly.instantiate(bytes, {}); wasmModule result.instance.exports; return true; } async function init() { await loadWasm(); self.postMessage({ type: ready }); } function processImageData(imageDataBuffer, width, height, operation) { const data new Uint8ClampedArray(imageDataBuffer); const size data.length; // 在 WASM 內(nèi)存中申請(qǐng)緩沖區(qū) const inputPtr wasmModule.allocBuffer(size); wasmModule.HEAPU8.set(data, inputPtr); if (operation grayscale) { wasmModule.grayscale(inputPtr, width, height); } else if (operation blur) { wasmModule.gaussianBlur(inputPtr, width, height); } // 讀取結(jié)果 const resultData new Uint8ClampedArray( wasmModule.HEAPU8.buffer, inputPtr, size ); // 復(fù)制一份普通數(shù)組方便 postMessage 傳輸 const output new Uint8ClampedArray(resultData); wasmModule.freeBuffer(inputPtr); return output; } self.onmessage async (event) { const { type, width, height, imageDataBuffer, operation } event.data; if (type init) { await init(); return; } if (type process) { const startTime performance.now(); const outputData processImageData(imageDataBuffer, width, height, operation); const endTime performance.now(); self.postMessage({ type: result, imageData: outputData.buffer, width, height, duration: endTime - startTime }, [outputData.buffer]); } };注意這里postMessage的第二個(gè)參數(shù)是轉(zhuǎn)移列表把outputData.buffer轉(zhuǎn)移給主線程避免結(jié)構(gòu)化克隆的額外拷貝。這個(gè)細(xì)節(jié)對(duì)于性能優(yōu)化非常重要。再改造主線程的main.js。// 文件路徑public/main.js (Worker 版本) let worker null; let sourceCanvas document.getElementById(sourceCanvas); let outputCanvas document.getElementById(outputCanvas); let statusText document.getElementById(status); let fileInput document.getElementById(fileInput); let originalImageData null; // 初始化 Worker function initWorker() { worker new Worker(./worker.js); worker.onmessage (event) { const msg event.data; if (msg.type ready) { statusText.textContent 圖像處理 Worker 已就緒請(qǐng)選擇圖片; } if (msg.type result) { const imageData new ImageData( new Uint8ClampedArray(msg.imageData), msg.width, msg.height ); const outputCtx outputCanvas.getContext(2d); outputCtx.putImageData(imageData, 0, 0); const time msg.duration ? 耗時(shí) ${msg.duration.toFixed(2)}ms : ; statusText.textContent 處理完成由 Worker 執(zhí)行${time}; } }; worker.postMessage({ type: init }); } fileInput.addEventListener(change, (e) { const file e.target.files[0]; if (!file) return; const img new Image(); const objectUrl URL.createObjectURL(file); img.onload () { const width Math.min(img.width, 640); const height Math.min(img.height, 480); sourceCanvas.width width; sourceCanvas.height height; outputCanvas.width width; outputCanvas.height height; const ctx sourceCanvas.getContext(2d); ctx.drawImage(img, 0, 0, width, height); originalImageData ctx.getImageData(0, 0, width, height); const outputCtx outputCanvas.getContext(2d); outputCtx.putImageData(originalImageData, 0, 0); URL.revokeObjectURL(objectUrl); statusText.textContent 圖片尺寸${width} × ${height}; }; img.src objectUrl; }); function processWithWorker(type) { if (!originalImageData || !worker) return; const width originalImageData.width; const height originalImageData.height; const imageDataBuffer originalImageData.data.buffer; worker.postMessage({ type: process, width, height, imageDataBuffer, operation: type }, [imageDataBuffer]); statusText.textContent 正在處理中頁(yè)面不會(huì)卡頓...; } document.getElementById(grayscaleBtn).addEventListener(click, () processWithWorker(grayscale)); document.getElementById(blurBtn).addEventListener(click, () processWithWorker(blur)); initWorker();改造之后即使處理超大圖片主線程也不會(huì)被阻塞用戶可以繼續(xù)滾動(dòng)頁(yè)面、點(diǎn)擊按鈕動(dòng)畫(huà)也能保持流暢。6.4 還可以繼續(xù)優(yōu)化內(nèi)存復(fù)用與批量處理上面的 Worker 版本已經(jīng)能解決大部分卡頓問(wèn)題但工程上還可以繼續(xù)優(yōu)化內(nèi)存池每次處理都allocBuffer和freeBuffer在頻繁處理時(shí)是不必要的開(kāi)銷??梢栽?Worker 初始化時(shí)申請(qǐng)一塊固定大小的內(nèi)存后續(xù)處理復(fù)用。避免 repeated 全量拷貝如果圖片尺寸固定可以只更新變化的部分?jǐn)?shù)據(jù)而不是每次都整體拷貝。批量濾鏡如果用戶點(diǎn)擊了“灰度模糊”不要分兩次遍歷像素盡量在一個(gè)循環(huán)里完成多個(gè)操作減少內(nèi)存訪問(wèn)次數(shù)。simd 指令Emscripten 支持 SIMD在支持的瀏覽器里可以大幅提升卷積計(jì)算速度不過(guò)需要檢測(cè)運(yùn)行環(huán)境。6.5 OffscreenCanvas 的進(jìn)階用法如果想把putImageData也移出主線程我們需要在 Worker 中創(chuàng)建OffscreenCanvas。主線程先創(chuàng)建出一個(gè)OffscreenCanvas把它轉(zhuǎn)會(huì)給 WorkerWorker 直接在這個(gè) Canvas 上繪制。主線程側(cè)const offscreen outputCanvas.transferControlToOffscreen(); worker.postMessage({ type: init, canvas: offscreen }, [offscreen]);Worker 側(cè)let offscreenCanvas null; let offscreenCtx null; self.onmessage (event) { const { type, canvas } event.data; if (type init canvas) { offscreenCanvas canvas; offscreenCtx offscreenCanvas.getContext(2d); } // ... };處理完成后直接在 Worker 里offscreenCtx.putImageData(imageData, 0, 0);這樣主線程連渲染工作都省了真正實(shí)現(xiàn)了全鏈路的非阻塞處理。不過(guò)需要注意的是transferControlToOffscreen之后主線程上原來(lái)的outputCanvas就不能再直接操作了否則會(huì)拋異常。這一點(diǎn)在項(xiàng)目里需要特別小心。7. 常見(jiàn)問(wèn)題與排查思路7.1 WASM 模塊加載失敗問(wèn)題現(xiàn)象常見(jiàn)原因解決思路fetch 404wasm 文件路徑不對(duì)檢查fetch路徑和文件是否在靜態(tài)目錄下WebAssembly.instantiate 報(bào)錯(cuò)wasm 文件損壞或初始化參數(shù)不對(duì)檢查編譯命令確認(rèn)沒(méi)有遺漏導(dǎo)入對(duì)象跨域報(bào)錯(cuò)靜態(tài)服務(wù)器沒(méi)有配置正確的 MIME 類型使用本地靜態(tài)服務(wù)器而不是直接file://打開(kāi)7.2 編譯后的 C 函數(shù)在 JS 中調(diào)用不到Emscripten 導(dǎo)出函數(shù)名默認(rèn)帶下劃線但在EXPORTED_FUNCTIONS里寫(xiě)的是帶下劃線的名字。調(diào)用時(shí)用wasmModule._grayscale才是對(duì)的但實(shí)際我們?cè)诖a里寫(xiě)的是wasmModule.grayscale。這里要取決于你導(dǎo)出的是運(yùn)行時(shí)方法還是直接實(shí)例導(dǎo)出的函數(shù)。如果直接用WebAssembly.instantiate導(dǎo)出函數(shù)名就是 C 函數(shù)名不帶下劃線。如果通過(guò) Emscripten 的Module對(duì)象訪問(wèn)則需要使用Module._grayscale。這一點(diǎn)最容易踩坑。7.3 Worker 傳輸大數(shù)組時(shí)內(nèi)存占用過(guò)高postMessage傳輸大數(shù)據(jù)時(shí)如果不用轉(zhuǎn)移列表會(huì)觸發(fā)結(jié)構(gòu)化克隆相當(dāng)于復(fù)制一份數(shù)據(jù)內(nèi)存瞬間翻倍。大圖片場(chǎng)景下很容易導(dǎo)致內(nèi)存溢出。解決方案就是在上面的代碼里使用轉(zhuǎn)移列表postMessage(message, [buffer])把ArrayBuffer轉(zhuǎn)給接收方。但需要注意轉(zhuǎn)移之后發(fā)送方的 buffer 會(huì)變成 detached 狀態(tài)不能再訪問(wèn)。7.4 低端機(jī)上處理速度還是很慢如果已經(jīng)用了 Worker主線程不卡了但處理結(jié)果依然很慢這時(shí)候瓶頸主要集中在WASM 算法本身的復(fù)雜度。數(shù)據(jù)拷貝次數(shù)。圖片尺寸過(guò)大。瀏覽器對(duì) ArrayBuffer 傳輸?shù)膬?yōu)化程度。優(yōu)先做幾件事調(diào)整圖片尺寸比如處理前先壓縮到最大 1280px 寬。去掉不必要的拷貝直接操作 WASM 堆內(nèi)存。用 SIMD 優(yōu)化卷積計(jì)算??紤]把圖片分塊處理在 Worker 中并行處理多個(gè)塊。7.5 Canvas 在 Worker 中報(bào)錯(cuò)低版本瀏覽器對(duì) OffscreenCanvas 支持不完整使用前要做特性檢測(cè)if (typeof OffscreenCanvas ! undefined) { // 使用 OffscreenCanvas } else { // 直接在主線程渲染或者降級(jí)處理 }8. 最佳實(shí)踐到底什么時(shí)候該用 WebAssembly8.1 適合用 WASM 的場(chǎng)景從一個(gè)工程視角來(lái)看以下場(chǎng)景可以考慮 WebAssembly核心算法是計(jì)算密集型而且循環(huán)次數(shù)非常多比如圖像處理、音視頻編解碼、3D 數(shù)學(xué)運(yùn)算。需要復(fù)用 C/C/Rust 生態(tài)中的成熟庫(kù)比如 OpenCVWebAssembly 版、FFmpeg、libjpeg 等。對(duì)性能有明確指標(biāo)要求而且純 JavaScript 確實(shí)達(dá)不到。需要在瀏覽器端做離線處理不依賴后端服務(wù)。8.2 不適合用 WASM 的場(chǎng)景以下場(chǎng)景引入 WASM 可能是過(guò)度設(shè)計(jì)只是簡(jiǎn)單遍歷幾十個(gè)數(shù)據(jù)點(diǎn)JS 和 WASM 的差異可以忽略。項(xiàng)目里沒(méi)有 C/C/Rust 基礎(chǔ)純粹為了“性能”強(qiáng)行引入維護(hù)成本反而更高。需要頻繁和 DOM、Canvas 交互而且每次都重復(fù)轉(zhuǎn)移大量數(shù)據(jù)性能收益會(huì)被通信開(kāi)銷抵消。團(tuán)隊(duì)對(duì) WASM 不熟悉沒(méi)有完整的構(gòu)建鏈路和排錯(cuò)經(jīng)驗(yàn)。8.3 工程上的性能優(yōu)化順序一個(gè)高性能的前端圖像處理方案優(yōu)化優(yōu)先級(jí)應(yīng)該是先把計(jì)算移出主線程使用 Web Worker。能不用getImageData就不用盡量用drawImage配合 CSS filter 或 Canvas 原生濾鏡。如果必須逐像素處理再考慮 WASM。如果 WASM 計(jì)算還有瓶頸再考慮 SIMD、Worker 多線程、分塊計(jì)算。最后才是復(fù)雜的渲染鏈路優(yōu)化比如 OffscreenCanvas、GPU 加速等。這個(gè)順序不建議跳過(guò)。很多項(xiàng)目一開(kāi)始就上 WASM結(jié)果發(fā)現(xiàn)主線程還是卡原因就是第一步都沒(méi)做。8.4 性能評(píng)估方法在上線前不要只看開(kāi)發(fā)機(jī)的表現(xiàn)。建議做一個(gè)簡(jiǎn)單的評(píng)估清單在低端 Android 手機(jī)模擬器上測(cè)試。用performance.now()分別統(tǒng)計(jì)主線程和 Worker 中的耗時(shí)。使用 Chrome DevTools 的 Performance 面板檢查主線程占用時(shí)間。觀察getImageData、putImageData、postMessage各自耗時(shí)多少。在弱網(wǎng)環(huán)境下評(píng)估 WASM 文件加載對(duì)首屏的影響必要時(shí)延遲加載。8.5 關(guān)于內(nèi)存與安全WASM 雖然運(yùn)行在瀏覽器沙箱里但使用不當(dāng)也可能帶來(lái)問(wèn)題申請(qǐng)的內(nèi)存需要手動(dòng)釋放否則會(huì)造成內(nèi)存泄漏。傳入 WASM 的指針值要嚴(yán)格校驗(yàn)避免越界訪問(wèn)否則可能崩潰。不要把用戶輸入的圖片數(shù)據(jù)直接傳給不受信任的 WASM 模塊要考慮惡意構(gòu)造數(shù)據(jù)的情況。生產(chǎn)環(huán)境中建議在 Worker 中封裝完整的內(nèi)存生命周期不要暴露給主線程隨意操作。9. 總結(jié)性能優(yōu)化從來(lái)不是“換個(gè)名字就行”回到最初的標(biāo)題用 WebAssembly 給前端圖像處理加速結(jié)果低端機(jī)上該卡還是卡主線程居然還在等。這句話其實(shí)暴露了一個(gè)很普遍的心態(tài)大家都想找一個(gè)“銀彈”找到一個(gè)工具、一種技術(shù)就能讓性能問(wèn)題自動(dòng)消失。但實(shí)際上前端性能優(yōu)化是一個(gè)系統(tǒng)性問(wèn)題它需要你畫(huà)出整條鏈路的耗時(shí)分布找到真正的瓶頸再針對(duì)性優(yōu)化。WebAssembly 是非常好用的工具但它只解決了“計(jì)算密集”這一個(gè)環(huán)節(jié)。如果你的主線程依然被渲染、解碼、拷貝這些事占住WASM 再快也無(wú)濟(jì)于事。真正能落地的組合方案是用 Web Worker 把計(jì)算和主線程隔離。用 OffscreenCanvas 把渲染也移出主線程。用 WASM 提升核心算法的計(jì)算效率。用內(nèi)存復(fù)用、SIMD、分塊計(jì)算進(jìn)一步壓榨性能。低端機(jī)會(huì)卡不是某一個(gè)環(huán)節(jié)出了問(wèn)題而是所有環(huán)節(jié)被擠在主線程上排隊(duì)執(zhí)行的結(jié)果。把排隊(duì)變成并行把大任務(wù)拆成小任務(wù)才能讓低端機(jī)也“不卡”。希望這篇文章能幫助你少走一些彎路。如果你也在實(shí)際項(xiàng)目里碰到過(guò)類似的性能優(yōu)化問(wèn)題或者有更好的方案歡迎在評(píng)論區(qū)交流。代碼里的方案可以直接復(fù)制去跑調(diào)試過(guò)程中如果遇到報(bào)錯(cuò)也可以對(duì)照“常見(jiàn)問(wèn)題”一節(jié)逐條排查。
返回列表
PREV
查看更多資訊
NEXT
返回資訊列表
黄色小视频日本txt| 日本精品无码三级网站| 久久欧美性爱视频| 熟女久久久| 伊人激情五月天一区二区| 国产午夜视频| 日韩高清黄片| 欧美中字二区| 亚洲天堂一区二区久久| 日本欧美色| 8x福利精品第一福利视频导航| 欧美男女午夜啪啪| 欧美黄页| 青青草久久一区网| 国产精品爱欲| 青青草国产一区二区三区| 欧美日韩另类在线播放| 另类成人首页一区| www.色99| 舔足天天操天天射| 18精品一区| 国产内射爽爽大片| 97激情97激情| 国产高清26uuu| 少妇高潮喷水无套久久久久久| 家庭乱伦国产| 嗯嗯啊啊好大好爽| 伊人色综合网电影| 91色插| 婷婷99狠狠| 天天拍夜夜| 蜜桃久久综合视频| 韩三级a视频在线观看| 精品乱子一区二区三区99| 国产精品人妻一区二区| 91网站视频在线观看| 自怕偷自怕亚洲精品| 日韩欧美资源| 五月天色色网站| 91岛国动作片| 日日夜夜噜| 人人操人人uiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii | 国产激情av女片自拍| 四虎在线免费视频| AV中文在线| 欧美色女人| 久视频在线观看| 国产乱伦性爱区| 日韩综合97P| 激情AV| 婷婷色色五月天福利| 97久久精品国产| 欧美色性爱| 人妻铁牛TV| 一级黄碟在线观看| 国产成人自拍视频在线| 91在线超高颜值国产| 久久中文字幕女同性恋一区| 操人妻少妇中文| 三级色综合| 91精品丝袜久久久久久| 成人精品视频一区二区| 天天做日日爱夜夜爽| 欧美超碰97| 中文字幕诱惑制服人妻丝袜美丝袜美 | 久久这里精品国产99丫e6| 天天做日日做| 亚洲资源站| 天天综合网~91入口| 超碰AV在线| 人人人摸人人| 国产精品片| 日韩 欧美 国产 麻豆| 操碰97| 欧美性生活免费网| 日韩电影在线观看网址| 欧美性爱超碰97| 日韩午夜国产| 啪啪视频mP4| 围产精品一区二区三区视频播放| 超碰午夜| 大二网站亚洲| 伊人麻豆传媒| 欧美亚洲天天| 91艹| 亚洲熟女一区| 97综合国产精品高潮久久| 性爱av在线免费观看| 日本中文字幕不卡视频| 亚洲综合首页| 中文字幕一区二区三区人妻不卡 | 天天在线91| 熟女一区二区| 亚洲天堂男人在线| 超碰九色| 99自拍视频在线| 思思热久久成人| 欧美片第一页| 探花精品 一区二区| 精品久操| 啊啊啊操死我了| 九九国产热| 超碰久久性爱| 女优免费一区二区永久| 国产剧情一区在线观看| 天天操综合网| 欧美日韩国产在线| 高清无码网址| 天天干少妇| 一区二区三区激情在线观看| 强奸乱亚洲| 欧美精品1区2区3区| 色伊人91| 精品在线观看视频在线| 中文字幕一区二区韩| 免费观看国产小粉嫩喷水精品午| 五月丁香六月综合缴清无码| 日韩免费簧片| 操我无码| 日日碰狠狠添天天爽超| 欧美日韩岛国大片在线观看| 很很热性爱视频| 成人八戒网站| 人人干人人搞人人摸| 国产操逼逼网| 黄色高清无码无码破解免费暗网| 蜜乳AV色欲AVAV无码| 国产精品视频白浆免费| 床上啊啊啊一区二区三区| 中文字幕一区二区三区视频播放| 99热在线播放| 混色激情av| 97蜜桃综合| 大香蕉伊人一区在线观看| 丝袜内射| 亚洲在高跟鞋自慰久久在色线| 97超碰亚洲| 青青操在线亚洲视频观看欧美在线 | 日本一区二区不卡| 亚洲另类欧美精品| 一区操逼日比视频| 国产精品久久久久久久久AV大片| 久久久九九网站| 香蕉久久国产AV一区二区| 九色PORNY9l原创自拍| 午夜精品一区二区三区三上悠亚| 人妻碰碰碰碰碰碰| 亚洲大色堂| 91视频综合在线| 亚洲天堂久久| 人人搞人人插人人操| 亚洲人体视频在线观看| 免费亚洲黄色视频在线观看| 手机看片1025| 97内射偷拍| 欧美精品久久| 久热一区二区| 性爱免费视频成人| 五月婷婷激情| 国产精品欧美激在线| 91国内外在线| 蜜桃久久一区二区| 欧美日韩另类在线播放| 岛国黄色大片网站| 99.色网| 亚洲综合图片在线| 91美女片在线| 五十路六十路素人熟女| 综合熟女| 啊灬快c我灬啊灬用力灬啊灬-国产精品性做久久久久久-成人AV | 国产一区二区三区导航| 少妇被玩视频二三区| 日韩精品人妻中文字有码在线| 骚熟女AV网| 亚洲中文字幕在现观看| 丁香九月激情| 少妇蹲下买菜露大唇0| 国产97视频| 亚洲蜜乳av| 日韩AV片| 偷拍亚洲视频一区二区三区四区| 中日韩免费看男女操逼大全| 国产呦精品一区二区三区下载| 超碰人人乐97| 另类老少妇| 天天澡天天爽日日AV| 欧美极品性爱天天射| 男人夜色天堂ss| 欧美最大综合网| 99色网| 国语av最新自产拍在线观看| 亚洲 欧美 小说| 久久久久久久久久9| 91在线视频观看国产| 又黄又爽在线观看视频| 果冻传媒一区二区三区| 成人性爱AV在线免费观看| 色色五月婷| 好看的久久不射无码影视影院| 久九九九| 综合色啪| 国产精品在线一区二区| 久久久精品电影| 丝袜 亚洲 偷拍| 国产人妻精品一区二区三区秋霞| 中国操逼无码| 色婷婷成人综合| 久久久久国色αv免费观看| 日韩丰满熟妇| 97操在线| 免费看国产曰批40分钟怎么下载| 91亚州欧美| 九九综合九九综合| 九九十八精品| 久久精品国产欧美日韩亚洲欧美日韩中文久久国产一区 | 天天综合网日韩| 亚洲第一在线视频| 4tube欧美女厕所| 国产日韩欧美三级片| 四虎在线免费视频| 日韩不卡av一二三| 中文字幕av一区二区三区人妻少妇| 性久久| 综合网~91综合网| 黄色成人网久久久久久| 福利偷拍视频-中文字幕2019国语完整视频大全-S91AV | 亚洲男人的天堂va亚洲男人社| 牛黄色久午久| 欧美黑人熟妇精品91| 婷婷丁香五月激情啪啪| 男人的天堂VA| 91肉片| 大香蕉99re| 国产1769在线| 国产精品。| 天堂69亚洲精品中文字| 4141514逼喷水三级片| 人人摸人人入| 怡春苑东京热| 女人 A一级| 蜜桃狠狠色伊人亚洲综合 | 色偷偷综合91久久噜噜| 国产小u女在线观看| 丰满欧美放荡少妇在线| 久热超碰| 青草草免费网站av| 亚洲啪啪啪啪视香蕉| 亚洲操逼无码| 人人操人人色网| 91女人的网站| 91人妻尻屄视频| 亚洲欧美综合图片| 人妻天天爽夜夜爽精品2| 岛国1区2区3区在线观看| 狠狠操一区二区| 中日韩久久久| 国产成人精品网站| 欧美情色贴图| 亚洲,欧美,春色,另类| 熟妇综合一区二区三区| 99蜜桃臀亚洲成人在线观看| av天堂5| 91欧美经典| 后入 亚洲 美女 射| 亚洲黄色视频在线观看视频| 国产情色在线| 中文字幕艹艹| 欧美日本一区二区a人| 婷婷性网| 亚洲精品天天影视综合网 | 欧美一区二区亚洲天堂| 日本欧美中文字幕| 日日夜夜模| 六月色婷婷| 香伊人在线| 天天综合站| 人人操天天爽| 99热色精品| 精品国产91内射久久| 97av,com| 啪啪AV导航| 日韩无码人妻中字久久三区四区| 免费的av网| 亚一综合久久久久久久久久| 97香蕉网| 后入式福利| 67194无码不卡| 中文字幕免费看大片| 小说区 图片区色 综合区| 国产99999久久精品| 综合网,亚洲,欧美| 韩日无码在线观看| 欧美福利视频啊啊啊啊| 大逼色网站| 久久久穴999| 超碰成人免费| 日本Xx性爱| 日韩性爱一级片| 伊人性在线视频| 91夜夜蜜桃臀1区2区3区| 大香蕉久久| 加勒比久久综合网高清| 一级片视频啪啪| 色色九区| 美女爽到高潮91| 九九九九九九成人| 岛国小电影| 国产激情久久久| 国产精品无套内谢| 黄色一区二区秘书性感| 中文字幕日韩专区精品系列 | 美女t无毒不卡不卡| 超碰天天操| 偷拍 精品 另类 四区| 偷窥自拍A片| 性爱Av免费| 日本一级真人黄色性爱视频| 欧美天天射| 中文有码9| 97草草| 亚洲男人的天堂网| 日韩啪啪啪视频| 久久久久久久久久久人妻| 人妻AV在线| 操美女高潮抽搐白浆| 亚洲人妻在线一区| 欧美激情性爱视频网站| 国产9 9在线 | 亚洲| yiqicaoav| 97中文字幕九区| 日韩成人小视频| 极品AV网站在线观看| 1204金沙人妻懂旧版免费| 久久这里精品国产99丫e6| 99这里只有精品| www.色婷婷.com| 六月丁丁香| 亚洲中文字幕av| 偷看洗澡一二三区美女| 久操婷婷| 婷婷激情啪啪| 97操97色| 人妻天天爽夜夜爽精品2| 男人下部插入女人下部| 亚洲中文字幕乱码无码一区二区| 大香蕉在线86| 久久99精品国产| 亚州日韩97| 男女香蕉一区二区| 久九九九九九九九热| 南澳成人一级片在线播放| 东京热av影院| 偷拍精品一区二区三区| 国产精品福利资源在线尤物| 99这里只有精品国产| 亚洲国产精品有声| 国产福利精品最新在线 | 成人在线视频网| 丁香五月自拍| 97蜜桃综合| 中文字日本乱码| 操死我了嗯嗯嗯| 亚洲色图 图片| 久久九九精品一区二区| 夜夜爽夜夜操| 超碰无码加勒比| 久久精品中文字幕无码l| 亚洲欧美日韩夜夜| ′ !γ}丶。。久久精品欧美一区二区三区| 一本道综合色图| 嗯嗯啊啊亚欧精品| 九九九精品色乱九九九| 97视频免费播放| 亚洲人妻中文在线视频| 人人操人人uiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii | 午夜寂寞欧美| 国产刺激视频| 久久综合女优| 99草精| 思思热国产高清| 无码最新| 婷婷五月天_亚洲小说欧美激情另类_精品久久国产字幕 | 激情 欧美 亚洲 小说| 97人妻免费中文字幕| 久久久久婷婷| 加勒比日本在线| 干美女人妻| 免费AV中文网在线观看| 亚洲蜜桃V妇女| 狼天天狼天天大香蕉| 嗯嗯啊好大| 亚洲一区二区av| 天天插夜夜操| 久久久久无码| 少妇熟女视频一区二区三区| 国产黄色视频久久| 色噜噜狠狠色综无码久久合欧美| 97日视频| 97日韩欧美| 国岛片视频| 久久久9品一区二区三区| 国产精品一级二级在线| 岛国福利在线精品播放| 九九色热| 亚洲精品不卡一二三区| 伊人热综合| 91性高潮久久久久久久久| 啊灬快c我灬啊灬用力灬啊灬-国产精品性做久久久久久-成人AV | 久久人人爽爽人人爽人人片αV| 色丁香五月婷婷| 99久热精品99re6热| 97色综合中文网| 色成人Www精品永久观看| 九九热精品免费视频| 蜜臀在线网站| 日本熟女中文字幕一区| ss久久| 久久久555| 破苞ⅩXXX性无码动漫无码| 青春草A| 久久9久| AV中文在线| 国产熟女高潮一区二区三区| 日韩国产不卡在线视频| 日韩精品人妻系列无码天堂| 老熟女网站| 亚洲天堂热| 狠狠爱夜夜干| 國產尤物AV尤物在線觀看| 欧美一区二区传媒| 欧美亚洲自拍另类人妻| 67914亚洲精品| 91无码人妻精品一区二区三区蜜桃 | 日韩中文字幕熟妇人妻| 丝袜性亚洲| 人妻丝袜一区二区三区在线| 深爱五月婷婷| 欧美亚洲天天| 国产 码在线成人网站| 一本大道久| 黄aaaaaaaaaaaaaaaaaa色网站| 欧美色日| 自拍大香蕉乱插| 亚洲 欧美 综合 91| 搞中出久久| 婷婷色网| 天天日天天搞天天干| 麻豆性爱视频在线播放| 在线有码中文字幕| 欧美国产有色电影| 国产精品宅男免费| 夜夜国自区| 亚洲精品日韩国产欧美| 日本一二三免费久久| 99操逼| 伊人九九| 中文字幕av色| 一区二区三区美女超清| 欧美第38页| 家庭乱伦国产精品| 媚薬在线视频麻豆| 午夜影美女日鸡鸡天天视频国产| 久久亚洲天堂| 中文字幕 国产区| 国产精品乱码久久久久久久久| 日本精品成人无码| 人妻精品一区二区| 亚州色站 日韩电影| 无码 黑人一区二区三区| 校园春色亚洲无码| 成人性爱电影网| 欧美黑人极品高潮喷吹熟女黑人性暴力日韩在线欧美极品一区 | 曰韩操B| 国产女人9999| 天天综合中文字幕 91| 91亚洲精品青草| 国产乱伦性爱区| 少好三P| 色99视频| 国产狂喷潮在线精品| 国产精品久久久九九九| 91精品久久久久久77777| 偷拍盗拍亚洲色图图片| 亚州色图欧美| 99久热| 欧美性爱综合,免费| 国产久久一区二区| 五月天色五月| 91人妻最真实刺激绿帽| 97在线播放| 91青视频| 欧美精品自慰系列寂寞少妇| 大JI巴好深好爽又大又粗视频| 99亚洲人人| 亚洲高清无码免费观看视频| 啪啪性爱免费视频| 亚洲骚男同com| 久久久噜噜噜久久久| 国产精品爽爽v| 怡春院久久| 亚洲激情色片 | 四虎884a| 中日高清无码操逼视频| 日韩无码视频黄色| 国产国产亚洲一二三久久| 日本不卡高清免v欧美日韩在线观看| 91人妻做a观看视频| 欧美色图91| 久久99草| 综合久草| 九九激情网| 久操凹凸视频| 男女啪啪啪18禁网站| 亚欧操逼片在线观看 | 曰韩成人免费视频| 日日操免费视频| 日本三级精品| 激情人妻另类| 亚洲 图片 欧美 色图| 亚洲色诱惑| 欧美日韩色综合网| 又粗又长又大国产不卡| 精品在线78| 天天草AV| 欧美猛交黑寡妇中文字幕| 性欧美另类高清| 亚洲天堂 视频你懂的| 日韩美女啪啪一区| 国产91精品在线免费| 免费视频观看60秒| 99热99re6国产在线播放| 日日干夜夜操视频h| 中文字幕一区av| 欧洲熟妇xxXx欧美老妇裸体 | 亚洲性少妇| 操b网站亚洲无码| 精品少妇后入一区二区三区四区人妻巨乳 | 欧美91精彩| 久久综合久久综合人久久夜精品| 亚洲色五月| 免费人成?大片在线播放| 中文字幕国产| 国产亚洲精品精AV.| 97超碰站| 九九九九国产| 69精品| 9丨久久九九九| 欧美自拍网| 新91视频.cmp| 夜夜久久久| 综合亚洲网| 欧美少妇高潮| 日韩成人小视频| 中日韩久久久免费看| 熟女久久久| 51一区二区三区| 91精品操美女| 熟人人妻少妇精品久久| 久久久啊啊啊| 老熟女91视频| 久久亚洲AV无码白度| 婷婷爽人人婷婷爽视频| 色香欲影| 在线免费观看高清无码视频| 久久久久亚洲熟妇熟女| 国产亚洲日韩欧| 超碰无码加勒比| 人人操人人插人www| 日韩亚洲中文字幕在线| 国产懂色精品国产av| 亚洲偷拍自拍在线视频| 色墦五月丁香| 爆乳免费黄网站| 亚洲情色一区综合| 91激情网| 亚洲国产福利视频| 日本韩国五十路六十路七十路老熟女作爱视频网站 | 九九九九9999| 蜜乳中文字幕a在线| 欧美性生活男人的天堂| 免费一级黄色录像影片| AV无码久久久精品| 九九色色| 婷婷色香| 久久久精品一区二区| 精品无人区麻豆乱码1区2区图片| 日日躁夜夜躁狠狠躁超爽| 久久久夜夜夜| 天天射天天| 成人网站 免费观看| 激情五月丁香五月| 一区二区三区网站日日骚| 久婷婷一区| 综合大香蕉美。| 大香蕉狠狠爱| 三级精品三级在线观看| 屁屁影院一区二区三区国产 | 国产AV线| 精品一区二区三区免费古装毛片香港三级日本三级人妇 | 日韩黄片视频试看| 中文字幕在线高清男人的天堂 | 熟女精品va中文字幕| 99爱在线视频| 男人久久精品| 高清视频一区| 一本精品日本在线视频精品| 色婷婷基地| 国产污视频麻豆传媒一区二区| 久久人妻无码毛片A片麻豆| BBBBB97COM| 欧美日产国产在线成人第一区| 乱伦熟女区| 亚洲日韩青青草色月| 青青草五月份天| 99久久久久久亚洲精品不卡| 乱老女人一区二区视频| 欧美操逼视频二区| 四虎影视欧美| 黄在线| GVH-003 母子姦 青木玲-麻豆视频,麻豆视传媒短视频网站入口,麻豆视传媒官网直 | 亚州国产成人精品女人久久| 麻豆精品一区二区三区四区免费观看| 99久久婷婷丁香| 野狼激情网| 欧美黑人日韩少妇色情| 国产真乱mangent| 久久久五月天| 狠狠爱夜夜干| 91丨九色丨国产丨人妻在线| 午夜免费视频1000| 中文字幕精品三级久久久| 人妻精品免费一二三区| 色99色| 国产日产欧产美韩系列麻豆免费| 亚洲成人黄色在线观看| 熟妇人妻精品一区二区视频色欲| 校园春色欧美| av强奸乱轮| av在线人气| 国产AV中文| 国产成人自拍视频在线| 亚洲网污污污污| 亚洲欧洲无码bt精品合集| 999在线电影香蕉| 97精品人妻一二三四| 在线岛| 红桃视频高潮| 亚洲欧美综合| 国产成人亚洲精品自产在线| 欧美色91| 亚洲欧美国产日本一区二区三区| 2017天天透天天通天天擦| 成人性爱av| 91色综合激情| 中文字幕av亚洲精品| 久久久98网站免费视频| 欧洲人妻视频| 在线只有精品| 国色综合天| 五月婷婷色色| 东京热91| 亚洲色久| 国产精品久久泡妞网站| 精品色色| 久久系列| 丰满人妻一区二区三区四| 国产剧情在线| 亚洲情色五月天 | 中文字幕视频在线观看一区二区| 日本综合色图| 熟女啪啪视频| 欧亚无码视频| 二对二中文字幕。| 久久青青草原免费视频| 性爱AV天堂| 精品一区二区成人| 久久久久久久久久久久久女过产乱-少妇高潮一区二区三区喷水-成人AV | 97aiaiai| 91麻豆天美国产| 夜夜操美女| 久日91在线| 岛国视频免费在线观看| 死我十八禁| 亚洲高清无码免费观看视频| 天美传媒麻豆一区二区三区国产精| 中文字幕日本久久| 狼人狠干| 色一射色一射| 少妇啪啪自拍| 亚洲91射| 欧美久久九九| 日韩免费高清大片在线| 欧美91网站| 成人日本视频人妻在线| 日韩十八禁| 精品无码一区二区| 日本狂喷奶水在线播放212| 中国的操老妇女| 超碰人人色| 蜜臀久久99精品久久久久久-DVD原版全| 人人妻人人操人人乐| 中文字幕黄片在线| 超碰到97情色| 国产在线76页| 飘花国产午夜精品不卡| 美女上床网站| 久久久一热在线播放| 国产成人精品必看| 97人人色| 青青草在线视频人人想人人上 | 国产99久久99热这里只有精品15 | 欧美成人A√在线一区二区| 超碰久久精品| 97资源制服丝袜| 天天干天天燥| 97资源站日韩| 啊啊啊不要啊啊受不了了视频在线 | 麻豆福利视频导航| 国产精品视频精品一二| 国产高清自拍视频| 福利大香蕉| 香蕉99秘 精品一区丁香| 26uuu性| 麻豆亚洲AV成人无码久久精品| 欧美少妇内射| 色区久久| AV和黑人在线播放| 国产精品视频在线观看| 97视频在线免费播放| 国产精品交换一区二区| 可以在线观看的黄色网址| 超碰97综合在线| 欧美伦乱爱| 日本有码久久| 中文字幕亚韩| 日本熟女不卡视频| 久久嫩草| 啊啊啊啊啊舒服| 9超碰免费| 欧美一级三级| 亚洲色图亚洲无码强奸乱伦| 性色av大全| 久久一区二区蜜桃| 玖玖爱伊人玖玖爱| 久久精品72| 黄色AV影视| 天天操天天舔| 国产99精品一区二区三区免费| 玖玖久久久| 成人夜夜| 一区二区三区色综合| 蜜伊人色综合97| 五月天激情网图片| 日本道久久综合色色| 6080YYY午夜理论片在线观看| 天天亚洲| 日韩精品午夜操呦呦不卡影院| 98超碰日本| 欧美精品偷拍| 歐美一級亂黃99在綫精品| 人妻丝袜无 码视频专区| 户外裸露刺激视频第一区| 久久久一区二区三区三州| 欧美一级在线观看成人| 91观看 国产白丝| 久草毛片| 超碰在线综合97| 天天激色| 九九九影院| 天天日天天舔东京热| 色一射色一射| 国产馆极品诱惑| 久久黄黄| 精品四五区| 精品夜夜澡人妻无码| 日本天天操| 国产亚洲在线观看| 欧美日韩99| 日本污ww视频网站| 日韩不卡av一二三| 性做久久久久久免费观看软件| 久久成人国产| 青娱乐久久艹| 99热只有这里有精品| 国产午夜无码片在线观看影视 | 啊啊好多水| 夜夜狠狠躁日日躁色视频| 欧洲乱码视频| 干B| 亚洲色图伊人网| 岛国不卡超碰护士AV在线播放| 青草视频人妻在线观看| 91欧美综合在线| 超碰到97情色| 蜜臀99久久精品| 综合亚州欧美| 欧美激情精品| 东北毛片| 韩国手机不卡无码三级视频| 久久精品国产99精品亚洲蜜...| 69少妇一区二区| 正在播放国产精品一区| 国产精品69人妻无码久久久| 亚乱色| av资源在线播放天堂| 激情AV| 好淫网一二三视区| 美女97超碰| 熟妇高潮精品一区二区三区下载| 超碰伊人在线| 天天欲望网| 玖草在线视频| 国产黄色影片在线观看| 黄片免费看黄片免费看| 色婷婷激情| 偷拍亚洲高清图片| 色男人色天堂东京热| 美女上床网站| 97碰| 亚洲国产成人福利在线观看| 国产懂色精品国产av| 天天射影院| 久久伊人网视频一区二区三区| 日韩无码AB| 天天躁日日躁狠狠狠躁| 2024年最新色情网站在线观看 | 丁香六月综合激情| 热天堂一区二区| 99热这里只有是精品10| 91久久国产综合精品| 日本色色视频网站| 久久精品中文| 超碰97玖玖爱| 色女综合| 有码免费观看| 色诱中文字幕| 男人的天堂色偷偷青青草视频婷婷网| 青娱乐 成人娱乐在线| 激情综合久久| 超碰九色| 最新中文字幕在线亚洲| 97国产高清视频在线观看| 超碰 欧美| 中文字幕亚洲欧美在线不卡| 殴美综合色88| 美女性91| 精品人妻无码一区二区三区不卡-精品人妻无码一区二区...|精品少妇一区二区三 | 97人人中文网| 亚洲无992tv| 激情第四色| 天堂亚洲精品久久老牛| 尹人免费观看视频在线| 91丝袜美女国产| 97这里都是精品| 日本潮催一卡操| 国产av尤物| 亚洲欧美校园| 国产精品91ai| 三级片大波波| 亚洲91射| 日本性交操一区二区不卡系列| 欧美成人黄网色网站| 日韩丝袜人妻AV| 噜噜噜噜天天狠狠| 超碰国产精品无码| 久久久久久午夜男人的天堂| 自拍亚洲综合| 国产精品成久久久久午夜午夜| 免费综合亚洲中文| 亚洲在高跟鞋自慰久久在色线| 国产精品久久久久久久久久久久久久吹 | 性爱乱伦视频免费| 欧美黄页在线| 亚洲精品久久久久久久蜜桃臀| 99re6国产精品99re在线| 97天天插| 亚洲三区视频| 欧美专利1区2区3区4区5区免费| 青青草AV色| 天天综合网日韩7799| 精品久久久久瑟瑟| 啊啊啊啊操死我| 人人做人人妻人人夜视频| 一级黄碟在线观看| 亚洲一区二区在线观看91| 日韩在线观看中文字幕视频| 亚洲成人妻日韩在线| 偷拍偷窥与盗摄视频专区| 色婷婷五月天| 亚洲天天自拍| 深田咏美亚洲精品福利社| 91激情综合| 一区不卡在线观看av| 国产精品久久发布| 屁股久久久久久久久久| 成人看片网站| 香蕉精品二区二区| 色婷久久| 青青草在线视频播放器| 日本亚洲熟女视频| 超碰9 7女人 | 丁香六月婷婷久久综合| 91无码人妻精品一区二区三区蜜桃| 日本天天操| 亚洲综合贴图91 | 天天操人人操骚逼网站| 吖在线不卡一区二区国产剧情| av操操不卡| 国产精品又黄又猛又粗| 国产自产91区13区| 日本韩高清无砖码22o| 精品久久久av| 欧美性爽xyxOOOO| 四虎AV无码| 日本爽爽爽爽爽爽免费视频| 78p欧美| 日韩操p| 色 亚洲 91| 无码高清国产AV| 久久久久久少妇| 久久性爱大全| 殴美色网| 男人的天堂亚洲| 97色碰| 日欧美色| 性爱视频无打码在线观看| 情色五月天网| 国产精品一区二区 尿失禁| 欧美后入式| 天天爽天天爽| 中文字幕av亚洲精品| 国产AV天美| 美女极品一区二区三区| 久久久少妇诱惑精品视频| 97最新在线播放视频| 99热这里都是精品| 国产精品青青草| .精品人妻一区二区三| 日欧毛片久久| 色香色欲天天综合网天天来吧| 欧洲亚洲人妻无码高清久久三区四区| 99热精品在线观看| 欧美性爱第一页久久| 大香网伊人久久综合网eew| 黄片免费久久久久久久| 久热精品在线| 97色在线观看| 日韩中文字幕人妻视频| 亚洲九九视频| 中日无幕一二三四区| 大学生口爆吞精| 久久成人东京热人妻| 神马久久久久眼| 精品视频免费在线一区| 九九热只有精品| 国内黄色精品| 日本午夜操逼| 欧美高清色| 精品性爱久久视频| 大香蕉久操| 欧美激情视频一区二区| 久久久工口| 黄色AAAAAAAAAAA大片| 久久久啊啊啊| 国产极品久久久| 日韩另类| 欧美成人A√在线一区二区| 91国产丝袜美女| 日本人体九九九九九九| 国产精品亚洲天堂网址| 亚洲色婷婷综合久久一区二区三区| 天天淫人人妻日日色| 欧亚乱色熟女一区二区| 老熟女网站| 国产精品不卡一区二区三区| 色99视频| 精品中文字幕第一页| 哈哈操电影| 熟女人妇一区二区三区| 97视频网站| 国产精品久久久久999| 操九九九九九九| 极品白嫩美女白浆成人福利在线看| 大肥女高潮bbwbbwhd视频| 亚洲91综合| 97干色天堂| 国产成人综合网| 在线观看成人性爱免费小视频| 色臀AV| 伊人午夜福利视频| 亚洲激情 欧美色图| 婷婷五月色| AV免费在线播放一区| 成全动漫视频观看免费下载| 校园春色 亚洲| 东北女人操比视频| 中文字幕 一区二区 亚洲无码| 91人妻尻屄视频| 日韩三A大片在线观看| 日韩小电影| 极品少妇久久久久| 亚洲色图综合网| 久久九七| 久久精品免费| 日本福利社| 人妻熟女av国产网站| 日逼视频日本| 97无码视频在线播放| 日本媚薬中文字幕在线| 免费国产| 久草草一二三四区久久| 美女的肌被草喷水视频| 看看小穴| 亚洲五月丁香花狠狠干一区二区三区| 午夜精品久久久久久久99蜜桃一| 人人操人人插人人摸人人干| A级在线视频| 97超碰人妻| 热热色中文无码| 中文字幕福利视频一区二区三区在线观看| 自拍亚洲综合| 超碰久久草| laoshunv91| av麻豆啪啪| 亚洲激情色片| 神马久久中文字幕| 亚洲综合性感在线| 欧美日韩资源在线| 国精品一区二区三| 欧美三级一级| 欧美 亚洲 制服 精品| 男人的天堂2010| julia高潮后不停追击中出| 欧美日综合| 五月天综合| 免费观看的av| 九九热精品视频在线观看| 色情五月丁香| 九九在线精品| 天天日少妇逼AV| 91人人爽人人爽人人人,gav福利视频导航,日韩欧美亚洲国产字幕四区 | 狠狠操狠狠操操| 起碰97| 国内毛片欧美香蕉精品| 午夜国产成人精品视频| 香蕉国产精品麻豆亚洲欧美日韩| 老熟女乱伦片| 五十路六十路七十路熟婆| 一二三四视频中文字幕在线看| 国产一区二区三三视频| www.久久最新地址| aⅴ日韩成人电影av在线免费看av大全 | 夜嗨影院| 色综合尤物| 能看的AV| 超AV色女| caopeng97人妻| 97欧美日韩中文| 久久久久久久综合,国产| 超碰 欧美| 青青草好吊色| 日韩av性爱在线播放| 最新日日夜夜天天干干| 国产精品久久久久中文字幕| 国产精品一区二区 尿失禁| 婷婷综合网| 精品久久久久,69国产成人精| 人妻在线臀日韩| 狠狠夜色午夜久久综合在线| 97视频在线视频| 国产精品97视频| 秋霞怕怕片| 国产一级不卡在线观看| 亚洲aV性爱| 六六久久日韩不卡| 亚洲淫乱骚妇AV| 97国产精品久久久久| 色九久| 久热在线精品免费观看| 久久高清欧美国产| 欧美极品女人的天堂| 日日橹狠狠爱欧美超碰| 青久久| 91这里只有精品| 欧美aaaaaaa| 精品色色| 九九九九九九成人| 精品十八在线观看| 国产精品久久aV| 亚洲第一成人影院色播| 久久久久久中文字幕中文字幕最新| 欧美国产成人在线| 一二三区精品视频| 天天躁狠狠躁av| 亚洲无码一区成人免费午夜 | 日本精品成人无码| 黄色二级片网站| 爱丝福利| 最新亚洲黄色免费电影| 国产综合永久精品日韩鬼片| 亚洲精品视频二区| 91 综合 色| 超碰97中文| 一区二区三区四区免费视频| 麻豆2区1区天美| 日本免费一区二区不卡| WWW.操逼.COM| 3p国产色噜噜一区| 欧美爆操91| 99999久久精| 久操网视频| 色av中文字| 97在线日韩中文字幕| 亚洲AV秘无码一区..| 99无码视频| 裸体美女久久久| 久操电影| 九九99精品视频在线观看| 国产乱人妻精品入口| 97天天综合| 人妻精品视频一区二区| 97自拍一区| 精品人妻一区二区三区四区不卡在| 人人摸人人干人人拍97| 91视频成人福利网站在线一区 | 国产67194| 青青伊人这里只有精品| 国产福利一区二| 丰满人妻一区二区三区| 最新9久久久9免费视频| 无码高清操逼| 丁香五月影院| 在线 欧美 亚洲| 精品人体无圣光凹凸| 嗯嗯啊啊操死我| www.男人的天堂| 欧美色图片欧美色图| 天天看人人操屄犊摸阴| 日本不卡在线二区三区| 黄色视频特级毛片| 九九九九日本| 国产成人亚洲精品无| 色五月综合网| 久久久三区二区一区| 韩国成人精品久久久免费看| 中美日韩毛片| 亚洲97| 91久久久久免| 精品人妻一区二区三区不卡断 | 大香蕉92| 国产精品久久久久无码A√| 欧美成人精品一区二区三区| 春色91| 色婷视频| 亚洲综合嫩| 日韩黄色电影网站| 色情婷婷久久五月天| 一区二区三区黄片免费观看| 人妻人人澡人人爽人人| 国产一区二区免费福利片|