diff --git a/404.html b/404.html index df033bcd..735106b3 100644 --- a/404.html +++ b/404.html @@ -21,7 +21,7 @@
Skip to content

404

PAGE NOT FOUND

But if you don't change your direction, and if you keep looking, you may end up where you are heading.
- + \ No newline at end of file diff --git a/assets/6.fdcb22fa.png b/assets/6.fdcb22fa.png deleted file mode 100644 index 5354433b..00000000 Binary files a/assets/6.fdcb22fa.png and /dev/null differ diff --git a/assets/7.522a2c1b.png b/assets/7.522a2c1b.png deleted file mode 100644 index a6666eaa..00000000 Binary files a/assets/7.522a2c1b.png and /dev/null differ diff --git a/assets/8.adec2266.png b/assets/8.adec2266.png deleted file mode 100644 index d84e2428..00000000 Binary files a/assets/8.adec2266.png and /dev/null differ diff --git "a/assets/guide_DDD \351\242\206\345\237\237\351\251\261\345\212\250\350\256\276\350\256\241_index.md.a954ac27.lean.js" "b/assets/guide_DDD \351\242\206\345\237\237\351\251\261\345\212\250\350\256\276\350\256\241_index.md.7e53d5dd.js" similarity index 92% rename from "assets/guide_DDD \351\242\206\345\237\237\351\251\261\345\212\250\350\256\276\350\256\241_index.md.a954ac27.lean.js" rename to "assets/guide_DDD \351\242\206\345\237\237\351\251\261\345\212\250\350\256\276\350\256\241_index.md.7e53d5dd.js" index a25d0c83..85c44069 100644 --- "a/assets/guide_DDD \351\242\206\345\237\237\351\251\261\345\212\250\350\256\276\350\256\241_index.md.a954ac27.lean.js" +++ "b/assets/guide_DDD \351\242\206\345\237\237\351\251\261\345\212\250\350\256\276\350\256\241_index.md.7e53d5dd.js" @@ -1 +1 @@ -import{_ as t,o as d,c as r,k as e,a}from"./chunks/framework.b6910bb2.js";const D=JSON.parse('{"title":"领域驱动设计","description":"","frontmatter":{},"headers":[],"relativePath":"guide/DDD 领域驱动设计/index.md","filePath":"guide/DDD 领域驱动设计/index.md","lastUpdated":1718173557000}'),s={name:"guide/DDD 领域驱动设计/index.md"},n=e("h1",{id:"领域驱动设计",tabindex:"-1"},[a("领域驱动设计 "),e("a",{class:"header-anchor",href:"#领域驱动设计","aria-label":'Permalink to "领域驱动设计"'},"​")],-1),o=e("h2",{id:"定义",tabindex:"-1"},[a("定义 "),e("a",{class:"header-anchor",href:"#定义","aria-label":'Permalink to "定义"'},"​")],-1),i=[n,o];function c(l,_,h,p,m,f){return d(),r("div",null,i)}const u=t(s,[["render",c]]);export{D as __pageData,u as default}; +import{_ as t,o as d,c as r,k as e,a}from"./chunks/framework.b6910bb2.js";const D=JSON.parse('{"title":"领域驱动设计","description":"","frontmatter":{},"headers":[],"relativePath":"guide/DDD 领域驱动设计/index.md","filePath":"guide/DDD 领域驱动设计/index.md","lastUpdated":1718174182000}'),s={name:"guide/DDD 领域驱动设计/index.md"},n=e("h1",{id:"领域驱动设计",tabindex:"-1"},[a("领域驱动设计 "),e("a",{class:"header-anchor",href:"#领域驱动设计","aria-label":'Permalink to "领域驱动设计"'},"​")],-1),o=e("h2",{id:"定义",tabindex:"-1"},[a("定义 "),e("a",{class:"header-anchor",href:"#定义","aria-label":'Permalink to "定义"'},"​")],-1),i=[n,o];function c(l,_,h,p,m,f){return d(),r("div",null,i)}const u=t(s,[["render",c]]);export{D as __pageData,u as default}; diff --git "a/assets/guide_DDD \351\242\206\345\237\237\351\251\261\345\212\250\350\256\276\350\256\241_index.md.a954ac27.js" "b/assets/guide_DDD \351\242\206\345\237\237\351\251\261\345\212\250\350\256\276\350\256\241_index.md.7e53d5dd.lean.js" similarity index 92% rename from "assets/guide_DDD \351\242\206\345\237\237\351\251\261\345\212\250\350\256\276\350\256\241_index.md.a954ac27.js" rename to "assets/guide_DDD \351\242\206\345\237\237\351\251\261\345\212\250\350\256\276\350\256\241_index.md.7e53d5dd.lean.js" index a25d0c83..85c44069 100644 --- "a/assets/guide_DDD \351\242\206\345\237\237\351\251\261\345\212\250\350\256\276\350\256\241_index.md.a954ac27.js" +++ "b/assets/guide_DDD \351\242\206\345\237\237\351\251\261\345\212\250\350\256\276\350\256\241_index.md.7e53d5dd.lean.js" @@ -1 +1 @@ -import{_ as t,o as d,c as r,k as e,a}from"./chunks/framework.b6910bb2.js";const D=JSON.parse('{"title":"领域驱动设计","description":"","frontmatter":{},"headers":[],"relativePath":"guide/DDD 领域驱动设计/index.md","filePath":"guide/DDD 领域驱动设计/index.md","lastUpdated":1718173557000}'),s={name:"guide/DDD 领域驱动设计/index.md"},n=e("h1",{id:"领域驱动设计",tabindex:"-1"},[a("领域驱动设计 "),e("a",{class:"header-anchor",href:"#领域驱动设计","aria-label":'Permalink to "领域驱动设计"'},"​")],-1),o=e("h2",{id:"定义",tabindex:"-1"},[a("定义 "),e("a",{class:"header-anchor",href:"#定义","aria-label":'Permalink to "定义"'},"​")],-1),i=[n,o];function c(l,_,h,p,m,f){return d(),r("div",null,i)}const u=t(s,[["render",c]]);export{D as __pageData,u as default}; +import{_ as t,o as d,c as r,k as e,a}from"./chunks/framework.b6910bb2.js";const D=JSON.parse('{"title":"领域驱动设计","description":"","frontmatter":{},"headers":[],"relativePath":"guide/DDD 领域驱动设计/index.md","filePath":"guide/DDD 领域驱动设计/index.md","lastUpdated":1718174182000}'),s={name:"guide/DDD 领域驱动设计/index.md"},n=e("h1",{id:"领域驱动设计",tabindex:"-1"},[a("领域驱动设计 "),e("a",{class:"header-anchor",href:"#领域驱动设计","aria-label":'Permalink to "领域驱动设计"'},"​")],-1),o=e("h2",{id:"定义",tabindex:"-1"},[a("定义 "),e("a",{class:"header-anchor",href:"#定义","aria-label":'Permalink to "定义"'},"​")],-1),i=[n,o];function c(l,_,h,p,m,f){return d(),r("div",null,i)}const u=t(s,[["render",c]]);export{D as __pageData,u as default}; diff --git "a/assets/guide_Fabric.js_\345\246\202\344\275\225\350\260\203\350\257\225Fabric.md.c1b3d722.js" "b/assets/guide_Fabric.js_\345\246\202\344\275\225\350\260\203\350\257\225Fabric.md.6b7c3634.js" similarity index 99% rename from "assets/guide_Fabric.js_\345\246\202\344\275\225\350\260\203\350\257\225Fabric.md.c1b3d722.js" rename to "assets/guide_Fabric.js_\345\246\202\344\275\225\350\260\203\350\257\225Fabric.md.6b7c3634.js" index 59f78120..beba8b3b 100644 --- "a/assets/guide_Fabric.js_\345\246\202\344\275\225\350\260\203\350\257\225Fabric.md.c1b3d722.js" +++ "b/assets/guide_Fabric.js_\345\246\202\344\275\225\350\260\203\350\257\225Fabric.md.6b7c3634.js" @@ -1 +1 @@ -import{_ as s,o as a,c as l,Q as e}from"./chunks/framework.b6910bb2.js";const p="/vitePress-blob/assets/调试Fabric.2a8c097f.png",F=JSON.parse('{"title":"如何调试 Fabric.js","description":"","frontmatter":{},"headers":[],"relativePath":"guide/Fabric.js/如何调试Fabric.md","filePath":"guide/Fabric.js/如何调试Fabric.md","lastUpdated":1718173557000}'),n={name:"guide/Fabric.js/如何调试Fabric.md"},o=e('

如何调试 Fabric.js

为了更好的学习 Fabric.js 的源码,我们需要了解如何调试 Fabric.js。

第一步:下载源码

首先,我们需要下载 Fabric.js 的源码。Fabric.js 的源码托管在 GitHub 上,我们可以通过 git clone 命令将源码下载到本地。

bash
git clone https://github.com/fabricjs/fabricjs.com.git
git clone https://github.com/fabricjs/fabricjs.com.git

第二步:安装依赖

Fabric.js 使用 Jekyll 来提供页面服务,因此我们需要安装 Jekyll

Jekyll 提供了多种安装方式,在下将以 macOS 为例

Step 1: Install Homebrew

bash
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

Step 2: Install chruby and the latest Ruby with ruby-install

bash
brew install chruby ruby-install xz
brew install chruby ruby-install xz

Step 3: Install Ruby

bash
ruby-install ruby 3.1.3
ruby-install ruby 3.1.3

Step 4: 检查 ruby 是否安装成功

bash
ruby -v
ruby -v

它应该显示 ruby​​ 3.1.3p185(2022-11-24 修订版 1a6b16756e)或更新版本。 alt text

Step 5: 安装 Jekyll

bash
gem install jekyll
gem install jekyll

Step 6: 运行环境 安装完成后,在项目仓库根目录中运行命令 jekyll serve 即可.在此命令的控制台输出中,您将看到 Server address: <base_url> ,在浏览器中访问此 base_url ,您将看到 fabricjs.com 上的内容以及本地更改应用。

',20),t=[o];function c(r,i,y,b,d,h){return a(),l("div",null,t)}const E=s(n,[["render",c]]);export{F as __pageData,E as default}; +import{_ as s,o as a,c as l,Q as e}from"./chunks/framework.b6910bb2.js";const p="/vitePress-blob/assets/调试Fabric.2a8c097f.png",F=JSON.parse('{"title":"如何调试 Fabric.js","description":"","frontmatter":{},"headers":[],"relativePath":"guide/Fabric.js/如何调试Fabric.md","filePath":"guide/Fabric.js/如何调试Fabric.md","lastUpdated":1718174182000}'),n={name:"guide/Fabric.js/如何调试Fabric.md"},o=e('

如何调试 Fabric.js

为了更好的学习 Fabric.js 的源码,我们需要了解如何调试 Fabric.js。

第一步:下载源码

首先,我们需要下载 Fabric.js 的源码。Fabric.js 的源码托管在 GitHub 上,我们可以通过 git clone 命令将源码下载到本地。

bash
git clone https://github.com/fabricjs/fabricjs.com.git
git clone https://github.com/fabricjs/fabricjs.com.git

第二步:安装依赖

Fabric.js 使用 Jekyll 来提供页面服务,因此我们需要安装 Jekyll

Jekyll 提供了多种安装方式,在下将以 macOS 为例

Step 1: Install Homebrew

bash
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

Step 2: Install chruby and the latest Ruby with ruby-install

bash
brew install chruby ruby-install xz
brew install chruby ruby-install xz

Step 3: Install Ruby

bash
ruby-install ruby 3.1.3
ruby-install ruby 3.1.3

Step 4: 检查 ruby 是否安装成功

bash
ruby -v
ruby -v

它应该显示 ruby​​ 3.1.3p185(2022-11-24 修订版 1a6b16756e)或更新版本。 alt text

Step 5: 安装 Jekyll

bash
gem install jekyll
gem install jekyll

Step 6: 运行环境 安装完成后,在项目仓库根目录中运行命令 jekyll serve 即可.在此命令的控制台输出中,您将看到 Server address: <base_url> ,在浏览器中访问此 base_url ,您将看到 fabricjs.com 上的内容以及本地更改应用。

',20),t=[o];function c(r,i,y,b,d,h){return a(),l("div",null,t)}const E=s(n,[["render",c]]);export{F as __pageData,E as default}; diff --git "a/assets/guide_Fabric.js_\345\246\202\344\275\225\350\260\203\350\257\225Fabric.md.c1b3d722.lean.js" "b/assets/guide_Fabric.js_\345\246\202\344\275\225\350\260\203\350\257\225Fabric.md.6b7c3634.lean.js" similarity index 88% rename from "assets/guide_Fabric.js_\345\246\202\344\275\225\350\260\203\350\257\225Fabric.md.c1b3d722.lean.js" rename to "assets/guide_Fabric.js_\345\246\202\344\275\225\350\260\203\350\257\225Fabric.md.6b7c3634.lean.js" index 929ddf09..c83700be 100644 --- "a/assets/guide_Fabric.js_\345\246\202\344\275\225\350\260\203\350\257\225Fabric.md.c1b3d722.lean.js" +++ "b/assets/guide_Fabric.js_\345\246\202\344\275\225\350\260\203\350\257\225Fabric.md.6b7c3634.lean.js" @@ -1 +1 @@ -import{_ as s,o as a,c as l,Q as e}from"./chunks/framework.b6910bb2.js";const p="/vitePress-blob/assets/调试Fabric.2a8c097f.png",F=JSON.parse('{"title":"如何调试 Fabric.js","description":"","frontmatter":{},"headers":[],"relativePath":"guide/Fabric.js/如何调试Fabric.md","filePath":"guide/Fabric.js/如何调试Fabric.md","lastUpdated":1718173557000}'),n={name:"guide/Fabric.js/如何调试Fabric.md"},o=e("",20),t=[o];function c(r,i,y,b,d,h){return a(),l("div",null,t)}const E=s(n,[["render",c]]);export{F as __pageData,E as default}; +import{_ as s,o as a,c as l,Q as e}from"./chunks/framework.b6910bb2.js";const p="/vitePress-blob/assets/调试Fabric.2a8c097f.png",F=JSON.parse('{"title":"如何调试 Fabric.js","description":"","frontmatter":{},"headers":[],"relativePath":"guide/Fabric.js/如何调试Fabric.md","filePath":"guide/Fabric.js/如何调试Fabric.md","lastUpdated":1718174182000}'),n={name:"guide/Fabric.js/如何调试Fabric.md"},o=e("",20),t=[o];function c(r,i,y,b,d,h){return a(),l("div",null,t)}const E=s(n,[["render",c]]);export{F as __pageData,E as default}; diff --git "a/assets/guide_Node\347\233\270\345\205\263_\346\246\202\350\246\201.md.c177becf.js" "b/assets/guide_Node\347\233\270\345\205\263_\346\246\202\350\246\201.md.3c56ab35.js" similarity index 84% rename from "assets/guide_Node\347\233\270\345\205\263_\346\246\202\350\246\201.md.c177becf.js" rename to "assets/guide_Node\347\233\270\345\205\263_\346\246\202\350\246\201.md.3c56ab35.js" index a9246fc0..68936361 100644 --- "a/assets/guide_Node\347\233\270\345\205\263_\346\246\202\350\246\201.md.c177becf.js" +++ "b/assets/guide_Node\347\233\270\345\205\263_\346\246\202\350\246\201.md.3c56ab35.js" @@ -1 +1 @@ -import{_ as e,o as t,c as a}from"./chunks/framework.b6910bb2.js";const m=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"guide/Node相关/概要.md","filePath":"guide/Node相关/概要.md","lastUpdated":1718173557000}'),o={name:"guide/Node相关/概要.md"};function d(r,s,c,n,i,_){return t(),a("div")}const f=e(o,[["render",d]]);export{m as __pageData,f as default}; +import{_ as e,o as t,c as a}from"./chunks/framework.b6910bb2.js";const m=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"guide/Node相关/概要.md","filePath":"guide/Node相关/概要.md","lastUpdated":1718174182000}'),o={name:"guide/Node相关/概要.md"};function d(r,s,c,n,i,_){return t(),a("div")}const f=e(o,[["render",d]]);export{m as __pageData,f as default}; diff --git "a/assets/guide_Node\347\233\270\345\205\263_\346\246\202\350\246\201.md.c177becf.lean.js" "b/assets/guide_Node\347\233\270\345\205\263_\346\246\202\350\246\201.md.3c56ab35.lean.js" similarity index 84% rename from "assets/guide_Node\347\233\270\345\205\263_\346\246\202\350\246\201.md.c177becf.lean.js" rename to "assets/guide_Node\347\233\270\345\205\263_\346\246\202\350\246\201.md.3c56ab35.lean.js" index a9246fc0..68936361 100644 --- "a/assets/guide_Node\347\233\270\345\205\263_\346\246\202\350\246\201.md.c177becf.lean.js" +++ "b/assets/guide_Node\347\233\270\345\205\263_\346\246\202\350\246\201.md.3c56ab35.lean.js" @@ -1 +1 @@ -import{_ as e,o as t,c as a}from"./chunks/framework.b6910bb2.js";const m=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"guide/Node相关/概要.md","filePath":"guide/Node相关/概要.md","lastUpdated":1718173557000}'),o={name:"guide/Node相关/概要.md"};function d(r,s,c,n,i,_){return t(),a("div")}const f=e(o,[["render",d]]);export{m as __pageData,f as default}; +import{_ as e,o as t,c as a}from"./chunks/framework.b6910bb2.js";const m=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"guide/Node相关/概要.md","filePath":"guide/Node相关/概要.md","lastUpdated":1718174182000}'),o={name:"guide/Node相关/概要.md"};function d(r,s,c,n,i,_){return t(),a("div")}const f=e(o,[["render",d]]);export{m as __pageData,f as default}; diff --git "a/assets/guide_React_React\344\270\216Vue\347\232\204\345\214\272\345\210\253.md.ee1c50b9.js" "b/assets/guide_React_React\344\270\216Vue\347\232\204\345\214\272\345\210\253.md.672b0c8e.js" similarity index 85% rename from "assets/guide_React_React\344\270\216Vue\347\232\204\345\214\272\345\210\253.md.ee1c50b9.js" rename to "assets/guide_React_React\344\270\216Vue\347\232\204\345\214\272\345\210\253.md.672b0c8e.js" index 8b64ce39..0e0b3709 100644 --- "a/assets/guide_React_React\344\270\216Vue\347\232\204\345\214\272\345\210\253.md.ee1c50b9.js" +++ "b/assets/guide_React_React\344\270\216Vue\347\232\204\345\214\272\345\210\253.md.672b0c8e.js" @@ -1 +1 @@ -import{_ as e,o as t,c as a}from"./chunks/framework.b6910bb2.js";const u=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"guide/React/React与Vue的区别.md","filePath":"guide/React/React与Vue的区别.md","lastUpdated":1718173557000}'),c={name:"guide/React/React与Vue的区别.md"};function r(o,s,d,n,_,i){return t(),a("div")}const m=e(c,[["render",r]]);export{u as __pageData,m as default}; +import{_ as e,o as t,c as a}from"./chunks/framework.b6910bb2.js";const u=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"guide/React/React与Vue的区别.md","filePath":"guide/React/React与Vue的区别.md","lastUpdated":1718174182000}'),c={name:"guide/React/React与Vue的区别.md"};function r(o,s,d,n,_,i){return t(),a("div")}const m=e(c,[["render",r]]);export{u as __pageData,m as default}; diff --git "a/assets/guide_React_React\344\270\216Vue\347\232\204\345\214\272\345\210\253.md.ee1c50b9.lean.js" "b/assets/guide_React_React\344\270\216Vue\347\232\204\345\214\272\345\210\253.md.672b0c8e.lean.js" similarity index 85% rename from "assets/guide_React_React\344\270\216Vue\347\232\204\345\214\272\345\210\253.md.ee1c50b9.lean.js" rename to "assets/guide_React_React\344\270\216Vue\347\232\204\345\214\272\345\210\253.md.672b0c8e.lean.js" index 8b64ce39..0e0b3709 100644 --- "a/assets/guide_React_React\344\270\216Vue\347\232\204\345\214\272\345\210\253.md.ee1c50b9.lean.js" +++ "b/assets/guide_React_React\344\270\216Vue\347\232\204\345\214\272\345\210\253.md.672b0c8e.lean.js" @@ -1 +1 @@ -import{_ as e,o as t,c as a}from"./chunks/framework.b6910bb2.js";const u=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"guide/React/React与Vue的区别.md","filePath":"guide/React/React与Vue的区别.md","lastUpdated":1718173557000}'),c={name:"guide/React/React与Vue的区别.md"};function r(o,s,d,n,_,i){return t(),a("div")}const m=e(c,[["render",r]]);export{u as __pageData,m as default}; +import{_ as e,o as t,c as a}from"./chunks/framework.b6910bb2.js";const u=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"guide/React/React与Vue的区别.md","filePath":"guide/React/React与Vue的区别.md","lastUpdated":1718174182000}'),c={name:"guide/React/React与Vue的区别.md"};function r(o,s,d,n,_,i){return t(),a("div")}const m=e(c,[["render",r]]);export{u as __pageData,m as default}; diff --git "a/assets/guide_React_React\344\270\255\347\232\204\344\272\213\344\273\266\346\234\272\345\210\266.md.58783f25.js" "b/assets/guide_React_React\344\270\255\347\232\204\344\272\213\344\273\266\346\234\272\345\210\266.md.a3d99e5c.js" similarity index 95% rename from "assets/guide_React_React\344\270\255\347\232\204\344\272\213\344\273\266\346\234\272\345\210\266.md.58783f25.js" rename to "assets/guide_React_React\344\270\255\347\232\204\344\272\213\344\273\266\346\234\272\345\210\266.md.a3d99e5c.js" index 84dc75d0..115c229f 100644 --- "a/assets/guide_React_React\344\270\255\347\232\204\344\272\213\344\273\266\346\234\272\345\210\266.md.58783f25.js" +++ "b/assets/guide_React_React\344\270\255\347\232\204\344\272\213\344\273\266\346\234\272\345\210\266.md.a3d99e5c.js" @@ -1 +1 @@ -import{_ as a,o as e,c as t,Q as c}from"./chunks/framework.b6910bb2.js";const p=JSON.parse('{"title":"React 事件机制","description":"","frontmatter":{},"headers":[],"relativePath":"guide/React/React中的事件机制.md","filePath":"guide/React/React中的事件机制.md","lastUpdated":1718173557000}'),r={name:"guide/React/React中的事件机制.md"},o=c('

React 事件机制

概要

为了抹平各个浏览器之间的差异以及统一维护和管理事件,React 自行实现了合成事件,用来模拟原生事件的行为 在 React 16 之前,React 的合成事件放在了 document 的冒泡阶段 在 React 16 之后,为了兼容各个版本,React 的合成事件放在了 根节点 的捕获和冒泡阶段

具体实现

',4),_=[o];function d(i,n,s,l,h,R){return e(),t("div",null,_)}const m=a(r,[["render",d]]);export{p as __pageData,m as default}; +import{_ as a,o as e,c as t,Q as c}from"./chunks/framework.b6910bb2.js";const p=JSON.parse('{"title":"React 事件机制","description":"","frontmatter":{},"headers":[],"relativePath":"guide/React/React中的事件机制.md","filePath":"guide/React/React中的事件机制.md","lastUpdated":1718174182000}'),r={name:"guide/React/React中的事件机制.md"},o=c('

React 事件机制

概要

为了抹平各个浏览器之间的差异以及统一维护和管理事件,React 自行实现了合成事件,用来模拟原生事件的行为 在 React 16 之前,React 的合成事件放在了 document 的冒泡阶段 在 React 16 之后,为了兼容各个版本,React 的合成事件放在了 根节点 的捕获和冒泡阶段

具体实现

',4),_=[o];function d(i,n,s,l,h,R){return e(),t("div",null,_)}const m=a(r,[["render",d]]);export{p as __pageData,m as default}; diff --git "a/assets/guide_React_React\344\270\255\347\232\204\344\272\213\344\273\266\346\234\272\345\210\266.md.58783f25.lean.js" "b/assets/guide_React_React\344\270\255\347\232\204\344\272\213\344\273\266\346\234\272\345\210\266.md.a3d99e5c.lean.js" similarity index 86% rename from "assets/guide_React_React\344\270\255\347\232\204\344\272\213\344\273\266\346\234\272\345\210\266.md.58783f25.lean.js" rename to "assets/guide_React_React\344\270\255\347\232\204\344\272\213\344\273\266\346\234\272\345\210\266.md.a3d99e5c.lean.js" index b8d55f50..c3a96274 100644 --- "a/assets/guide_React_React\344\270\255\347\232\204\344\272\213\344\273\266\346\234\272\345\210\266.md.58783f25.lean.js" +++ "b/assets/guide_React_React\344\270\255\347\232\204\344\272\213\344\273\266\346\234\272\345\210\266.md.a3d99e5c.lean.js" @@ -1 +1 @@ -import{_ as a,o as e,c as t,Q as c}from"./chunks/framework.b6910bb2.js";const p=JSON.parse('{"title":"React 事件机制","description":"","frontmatter":{},"headers":[],"relativePath":"guide/React/React中的事件机制.md","filePath":"guide/React/React中的事件机制.md","lastUpdated":1718173557000}'),r={name:"guide/React/React中的事件机制.md"},o=c("",4),_=[o];function d(i,n,s,l,h,R){return e(),t("div",null,_)}const m=a(r,[["render",d]]);export{p as __pageData,m as default}; +import{_ as a,o as e,c as t,Q as c}from"./chunks/framework.b6910bb2.js";const p=JSON.parse('{"title":"React 事件机制","description":"","frontmatter":{},"headers":[],"relativePath":"guide/React/React中的事件机制.md","filePath":"guide/React/React中的事件机制.md","lastUpdated":1718174182000}'),r={name:"guide/React/React中的事件机制.md"},o=c("",4),_=[o];function d(i,n,s,l,h,R){return e(),t("div",null,_)}const m=a(r,[["render",d]]);export{p as __pageData,m as default}; diff --git "a/assets/guide_React_React\344\270\255\347\232\204\345\274\202\345\270\270\346\234\272\345\210\266.md.4e0a6832.js" "b/assets/guide_React_React\344\270\255\347\232\204\345\274\202\345\270\270\346\234\272\345\210\266.md.07adea05.js" similarity index 85% rename from "assets/guide_React_React\344\270\255\347\232\204\345\274\202\345\270\270\346\234\272\345\210\266.md.4e0a6832.js" rename to "assets/guide_React_React\344\270\255\347\232\204\345\274\202\345\270\270\346\234\272\345\210\266.md.07adea05.js" index a5682d3f..f6e24860 100644 --- "a/assets/guide_React_React\344\270\255\347\232\204\345\274\202\345\270\270\346\234\272\345\210\266.md.4e0a6832.js" +++ "b/assets/guide_React_React\344\270\255\347\232\204\345\274\202\345\270\270\346\234\272\345\210\266.md.07adea05.js" @@ -1 +1 @@ -import{_ as e,o as t,c as a}from"./chunks/framework.b6910bb2.js";const m=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"guide/React/React中的异常机制.md","filePath":"guide/React/React中的异常机制.md","lastUpdated":1718173557000}'),c={name:"guide/React/React中的异常机制.md"};function r(o,s,_,d,n,i){return t(),a("div")}const f=e(c,[["render",r]]);export{m as __pageData,f as default}; +import{_ as e,o as t,c as a}from"./chunks/framework.b6910bb2.js";const m=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"guide/React/React中的异常机制.md","filePath":"guide/React/React中的异常机制.md","lastUpdated":1718174182000}'),c={name:"guide/React/React中的异常机制.md"};function r(o,s,_,d,n,i){return t(),a("div")}const f=e(c,[["render",r]]);export{m as __pageData,f as default}; diff --git "a/assets/guide_React_React\344\270\255\347\232\204\345\274\202\345\270\270\346\234\272\345\210\266.md.4e0a6832.lean.js" "b/assets/guide_React_React\344\270\255\347\232\204\345\274\202\345\270\270\346\234\272\345\210\266.md.07adea05.lean.js" similarity index 85% rename from "assets/guide_React_React\344\270\255\347\232\204\345\274\202\345\270\270\346\234\272\345\210\266.md.4e0a6832.lean.js" rename to "assets/guide_React_React\344\270\255\347\232\204\345\274\202\345\270\270\346\234\272\345\210\266.md.07adea05.lean.js" index a5682d3f..f6e24860 100644 --- "a/assets/guide_React_React\344\270\255\347\232\204\345\274\202\345\270\270\346\234\272\345\210\266.md.4e0a6832.lean.js" +++ "b/assets/guide_React_React\344\270\255\347\232\204\345\274\202\345\270\270\346\234\272\345\210\266.md.07adea05.lean.js" @@ -1 +1 @@ -import{_ as e,o as t,c as a}from"./chunks/framework.b6910bb2.js";const m=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"guide/React/React中的异常机制.md","filePath":"guide/React/React中的异常机制.md","lastUpdated":1718173557000}'),c={name:"guide/React/React中的异常机制.md"};function r(o,s,_,d,n,i){return t(),a("div")}const f=e(c,[["render",r]]);export{m as __pageData,f as default}; +import{_ as e,o as t,c as a}from"./chunks/framework.b6910bb2.js";const m=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"guide/React/React中的异常机制.md","filePath":"guide/React/React中的异常机制.md","lastUpdated":1718174182000}'),c={name:"guide/React/React中的异常机制.md"};function r(o,s,_,d,n,i){return t(),a("div")}const f=e(c,[["render",r]]);export{m as __pageData,f as default}; diff --git "a/assets/guide_React_React\344\270\255\347\232\204\346\200\247\350\203\275\344\274\230\345\214\226.md.a8328e29.js" "b/assets/guide_React_React\344\270\255\347\232\204\346\200\247\350\203\275\344\274\230\345\214\226.md.1a2d4379.js" similarity index 99% rename from "assets/guide_React_React\344\270\255\347\232\204\346\200\247\350\203\275\344\274\230\345\214\226.md.a8328e29.js" rename to "assets/guide_React_React\344\270\255\347\232\204\346\200\247\350\203\275\344\274\230\345\214\226.md.1a2d4379.js" index fea43e5d..57f7a382 100644 --- "a/assets/guide_React_React\344\270\255\347\232\204\346\200\247\350\203\275\344\274\230\345\214\226.md.a8328e29.js" +++ "b/assets/guide_React_React\344\270\255\347\232\204\346\200\247\350\203\275\344\274\230\345\214\226.md.1a2d4379.js" @@ -1,4 +1,4 @@ -import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.b6910bb2.js";const u=JSON.parse('{"title":"React 中的性能优化","description":"","frontmatter":{},"headers":[],"relativePath":"guide/React/React中的性能优化.md","filePath":"guide/React/React中的性能优化.md","lastUpdated":1718173557000}'),p={name:"guide/React/React中的性能优化.md"},o=l(`

React 中的性能优化

在 React 中当我们的父组件更新时,将渲染整个子组件树,这样会造成很大的性能开销,所以我们需要对组件进行优化,避免不必要的渲染。

常见的性能优化手段有:

  1. 减少不必要的渲染

    1. 使用 useMemo 缓存数据、使用 useCallback 缓存函数
    2. 使用 React.memo 缓存组件
    3. 合理的使用 Key
    4. 使用 Fragment 避免额外标记
    5. 通过 Suspense 和 Lazy 拆分组件
  2. 通用方案

    1. 在组件销毁的时候清除定时器/事件
    2. 频繁切换时使用 display: none; 避免不必要的性能开销
    3. 为组件创建错误边界

1 使用 useMemo 缓存数据、使用 useCallback 缓存函数

jsx
/**
+import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.b6910bb2.js";const u=JSON.parse('{"title":"React 中的性能优化","description":"","frontmatter":{},"headers":[],"relativePath":"guide/React/React中的性能优化.md","filePath":"guide/React/React中的性能优化.md","lastUpdated":1718174182000}'),p={name:"guide/React/React中的性能优化.md"},o=l(`

React 中的性能优化

在 React 中当我们的父组件更新时,将渲染整个子组件树,这样会造成很大的性能开销,所以我们需要对组件进行优化,避免不必要的渲染。

常见的性能优化手段有:

  1. 减少不必要的渲染

    1. 使用 useMemo 缓存数据、使用 useCallback 缓存函数
    2. 使用 React.memo 缓存组件
    3. 合理的使用 Key
    4. 使用 Fragment 避免额外标记
    5. 通过 Suspense 和 Lazy 拆分组件
  2. 通用方案

    1. 在组件销毁的时候清除定时器/事件
    2. 频繁切换时使用 display: none; 避免不必要的性能开销
    3. 为组件创建错误边界

1 使用 useMemo 缓存数据、使用 useCallback 缓存函数

jsx
/**
  * 使用 useMemo 缓存数据,类似于 Vue 的 computed 计算属性
  * 使用 useCallback 缓存函数
  * @returns
diff --git "a/assets/guide_React_React\344\270\255\347\232\204\346\200\247\350\203\275\344\274\230\345\214\226.md.a8328e29.lean.js" "b/assets/guide_React_React\344\270\255\347\232\204\346\200\247\350\203\275\344\274\230\345\214\226.md.1a2d4379.lean.js"
similarity index 87%
rename from "assets/guide_React_React\344\270\255\347\232\204\346\200\247\350\203\275\344\274\230\345\214\226.md.a8328e29.lean.js"
rename to "assets/guide_React_React\344\270\255\347\232\204\346\200\247\350\203\275\344\274\230\345\214\226.md.1a2d4379.lean.js"
index 5a19c639..28e36343 100644
--- "a/assets/guide_React_React\344\270\255\347\232\204\346\200\247\350\203\275\344\274\230\345\214\226.md.a8328e29.lean.js"
+++ "b/assets/guide_React_React\344\270\255\347\232\204\346\200\247\350\203\275\344\274\230\345\214\226.md.1a2d4379.lean.js"
@@ -1 +1 @@
-import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.b6910bb2.js";const u=JSON.parse('{"title":"React 中的性能优化","description":"","frontmatter":{},"headers":[],"relativePath":"guide/React/React中的性能优化.md","filePath":"guide/React/React中的性能优化.md","lastUpdated":1718173557000}'),p={name:"guide/React/React中的性能优化.md"},o=l("",41),e=[o];function t(c,r,E,y,i,F){return n(),a("div",null,e)}const A=s(p,[["render",t]]);export{u as __pageData,A as default};
+import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.b6910bb2.js";const u=JSON.parse('{"title":"React 中的性能优化","description":"","frontmatter":{},"headers":[],"relativePath":"guide/React/React中的性能优化.md","filePath":"guide/React/React中的性能优化.md","lastUpdated":1718174182000}'),p={name:"guide/React/React中的性能优化.md"},o=l("",41),e=[o];function t(c,r,E,y,i,F){return n(),a("div",null,e)}const A=s(p,[["render",t]]);export{u as __pageData,A as default};
diff --git "a/assets/guide_React_React\344\270\272\344\273\200\344\271\210\350\246\201\344\275\277\347\224\250JSX.md.46e1a94d.js" "b/assets/guide_React_React\344\270\272\344\273\200\344\271\210\350\246\201\344\275\277\347\224\250JSX.md.446a2a3a.js"
similarity index 88%
rename from "assets/guide_React_React\344\270\272\344\273\200\344\271\210\350\246\201\344\275\277\347\224\250JSX.md.46e1a94d.js"
rename to "assets/guide_React_React\344\270\272\344\273\200\344\271\210\350\246\201\344\275\277\347\224\250JSX.md.446a2a3a.js"
index 48f9e1c8..58dbf308 100644
--- "a/assets/guide_React_React\344\270\272\344\273\200\344\271\210\350\246\201\344\275\277\347\224\250JSX.md.46e1a94d.js"
+++ "b/assets/guide_React_React\344\270\272\344\273\200\344\271\210\350\246\201\344\275\277\347\224\250JSX.md.446a2a3a.js"
@@ -1 +1 @@
-import{_ as t,o as a,c,k as e,a as s}from"./chunks/framework.b6910bb2.js";const X=JSON.parse('{"title":"React 为什么要使用 JSX ?","description":"","frontmatter":{},"headers":[],"relativePath":"guide/React/React为什么要使用JSX.md","filePath":"guide/React/React为什么要使用JSX.md","lastUpdated":1718173557000}'),r={name:"guide/React/React为什么要使用JSX.md"},o=e("h1",{id:"react-为什么要使用-jsx",tabindex:"-1"},[s("React 为什么要使用 JSX ? "),e("a",{class:"header-anchor",href:"#react-为什么要使用-jsx","aria-label":'Permalink to "React 为什么要使用 JSX ?"'},"​")],-1),n=e("p",null,"JSX 是 JavaScript 语法拓展,结构类似于 XML,它可以在 JavaScript 中直接使用 HTML 标签,这样可以方便开发者编写组件,提高开发效率。",-1),_=e("p",null,"没有JSX时,也可以使用 React.createElement 实现一个组件,但是这样的代码可读性很差,而且不方便复用,所以 React 推荐使用 JSX。",-1),d=[o,n,_];function i(l,p,J,S,h,R){return a(),c("div",null,d)}const u=t(r,[["render",i]]);export{X as __pageData,u as default};
+import{_ as t,o as a,c,k as e,a as s}from"./chunks/framework.b6910bb2.js";const X=JSON.parse('{"title":"React 为什么要使用 JSX ?","description":"","frontmatter":{},"headers":[],"relativePath":"guide/React/React为什么要使用JSX.md","filePath":"guide/React/React为什么要使用JSX.md","lastUpdated":1718174182000}'),r={name:"guide/React/React为什么要使用JSX.md"},o=e("h1",{id:"react-为什么要使用-jsx",tabindex:"-1"},[s("React 为什么要使用 JSX ? "),e("a",{class:"header-anchor",href:"#react-为什么要使用-jsx","aria-label":'Permalink to "React 为什么要使用 JSX ?"'},"​")],-1),n=e("p",null,"JSX 是 JavaScript 语法拓展,结构类似于 XML,它可以在 JavaScript 中直接使用 HTML 标签,这样可以方便开发者编写组件,提高开发效率。",-1),_=e("p",null,"没有JSX时,也可以使用 React.createElement 实现一个组件,但是这样的代码可读性很差,而且不方便复用,所以 React 推荐使用 JSX。",-1),d=[o,n,_];function i(l,p,J,S,h,R){return a(),c("div",null,d)}const u=t(r,[["render",i]]);export{X as __pageData,u as default};
diff --git "a/assets/guide_React_React\344\270\272\344\273\200\344\271\210\350\246\201\344\275\277\347\224\250JSX.md.46e1a94d.lean.js" "b/assets/guide_React_React\344\270\272\344\273\200\344\271\210\350\246\201\344\275\277\347\224\250JSX.md.446a2a3a.lean.js"
similarity index 88%
rename from "assets/guide_React_React\344\270\272\344\273\200\344\271\210\350\246\201\344\275\277\347\224\250JSX.md.46e1a94d.lean.js"
rename to "assets/guide_React_React\344\270\272\344\273\200\344\271\210\350\246\201\344\275\277\347\224\250JSX.md.446a2a3a.lean.js"
index 48f9e1c8..58dbf308 100644
--- "a/assets/guide_React_React\344\270\272\344\273\200\344\271\210\350\246\201\344\275\277\347\224\250JSX.md.46e1a94d.lean.js"
+++ "b/assets/guide_React_React\344\270\272\344\273\200\344\271\210\350\246\201\344\275\277\347\224\250JSX.md.446a2a3a.lean.js"
@@ -1 +1 @@
-import{_ as t,o as a,c,k as e,a as s}from"./chunks/framework.b6910bb2.js";const X=JSON.parse('{"title":"React 为什么要使用 JSX ?","description":"","frontmatter":{},"headers":[],"relativePath":"guide/React/React为什么要使用JSX.md","filePath":"guide/React/React为什么要使用JSX.md","lastUpdated":1718173557000}'),r={name:"guide/React/React为什么要使用JSX.md"},o=e("h1",{id:"react-为什么要使用-jsx",tabindex:"-1"},[s("React 为什么要使用 JSX ? "),e("a",{class:"header-anchor",href:"#react-为什么要使用-jsx","aria-label":'Permalink to "React 为什么要使用 JSX ?"'},"​")],-1),n=e("p",null,"JSX 是 JavaScript 语法拓展,结构类似于 XML,它可以在 JavaScript 中直接使用 HTML 标签,这样可以方便开发者编写组件,提高开发效率。",-1),_=e("p",null,"没有JSX时,也可以使用 React.createElement 实现一个组件,但是这样的代码可读性很差,而且不方便复用,所以 React 推荐使用 JSX。",-1),d=[o,n,_];function i(l,p,J,S,h,R){return a(),c("div",null,d)}const u=t(r,[["render",i]]);export{X as __pageData,u as default};
+import{_ as t,o as a,c,k as e,a as s}from"./chunks/framework.b6910bb2.js";const X=JSON.parse('{"title":"React 为什么要使用 JSX ?","description":"","frontmatter":{},"headers":[],"relativePath":"guide/React/React为什么要使用JSX.md","filePath":"guide/React/React为什么要使用JSX.md","lastUpdated":1718174182000}'),r={name:"guide/React/React为什么要使用JSX.md"},o=e("h1",{id:"react-为什么要使用-jsx",tabindex:"-1"},[s("React 为什么要使用 JSX ? "),e("a",{class:"header-anchor",href:"#react-为什么要使用-jsx","aria-label":'Permalink to "React 为什么要使用 JSX ?"'},"​")],-1),n=e("p",null,"JSX 是 JavaScript 语法拓展,结构类似于 XML,它可以在 JavaScript 中直接使用 HTML 标签,这样可以方便开发者编写组件,提高开发效率。",-1),_=e("p",null,"没有JSX时,也可以使用 React.createElement 实现一个组件,但是这样的代码可读性很差,而且不方便复用,所以 React 推荐使用 JSX。",-1),d=[o,n,_];function i(l,p,J,S,h,R){return a(),c("div",null,d)}const u=t(r,[["render",i]]);export{X as __pageData,u as default};
diff --git "a/assets/guide_React_React\346\230\257\344\273\200\344\271\210.md.2a94b3c2.js" "b/assets/guide_React_React\346\230\257\344\273\200\344\271\210.md.d60b5e2d.js"
similarity index 98%
rename from "assets/guide_React_React\346\230\257\344\273\200\344\271\210.md.2a94b3c2.js"
rename to "assets/guide_React_React\346\230\257\344\273\200\344\271\210.md.d60b5e2d.js"
index 0428ae13..bf7fe9dd 100644
--- "a/assets/guide_React_React\346\230\257\344\273\200\344\271\210.md.2a94b3c2.js"
+++ "b/assets/guide_React_React\346\230\257\344\273\200\344\271\210.md.d60b5e2d.js"
@@ -1,4 +1,4 @@
-import{_ as s,o as a,c as o,Q as n}from"./chunks/framework.b6910bb2.js";const _=JSON.parse('{"title":"React 是什么?","description":"","frontmatter":{},"headers":[],"relativePath":"guide/React/React是什么.md","filePath":"guide/React/React是什么.md","lastUpdated":1718173557000}'),e={name:"guide/React/React是什么.md"},l=n(`

React 是什么?

React 是一个用于构建用户界面的 JavaScript 库, 通过组件化的方式解决视图层复用的问题。

它的核心思路是: 声明式、组件化、通用型

声明式

相比 JQ 的命令式编程: $(body).css('color', 'red');, 声明式编程更加直观、便于复用:

jsx
const Body = (props) => {
+import{_ as s,o as a,c as o,Q as n}from"./chunks/framework.b6910bb2.js";const _=JSON.parse('{"title":"React 是什么?","description":"","frontmatter":{},"headers":[],"relativePath":"guide/React/React是什么.md","filePath":"guide/React/React是什么.md","lastUpdated":1718174182000}'),e={name:"guide/React/React是什么.md"},l=n(`

React 是什么?

React 是一个用于构建用户界面的 JavaScript 库, 通过组件化的方式解决视图层复用的问题。

它的核心思路是: 声明式、组件化、通用型

声明式

相比 JQ 的命令式编程: $(body).css('color', 'red');, 声明式编程更加直观、便于复用:

jsx
const Body = (props) => {
    return <div style={{color: 'red'}}>{props.children}</div>
 }
const Body = (props) => {
    return <div style={{color: 'red'}}>{props.children}</div>
diff --git "a/assets/guide_React_React\346\230\257\344\273\200\344\271\210.md.2a94b3c2.lean.js" "b/assets/guide_React_React\346\230\257\344\273\200\344\271\210.md.d60b5e2d.lean.js"
similarity index 86%
rename from "assets/guide_React_React\346\230\257\344\273\200\344\271\210.md.2a94b3c2.lean.js"
rename to "assets/guide_React_React\346\230\257\344\273\200\344\271\210.md.d60b5e2d.lean.js"
index cb9fbaf8..64faeacc 100644
--- "a/assets/guide_React_React\346\230\257\344\273\200\344\271\210.md.2a94b3c2.lean.js"
+++ "b/assets/guide_React_React\346\230\257\344\273\200\344\271\210.md.d60b5e2d.lean.js"
@@ -1 +1 @@
-import{_ as s,o as a,c as o,Q as n}from"./chunks/framework.b6910bb2.js";const _=JSON.parse('{"title":"React 是什么?","description":"","frontmatter":{},"headers":[],"relativePath":"guide/React/React是什么.md","filePath":"guide/React/React是什么.md","lastUpdated":1718173557000}'),e={name:"guide/React/React是什么.md"},l=n("",12),p=[l];function t(c,r,i,d,E,y){return a(),o("div",null,p)}const u=s(e,[["render",t]]);export{_ as __pageData,u as default};
+import{_ as s,o as a,c as o,Q as n}from"./chunks/framework.b6910bb2.js";const _=JSON.parse('{"title":"React 是什么?","description":"","frontmatter":{},"headers":[],"relativePath":"guide/React/React是什么.md","filePath":"guide/React/React是什么.md","lastUpdated":1718174182000}'),e={name:"guide/React/React是什么.md"},l=n("",12),p=[l];function t(c,r,i,d,E,y){return a(),o("div",null,p)}const u=s(e,[["render",t]]);export{_ as __pageData,u as default};
diff --git "a/assets/guide_React_React\346\230\257\345\246\202\344\275\225\346\270\262\346\237\223\347\232\204.md.4ea938c9.js" "b/assets/guide_React_React\346\230\257\345\246\202\344\275\225\346\270\262\346\237\223\347\232\204.md.ce1d2ec5.js"
similarity index 99%
rename from "assets/guide_React_React\346\230\257\345\246\202\344\275\225\346\270\262\346\237\223\347\232\204.md.4ea938c9.js"
rename to "assets/guide_React_React\346\230\257\345\246\202\344\275\225\346\270\262\346\237\223\347\232\204.md.ce1d2ec5.js"
index c69dd2d6..0f522046 100644
--- "a/assets/guide_React_React\346\230\257\345\246\202\344\275\225\346\270\262\346\237\223\347\232\204.md.4ea938c9.js"
+++ "b/assets/guide_React_React\346\230\257\345\246\202\344\275\225\346\270\262\346\237\223\347\232\204.md.ce1d2ec5.js"
@@ -1 +1 @@
-import{_ as e,o as r,c as o,Q as t}from"./chunks/framework.b6910bb2.js";const a="/vitePress-blob/assets/3.9b1f9060.png",i="/vitePress-blob/assets/4.f4dd49d0.png",n="/vitePress-blob/assets/5.34ee565e.png",s="/vitePress-blob/assets/12.ba19c2aa.png",c="/vitePress-blob/assets/6.121ea6f5.png",l="/vitePress-blob/assets/7.3f678f52.png",p="/vitePress-blob/assets/8.9d04f238.png",d="/vitePress-blob/assets/9.bae86652.png",b="/vitePress-blob/assets/11.07a5666c.png",h="/vitePress-blob/assets/13.5bf5bc75.png",m="/vitePress-blob/assets/14.f1d70f78.png",u="/vitePress-blob/assets/16.4d6f740b.png",_="/vitePress-blob/assets/15.254fe341.png",f="/vitePress-blob/assets/18.09fcc54c.png",k="/vitePress-blob/assets/17.625ac807.png",g="/vitePress-blob/assets/19.77c3b0a6.png",C=JSON.parse('{"title":"React 是如何渲染的","description":"","frontmatter":{},"headers":[],"relativePath":"guide/React/React是如何渲染的.md","filePath":"guide/React/React是如何渲染的.md","lastUpdated":1718173557000}'),R={name:"guide/React/React是如何渲染的.md"},P=t('

React 是如何渲染的

概要

React 的渲染过程可以分成 2 大阶段, 分别是调和阶段和提交阶段。 调和阶段可以分成 beginWork 阶段、 completeWork 阶段。 在 beginWork 阶段中,React 会根据新生成的 ReactElement 对象和旧的 Fiber 节点进行对比,判断是否可以复用旧的 Fiber 节点并对 Fiber 进行标记。 在 completeWork 节点中,会自底向上构建副作用链表,用来记录需要更新的节点,生成的 DOM 节点会挂载在 Fiber 的 stateNode 属性上。

提交阶段主要分成:操作 DOM 前阶段、操作 DOM 阶段、操作 DOM 后阶段。

React 16 以前

在浏览器中 js 线程与渲染线程是互斥的,如果 js 线程长期占用着浏览器的主线程,那么界面将长时间不更新,在动画等一些场景下会造成卡顿效果。

因为 Stack Reconciler 是一个同步的递归过程,随着业务复杂度增加,Stack Reconciler 需要的调和时间会变长,

这意味着 js 将长时间占用浏览器,进而导致页面卡顿

Stack Reconciler

React 16 以后

将同步执行的 Stack Reconciler 替换成了异步可中断的 Fiber Reconciler

Fiber Reconciler

在更新时,每个任务会被赋予一个优先级,当任务抵达调度器时,高优先级的任务会更快抵达协调器,如有新的更高优先级的任务进入调度器时,当前协调器的任务就会被中断,更高优先级的任务将进入 reconciler

Fiber Reconciler

新的架构会导致部分生命周期重复执行:

  • componentWillMount
  • componentWillUpdate
  • showComponentUpdate
  • componentWillReceiveProps

Render Performance

从首次渲染的调用栈来看,React 的渲染过程主要分为以下几个步骤:

    1. Mount 阶段
    1. Render 阶段
    1. Commit 阶段

Mount 阶段

当执行 ReactDOM.render 时会直接调用 legacyRenderSubtreeIntoContainer 方法

legacyRenderSubtreeIntoContainer 方法

会创建 reactRootContainer 对象(也就是挂载的容器对象), reactRootContainer 对象的 _internalRoot 会指向 fiberRoot (FiberRootNode 类),也就是根节点对象。

legacyRenderSubtreeIntoContainer 最终返回挂载组件( App组件 )的实例对象。

Mount 渲染过程

FiberRootNode对象的描述

在 fiberRoot 对象( FiberRootNode类 )中的 current 属性将指向 rootFiber 对象 (根节点Fiber,即 FiberNode 实例)

fiberRoot对象指向 rootFiber 根节点Fiber

挂载创建关系图

updateContainer 函数

updateContainer 函数主要有以下 3 件事:

    1. 获取当前节点的优先级 lane
    1. 结合 lane 创建当前 Fiber 节点 update 对象,并将其入队
    1. 调度当前节点 (rootFiber 节点)

updateContainer

scheduleUpdateOnFiber 函数

scheduleUpdateOnFiber 函数中会获取 Fiber 节点的mode属性判断是否走同步渲染还是异步渲染的逻辑,在 React17 中首次渲染走的是同步渲染的逻辑

scheduleUpdateOnFiber

这里可能有小伙伴会问,Fiber架构不就是异步渲染的么? 我想说的是,Fiber架构的设计初衷确实是为了异步渲染而设计的,但是 Fiber 架构并不能和异步渲染画上等号,我们不难发现,Fiber 架构同时兼容了同步渲染和异步渲染,如下图,决定同步还是异步取决于 mode

mode 决定同步异步

Render 阶段

performSyncWorkOnRoot 函数

核心逻辑在 renderRootSync 函数中

renderRootSync 函数

核心方法有俩个 prepareFreshStackworkLoopSync 函数

renderRootSync 逻辑

prepareFreshStack 函数

主要是有个方法 createWorkInProgress , 用来构建 workInProgress 双缓冲树,通过 alternate 相互指向

createWorkInProgress 构建 work-in-progress 树

当建立好双缓冲树的关系后,我们不难得到以下的关系图

双缓冲树关系图

workLoopSync 函数

当我们构建完 workInProgress Tree 的根节点时,建立 current tree 和 workInProgess Tree 的关联关系后,将进入 workLoopSync 调和阶段。

反复判断 workInProgress 是否为空,如果不为空,就执行 performUnitOfWork 方法 workLoopSync 逻辑

performUnitOfWork 函数

performUnitOfWork 函数的作用是 beginWork 优先创建子节点。 completeUnitOfWork 创建完子节点后判断是否有兄弟节点,有则创建兄弟节点,无则继续向上遍历父节点,直到遍历到根节点为止

performUnitOfWork 逻辑

beginWork 函数

参考文档

1 https://zhuanlan.zhihu.com/p/385319664 2

',58),q=[P];function F(S,y,W,v,w,x){return r(),o("div",null,q)}const U=e(R,[["render",F]]);export{C as __pageData,U as default}; +import{_ as e,o as r,c as o,Q as t}from"./chunks/framework.b6910bb2.js";const a="/vitePress-blob/assets/3.9b1f9060.png",i="/vitePress-blob/assets/4.f4dd49d0.png",n="/vitePress-blob/assets/5.34ee565e.png",s="/vitePress-blob/assets/12.ba19c2aa.png",c="/vitePress-blob/assets/6.121ea6f5.png",l="/vitePress-blob/assets/7.3f678f52.png",p="/vitePress-blob/assets/8.9d04f238.png",d="/vitePress-blob/assets/9.bae86652.png",b="/vitePress-blob/assets/11.07a5666c.png",h="/vitePress-blob/assets/13.5bf5bc75.png",m="/vitePress-blob/assets/14.f1d70f78.png",u="/vitePress-blob/assets/16.4d6f740b.png",_="/vitePress-blob/assets/15.254fe341.png",f="/vitePress-blob/assets/18.09fcc54c.png",k="/vitePress-blob/assets/17.625ac807.png",g="/vitePress-blob/assets/19.77c3b0a6.png",C=JSON.parse('{"title":"React 是如何渲染的","description":"","frontmatter":{},"headers":[],"relativePath":"guide/React/React是如何渲染的.md","filePath":"guide/React/React是如何渲染的.md","lastUpdated":1718174182000}'),R={name:"guide/React/React是如何渲染的.md"},P=t('

React 是如何渲染的

概要

React 的渲染过程可以分成 2 大阶段, 分别是调和阶段和提交阶段。 调和阶段可以分成 beginWork 阶段、 completeWork 阶段。 在 beginWork 阶段中,React 会根据新生成的 ReactElement 对象和旧的 Fiber 节点进行对比,判断是否可以复用旧的 Fiber 节点并对 Fiber 进行标记。 在 completeWork 节点中,会自底向上构建副作用链表,用来记录需要更新的节点,生成的 DOM 节点会挂载在 Fiber 的 stateNode 属性上。

提交阶段主要分成:操作 DOM 前阶段、操作 DOM 阶段、操作 DOM 后阶段。

React 16 以前

在浏览器中 js 线程与渲染线程是互斥的,如果 js 线程长期占用着浏览器的主线程,那么界面将长时间不更新,在动画等一些场景下会造成卡顿效果。

因为 Stack Reconciler 是一个同步的递归过程,随着业务复杂度增加,Stack Reconciler 需要的调和时间会变长,

这意味着 js 将长时间占用浏览器,进而导致页面卡顿

Stack Reconciler

React 16 以后

将同步执行的 Stack Reconciler 替换成了异步可中断的 Fiber Reconciler

Fiber Reconciler

在更新时,每个任务会被赋予一个优先级,当任务抵达调度器时,高优先级的任务会更快抵达协调器,如有新的更高优先级的任务进入调度器时,当前协调器的任务就会被中断,更高优先级的任务将进入 reconciler

Fiber Reconciler

新的架构会导致部分生命周期重复执行:

  • componentWillMount
  • componentWillUpdate
  • showComponentUpdate
  • componentWillReceiveProps

Render Performance

从首次渲染的调用栈来看,React 的渲染过程主要分为以下几个步骤:

    1. Mount 阶段
    1. Render 阶段
    1. Commit 阶段

Mount 阶段

当执行 ReactDOM.render 时会直接调用 legacyRenderSubtreeIntoContainer 方法

legacyRenderSubtreeIntoContainer 方法

会创建 reactRootContainer 对象(也就是挂载的容器对象), reactRootContainer 对象的 _internalRoot 会指向 fiberRoot (FiberRootNode 类),也就是根节点对象。

legacyRenderSubtreeIntoContainer 最终返回挂载组件( App组件 )的实例对象。

Mount 渲染过程

FiberRootNode对象的描述

在 fiberRoot 对象( FiberRootNode类 )中的 current 属性将指向 rootFiber 对象 (根节点Fiber,即 FiberNode 实例)

fiberRoot对象指向 rootFiber 根节点Fiber

挂载创建关系图

updateContainer 函数

updateContainer 函数主要有以下 3 件事:

    1. 获取当前节点的优先级 lane
    1. 结合 lane 创建当前 Fiber 节点 update 对象,并将其入队
    1. 调度当前节点 (rootFiber 节点)

updateContainer

scheduleUpdateOnFiber 函数

scheduleUpdateOnFiber 函数中会获取 Fiber 节点的mode属性判断是否走同步渲染还是异步渲染的逻辑,在 React17 中首次渲染走的是同步渲染的逻辑

scheduleUpdateOnFiber

这里可能有小伙伴会问,Fiber架构不就是异步渲染的么? 我想说的是,Fiber架构的设计初衷确实是为了异步渲染而设计的,但是 Fiber 架构并不能和异步渲染画上等号,我们不难发现,Fiber 架构同时兼容了同步渲染和异步渲染,如下图,决定同步还是异步取决于 mode

mode 决定同步异步

Render 阶段

performSyncWorkOnRoot 函数

核心逻辑在 renderRootSync 函数中

renderRootSync 函数

核心方法有俩个 prepareFreshStackworkLoopSync 函数

renderRootSync 逻辑

prepareFreshStack 函数

主要是有个方法 createWorkInProgress , 用来构建 workInProgress 双缓冲树,通过 alternate 相互指向

createWorkInProgress 构建 work-in-progress 树

当建立好双缓冲树的关系后,我们不难得到以下的关系图

双缓冲树关系图

workLoopSync 函数

当我们构建完 workInProgress Tree 的根节点时,建立 current tree 和 workInProgess Tree 的关联关系后,将进入 workLoopSync 调和阶段。

反复判断 workInProgress 是否为空,如果不为空,就执行 performUnitOfWork 方法 workLoopSync 逻辑

performUnitOfWork 函数

performUnitOfWork 函数的作用是 beginWork 优先创建子节点。 completeUnitOfWork 创建完子节点后判断是否有兄弟节点,有则创建兄弟节点,无则继续向上遍历父节点,直到遍历到根节点为止

performUnitOfWork 逻辑

beginWork 函数

参考文档

1 https://zhuanlan.zhihu.com/p/385319664 2

',58),q=[P];function F(S,y,W,v,w,x){return r(),o("div",null,q)}const U=e(R,[["render",F]]);export{C as __pageData,U as default}; diff --git "a/assets/guide_React_React\346\230\257\345\246\202\344\275\225\346\270\262\346\237\223\347\232\204.md.4ea938c9.lean.js" "b/assets/guide_React_React\346\230\257\345\246\202\344\275\225\346\270\262\346\237\223\347\232\204.md.ce1d2ec5.lean.js" similarity index 94% rename from "assets/guide_React_React\346\230\257\345\246\202\344\275\225\346\270\262\346\237\223\347\232\204.md.4ea938c9.lean.js" rename to "assets/guide_React_React\346\230\257\345\246\202\344\275\225\346\270\262\346\237\223\347\232\204.md.ce1d2ec5.lean.js" index 21d6e091..b2d7ea88 100644 --- "a/assets/guide_React_React\346\230\257\345\246\202\344\275\225\346\270\262\346\237\223\347\232\204.md.4ea938c9.lean.js" +++ "b/assets/guide_React_React\346\230\257\345\246\202\344\275\225\346\270\262\346\237\223\347\232\204.md.ce1d2ec5.lean.js" @@ -1 +1 @@ -import{_ as e,o as r,c as o,Q as t}from"./chunks/framework.b6910bb2.js";const a="/vitePress-blob/assets/3.9b1f9060.png",i="/vitePress-blob/assets/4.f4dd49d0.png",n="/vitePress-blob/assets/5.34ee565e.png",s="/vitePress-blob/assets/12.ba19c2aa.png",c="/vitePress-blob/assets/6.121ea6f5.png",l="/vitePress-blob/assets/7.3f678f52.png",p="/vitePress-blob/assets/8.9d04f238.png",d="/vitePress-blob/assets/9.bae86652.png",b="/vitePress-blob/assets/11.07a5666c.png",h="/vitePress-blob/assets/13.5bf5bc75.png",m="/vitePress-blob/assets/14.f1d70f78.png",u="/vitePress-blob/assets/16.4d6f740b.png",_="/vitePress-blob/assets/15.254fe341.png",f="/vitePress-blob/assets/18.09fcc54c.png",k="/vitePress-blob/assets/17.625ac807.png",g="/vitePress-blob/assets/19.77c3b0a6.png",C=JSON.parse('{"title":"React 是如何渲染的","description":"","frontmatter":{},"headers":[],"relativePath":"guide/React/React是如何渲染的.md","filePath":"guide/React/React是如何渲染的.md","lastUpdated":1718173557000}'),R={name:"guide/React/React是如何渲染的.md"},P=t("",58),q=[P];function F(S,y,W,v,w,x){return r(),o("div",null,q)}const U=e(R,[["render",F]]);export{C as __pageData,U as default}; +import{_ as e,o as r,c as o,Q as t}from"./chunks/framework.b6910bb2.js";const a="/vitePress-blob/assets/3.9b1f9060.png",i="/vitePress-blob/assets/4.f4dd49d0.png",n="/vitePress-blob/assets/5.34ee565e.png",s="/vitePress-blob/assets/12.ba19c2aa.png",c="/vitePress-blob/assets/6.121ea6f5.png",l="/vitePress-blob/assets/7.3f678f52.png",p="/vitePress-blob/assets/8.9d04f238.png",d="/vitePress-blob/assets/9.bae86652.png",b="/vitePress-blob/assets/11.07a5666c.png",h="/vitePress-blob/assets/13.5bf5bc75.png",m="/vitePress-blob/assets/14.f1d70f78.png",u="/vitePress-blob/assets/16.4d6f740b.png",_="/vitePress-blob/assets/15.254fe341.png",f="/vitePress-blob/assets/18.09fcc54c.png",k="/vitePress-blob/assets/17.625ac807.png",g="/vitePress-blob/assets/19.77c3b0a6.png",C=JSON.parse('{"title":"React 是如何渲染的","description":"","frontmatter":{},"headers":[],"relativePath":"guide/React/React是如何渲染的.md","filePath":"guide/React/React是如何渲染的.md","lastUpdated":1718174182000}'),R={name:"guide/React/React是如何渲染的.md"},P=t("",58),q=[P];function F(S,y,W,v,w,x){return r(),o("div",null,q)}const U=e(R,[["render",F]]);export{C as __pageData,U as default}; diff --git "a/assets/guide_React_React\347\273\204\344\273\266\346\230\257\345\246\202\344\275\225\351\200\232\344\277\241\347\232\204.md.05b07664.js" "b/assets/guide_React_React\347\273\204\344\273\266\346\230\257\345\246\202\344\275\225\351\200\232\344\277\241\347\232\204.md.3b62799c.js" similarity index 91% rename from "assets/guide_React_React\347\273\204\344\273\266\346\230\257\345\246\202\344\275\225\351\200\232\344\277\241\347\232\204.md.05b07664.js" rename to "assets/guide_React_React\347\273\204\344\273\266\346\230\257\345\246\202\344\275\225\351\200\232\344\277\241\347\232\204.md.3b62799c.js" index f6787d2c..b16af649 100644 --- "a/assets/guide_React_React\347\273\204\344\273\266\346\230\257\345\246\202\344\275\225\351\200\232\344\277\241\347\232\204.md.05b07664.js" +++ "b/assets/guide_React_React\347\273\204\344\273\266\346\230\257\345\246\202\344\275\225\351\200\232\344\277\241\347\232\204.md.3b62799c.js" @@ -1 +1 @@ -import{_ as a,o as t,c,k as e,a as r}from"./chunks/framework.b6910bb2.js";const f=JSON.parse('{"title":"React 组件是如何通信的","description":"","frontmatter":{},"headers":[],"relativePath":"guide/React/React组件是如何通信的.md","filePath":"guide/React/React组件是如何通信的.md","lastUpdated":1718173557000}'),s={name:"guide/React/React组件是如何通信的.md"},o=e("h1",{id:"react-组件是如何通信的",tabindex:"-1"},[r("React 组件是如何通信的 "),e("a",{class:"header-anchor",href:"#react-组件是如何通信的","aria-label":'Permalink to "React 组件是如何通信的"'},"​")],-1),_=[o];function d(n,i,l,p,h,m){return t(),c("div",null,_)}const u=a(s,[["render",d]]);export{f as __pageData,u as default}; +import{_ as a,o as t,c,k as e,a as r}from"./chunks/framework.b6910bb2.js";const f=JSON.parse('{"title":"React 组件是如何通信的","description":"","frontmatter":{},"headers":[],"relativePath":"guide/React/React组件是如何通信的.md","filePath":"guide/React/React组件是如何通信的.md","lastUpdated":1718174182000}'),s={name:"guide/React/React组件是如何通信的.md"},o=e("h1",{id:"react-组件是如何通信的",tabindex:"-1"},[r("React 组件是如何通信的 "),e("a",{class:"header-anchor",href:"#react-组件是如何通信的","aria-label":'Permalink to "React 组件是如何通信的"'},"​")],-1),_=[o];function d(n,i,l,p,h,m){return t(),c("div",null,_)}const u=a(s,[["render",d]]);export{f as __pageData,u as default}; diff --git "a/assets/guide_React_React\347\273\204\344\273\266\346\230\257\345\246\202\344\275\225\351\200\232\344\277\241\347\232\204.md.05b07664.lean.js" "b/assets/guide_React_React\347\273\204\344\273\266\346\230\257\345\246\202\344\275\225\351\200\232\344\277\241\347\232\204.md.3b62799c.lean.js" similarity index 91% rename from "assets/guide_React_React\347\273\204\344\273\266\346\230\257\345\246\202\344\275\225\351\200\232\344\277\241\347\232\204.md.05b07664.lean.js" rename to "assets/guide_React_React\347\273\204\344\273\266\346\230\257\345\246\202\344\275\225\351\200\232\344\277\241\347\232\204.md.3b62799c.lean.js" index f6787d2c..b16af649 100644 --- "a/assets/guide_React_React\347\273\204\344\273\266\346\230\257\345\246\202\344\275\225\351\200\232\344\277\241\347\232\204.md.05b07664.lean.js" +++ "b/assets/guide_React_React\347\273\204\344\273\266\346\230\257\345\246\202\344\275\225\351\200\232\344\277\241\347\232\204.md.3b62799c.lean.js" @@ -1 +1 @@ -import{_ as a,o as t,c,k as e,a as r}from"./chunks/framework.b6910bb2.js";const f=JSON.parse('{"title":"React 组件是如何通信的","description":"","frontmatter":{},"headers":[],"relativePath":"guide/React/React组件是如何通信的.md","filePath":"guide/React/React组件是如何通信的.md","lastUpdated":1718173557000}'),s={name:"guide/React/React组件是如何通信的.md"},o=e("h1",{id:"react-组件是如何通信的",tabindex:"-1"},[r("React 组件是如何通信的 "),e("a",{class:"header-anchor",href:"#react-组件是如何通信的","aria-label":'Permalink to "React 组件是如何通信的"'},"​")],-1),_=[o];function d(n,i,l,p,h,m){return t(),c("div",null,_)}const u=a(s,[["render",d]]);export{f as __pageData,u as default}; +import{_ as a,o as t,c,k as e,a as r}from"./chunks/framework.b6910bb2.js";const f=JSON.parse('{"title":"React 组件是如何通信的","description":"","frontmatter":{},"headers":[],"relativePath":"guide/React/React组件是如何通信的.md","filePath":"guide/React/React组件是如何通信的.md","lastUpdated":1718174182000}'),s={name:"guide/React/React组件是如何通信的.md"},o=e("h1",{id:"react-组件是如何通信的",tabindex:"-1"},[r("React 组件是如何通信的 "),e("a",{class:"header-anchor",href:"#react-组件是如何通信的","aria-label":'Permalink to "React 组件是如何通信的"'},"​")],-1),_=[o];function d(n,i,l,p,h,m){return t(),c("div",null,_)}const u=a(s,[["render",d]]);export{f as __pageData,u as default}; diff --git "a/assets/guide_React_diff\347\256\227\346\263\225.md.e6203201.js" "b/assets/guide_React_diff\347\256\227\346\263\225.md.0ae563f7.js" similarity index 98% rename from "assets/guide_React_diff\347\256\227\346\263\225.md.e6203201.js" rename to "assets/guide_React_diff\347\256\227\346\263\225.md.0ae563f7.js" index ca3e5daf..9c9e9017 100644 --- "a/assets/guide_React_diff\347\256\227\346\263\225.md.e6203201.js" +++ "b/assets/guide_React_diff\347\256\227\346\263\225.md.0ae563f7.js" @@ -1 +1 @@ -import{_ as e,o as a,c as t,Q as i}from"./chunks/framework.b6910bb2.js";const k=JSON.parse('{"title":"React 中的 Diff 算法","description":"","frontmatter":{},"headers":[],"relativePath":"guide/React/diff算法.md","filePath":"guide/React/diff算法.md","lastUpdated":1718173557000}'),d={name:"guide/React/diff算法.md"},r=i('

React 中的 Diff 算法

概要

React Diff 算法主要分单节点和多节点 Diff 算法 在单节点 Diff 算法中,会对比 key 和 tag 是否可以复用 如果 key 和 tag 都相同时,复用当前的 Fiber 节点,标记其他 Fiber 节点为删除 如果 key 不相同,标记删除当前的 Fiber 节点,对比下一个节点 如果 key 相同、tag 不同,则标记删除所有 Fiber 节点,生成新的 Fiber 节点

在多节点 Diff 中,有俩个 for 循环,第一个 for 循环判断可以复用的节点,记录最后可复用节点的 lastIndex 位置

通过 Map 建立节点和下标的对应关系,如果新节点的key可以在 Map 中找到,则复用旧节点,并判断新节点下标和 lastIndex 下标的关系, 如果新节点下标 > lastIndex 下标,说明只需要更新节点,不需要移动位置,更新 lastIndex。 如果新节点下标 < lastIndex,说明需要更新移动位置,不需要更新 lastIndex。

单节点diff算法 (render方法创建的element元素子节点只有一个)

1. 旧节点不存在

  1. 如果旧节点不存在,则直接新增节点

2. 旧节点存在

1 判断 key 和 tag 是否相同,相同则复用节点,更新属性 2 如果 key 相同但 tag 不相同,则删除所有节点 3 如果 key、tag 不同,则不需要复用,旧节点标记为删除

多节点diff算法 (render方法创建的element元素子节点有多个)

多节点diff有俩次 for 循环, 第一次 for 循环判断元素是否需要更新,第二次 for 循环判断元素是否需要移动位置

1 第一次 for 循环比较key和tag, 如果相同则复用, 并用 lastIndex 标记当前可以复用的节点位置

2 遇到不相同时, 跳出第一层 for 循环, 创建一个 Map 对象, 存储旧节点的 key 和 index

  • key不同导致不可复用,立即跳出整个遍历,第一轮遍历结束
  • key 相同 type 不同导致不可复用,会将 oldFiber 标记为 DELETION,并继续遍历

3 在 Map 对象中查找新节点的 key, 如果存在, 则说明新节点可以复用旧节点, 并且判断是否需要移动位置

4 如果 index > lastIndex, 则不需要移动位置, 更新 lastIndex

5 如果 index < lastIndex, 则需要移动位置, 不需要更新 lastIndex

',18),n=[r];function l(o,f,s,h,x,c){return a(),t("div",null,n)}const p=e(d,[["render",l]]);export{k as __pageData,p as default}; +import{_ as e,o as a,c as t,Q as i}from"./chunks/framework.b6910bb2.js";const k=JSON.parse('{"title":"React 中的 Diff 算法","description":"","frontmatter":{},"headers":[],"relativePath":"guide/React/diff算法.md","filePath":"guide/React/diff算法.md","lastUpdated":1718174182000}'),d={name:"guide/React/diff算法.md"},r=i('

React 中的 Diff 算法

概要

React Diff 算法主要分单节点和多节点 Diff 算法 在单节点 Diff 算法中,会对比 key 和 tag 是否可以复用 如果 key 和 tag 都相同时,复用当前的 Fiber 节点,标记其他 Fiber 节点为删除 如果 key 不相同,标记删除当前的 Fiber 节点,对比下一个节点 如果 key 相同、tag 不同,则标记删除所有 Fiber 节点,生成新的 Fiber 节点

在多节点 Diff 中,有俩个 for 循环,第一个 for 循环判断可以复用的节点,记录最后可复用节点的 lastIndex 位置

通过 Map 建立节点和下标的对应关系,如果新节点的key可以在 Map 中找到,则复用旧节点,并判断新节点下标和 lastIndex 下标的关系, 如果新节点下标 > lastIndex 下标,说明只需要更新节点,不需要移动位置,更新 lastIndex。 如果新节点下标 < lastIndex,说明需要更新移动位置,不需要更新 lastIndex。

单节点diff算法 (render方法创建的element元素子节点只有一个)

1. 旧节点不存在

  1. 如果旧节点不存在,则直接新增节点

2. 旧节点存在

1 判断 key 和 tag 是否相同,相同则复用节点,更新属性 2 如果 key 相同但 tag 不相同,则删除所有节点 3 如果 key、tag 不同,则不需要复用,旧节点标记为删除

多节点diff算法 (render方法创建的element元素子节点有多个)

多节点diff有俩次 for 循环, 第一次 for 循环判断元素是否需要更新,第二次 for 循环判断元素是否需要移动位置

1 第一次 for 循环比较key和tag, 如果相同则复用, 并用 lastIndex 标记当前可以复用的节点位置

2 遇到不相同时, 跳出第一层 for 循环, 创建一个 Map 对象, 存储旧节点的 key 和 index

  • key不同导致不可复用,立即跳出整个遍历,第一轮遍历结束
  • key 相同 type 不同导致不可复用,会将 oldFiber 标记为 DELETION,并继续遍历

3 在 Map 对象中查找新节点的 key, 如果存在, 则说明新节点可以复用旧节点, 并且判断是否需要移动位置

4 如果 index > lastIndex, 则不需要移动位置, 更新 lastIndex

5 如果 index < lastIndex, 则需要移动位置, 不需要更新 lastIndex

',18),n=[r];function l(o,f,s,h,x,c){return a(),t("div",null,n)}const p=e(d,[["render",l]]);export{k as __pageData,p as default}; diff --git "a/assets/guide_React_diff\347\256\227\346\263\225.md.e6203201.lean.js" "b/assets/guide_React_diff\347\256\227\346\263\225.md.0ae563f7.lean.js" similarity index 86% rename from "assets/guide_React_diff\347\256\227\346\263\225.md.e6203201.lean.js" rename to "assets/guide_React_diff\347\256\227\346\263\225.md.0ae563f7.lean.js" index b9cc1866..bf8ac253 100644 --- "a/assets/guide_React_diff\347\256\227\346\263\225.md.e6203201.lean.js" +++ "b/assets/guide_React_diff\347\256\227\346\263\225.md.0ae563f7.lean.js" @@ -1 +1 @@ -import{_ as e,o as a,c as t,Q as i}from"./chunks/framework.b6910bb2.js";const k=JSON.parse('{"title":"React 中的 Diff 算法","description":"","frontmatter":{},"headers":[],"relativePath":"guide/React/diff算法.md","filePath":"guide/React/diff算法.md","lastUpdated":1718173557000}'),d={name:"guide/React/diff算法.md"},r=i("",18),n=[r];function l(o,f,s,h,x,c){return a(),t("div",null,n)}const p=e(d,[["render",l]]);export{k as __pageData,p as default}; +import{_ as e,o as a,c as t,Q as i}from"./chunks/framework.b6910bb2.js";const k=JSON.parse('{"title":"React 中的 Diff 算法","description":"","frontmatter":{},"headers":[],"relativePath":"guide/React/diff算法.md","filePath":"guide/React/diff算法.md","lastUpdated":1718174182000}'),d={name:"guide/React/diff算法.md"},r=i("",18),n=[r];function l(o,f,s,h,x,c){return a(),t("div",null,n)}const p=e(d,[["render",l]]);export{k as __pageData,p as default}; diff --git "a/assets/guide_React_react\345\274\202\345\270\270\346\234\272\345\210\266.md.8d2560d6.js" "b/assets/guide_React_react\345\274\202\345\270\270\346\234\272\345\210\266.md.c399b96d.js" similarity index 84% rename from "assets/guide_React_react\345\274\202\345\270\270\346\234\272\345\210\266.md.8d2560d6.js" rename to "assets/guide_React_react\345\274\202\345\270\270\346\234\272\345\210\266.md.c399b96d.js" index 25dcf765..ffc4ceeb 100644 --- "a/assets/guide_React_react\345\274\202\345\270\270\346\234\272\345\210\266.md.8d2560d6.js" +++ "b/assets/guide_React_react\345\274\202\345\270\270\346\234\272\345\210\266.md.c399b96d.js" @@ -1 +1 @@ -import{_ as e,o as t,c as a}from"./chunks/framework.b6910bb2.js";const m=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"guide/React/react异常机制.md","filePath":"guide/React/react异常机制.md","lastUpdated":1718173557000}'),c={name:"guide/React/react异常机制.md"};function r(o,s,d,n,_,i){return t(),a("div")}const f=e(c,[["render",r]]);export{m as __pageData,f as default}; +import{_ as e,o as t,c as a}from"./chunks/framework.b6910bb2.js";const m=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"guide/React/react异常机制.md","filePath":"guide/React/react异常机制.md","lastUpdated":1718174182000}'),c={name:"guide/React/react异常机制.md"};function r(o,s,d,n,_,i){return t(),a("div")}const f=e(c,[["render",r]]);export{m as __pageData,f as default}; diff --git "a/assets/guide_React_react\345\274\202\345\270\270\346\234\272\345\210\266.md.8d2560d6.lean.js" "b/assets/guide_React_react\345\274\202\345\270\270\346\234\272\345\210\266.md.c399b96d.lean.js" similarity index 84% rename from "assets/guide_React_react\345\274\202\345\270\270\346\234\272\345\210\266.md.8d2560d6.lean.js" rename to "assets/guide_React_react\345\274\202\345\270\270\346\234\272\345\210\266.md.c399b96d.lean.js" index 25dcf765..ffc4ceeb 100644 --- "a/assets/guide_React_react\345\274\202\345\270\270\346\234\272\345\210\266.md.8d2560d6.lean.js" +++ "b/assets/guide_React_react\345\274\202\345\270\270\346\234\272\345\210\266.md.c399b96d.lean.js" @@ -1 +1 @@ -import{_ as e,o as t,c as a}from"./chunks/framework.b6910bb2.js";const m=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"guide/React/react异常机制.md","filePath":"guide/React/react异常机制.md","lastUpdated":1718173557000}'),c={name:"guide/React/react异常机制.md"};function r(o,s,d,n,_,i){return t(),a("div")}const f=e(c,[["render",r]]);export{m as __pageData,f as default}; +import{_ as e,o as t,c as a}from"./chunks/framework.b6910bb2.js";const m=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"guide/React/react异常机制.md","filePath":"guide/React/react异常机制.md","lastUpdated":1718174182000}'),c={name:"guide/React/react异常机制.md"};function r(o,s,d,n,_,i){return t(),a("div")}const f=e(c,[["render",r]]);export{m as __pageData,f as default}; diff --git "a/assets/guide_React_setState\346\230\257\345\220\214\346\255\245\350\277\230\346\230\257\345\274\202\346\255\245\347\232\204.md.6d744533.js" "b/assets/guide_React_setState\346\230\257\345\220\214\346\255\245\350\277\230\346\230\257\345\274\202\346\255\245\347\232\204.md.cb4f6c10.js" similarity index 99% rename from "assets/guide_React_setState\346\230\257\345\220\214\346\255\245\350\277\230\346\230\257\345\274\202\346\255\245\347\232\204.md.6d744533.js" rename to "assets/guide_React_setState\346\230\257\345\220\214\346\255\245\350\277\230\346\230\257\345\274\202\346\255\245\347\232\204.md.cb4f6c10.js" index 44b10786..0d08e2c3 100644 --- "a/assets/guide_React_setState\346\230\257\345\220\214\346\255\245\350\277\230\346\230\257\345\274\202\346\255\245\347\232\204.md.6d744533.js" +++ "b/assets/guide_React_setState\346\230\257\345\220\214\346\255\245\350\277\230\346\230\257\345\274\202\346\255\245\347\232\204.md.cb4f6c10.js" @@ -1,4 +1,4 @@ -import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.b6910bb2.js";const p="/vitePress-blob/assets/1.5e4dabab.png",h=JSON.parse('{"title":"setState 是同步还是异步的?","description":"","frontmatter":{},"headers":[],"relativePath":"guide/React/setState是同步还是异步的.md","filePath":"guide/React/setState是同步还是异步的.md","lastUpdated":1718173557000}'),o={name:"guide/React/setState是同步还是异步的.md"},e=l('

setState 是同步还是异步的?

概要

setState 用于状态变更,触发组件的重新渲染,更新视图。

在 React 18 以前,setState 同步还是异步取决于是否处于 isBatchUpdates 字段,true 的话就是异步,否则就是同步

在 React 18 版本所有的 setState 都是异步批量操作

setState

js
// React 15
+import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.b6910bb2.js";const p="/vitePress-blob/assets/1.5e4dabab.png",h=JSON.parse('{"title":"setState 是同步还是异步的?","description":"","frontmatter":{},"headers":[],"relativePath":"guide/React/setState是同步还是异步的.md","filePath":"guide/React/setState是同步还是异步的.md","lastUpdated":1718174182000}'),o={name:"guide/React/setState是同步还是异步的.md"},e=l('

setState 是同步还是异步的?

概要

setState 用于状态变更,触发组件的重新渲染,更新视图。

在 React 18 以前,setState 同步还是异步取决于是否处于 isBatchUpdates 字段,true 的话就是异步,否则就是同步

在 React 18 版本所有的 setState 都是异步批量操作

setState

js
// React 15
 function enqueueUpdate (component) {
   // isBatchingUpdates 判断当前是否处理批量更新操作
   if (!batchingStrategy.isBatchingUpdates) { // 锁管理器
diff --git "a/assets/guide_React_setState\346\230\257\345\220\214\346\255\245\350\277\230\346\230\257\345\274\202\346\255\245\347\232\204.md.6d744533.lean.js" "b/assets/guide_React_setState\346\230\257\345\220\214\346\255\245\350\277\230\346\230\257\345\274\202\346\255\245\347\232\204.md.cb4f6c10.lean.js"
similarity index 88%
rename from "assets/guide_React_setState\346\230\257\345\220\214\346\255\245\350\277\230\346\230\257\345\274\202\346\255\245\347\232\204.md.6d744533.lean.js"
rename to "assets/guide_React_setState\346\230\257\345\220\214\346\255\245\350\277\230\346\230\257\345\274\202\346\255\245\347\232\204.md.cb4f6c10.lean.js"
index a689fc50..ea7ad8ae 100644
--- "a/assets/guide_React_setState\346\230\257\345\220\214\346\255\245\350\277\230\346\230\257\345\274\202\346\255\245\347\232\204.md.6d744533.lean.js"
+++ "b/assets/guide_React_setState\346\230\257\345\220\214\346\255\245\350\277\230\346\230\257\345\274\202\346\255\245\347\232\204.md.cb4f6c10.lean.js"
@@ -1 +1 @@
-import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.b6910bb2.js";const p="/vitePress-blob/assets/1.5e4dabab.png",h=JSON.parse('{"title":"setState 是同步还是异步的?","description":"","frontmatter":{},"headers":[],"relativePath":"guide/React/setState是同步还是异步的.md","filePath":"guide/React/setState是同步还是异步的.md","lastUpdated":1718173557000}'),o={name:"guide/React/setState是同步还是异步的.md"},e=l("",35),t=[e];function c(r,E,y,i,F,d){return n(),a("div",null,t)}const C=s(o,[["render",c]]);export{h as __pageData,C as default};
+import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.b6910bb2.js";const p="/vitePress-blob/assets/1.5e4dabab.png",h=JSON.parse('{"title":"setState 是同步还是异步的?","description":"","frontmatter":{},"headers":[],"relativePath":"guide/React/setState是同步还是异步的.md","filePath":"guide/React/setState是同步还是异步的.md","lastUpdated":1718174182000}'),o={name:"guide/React/setState是同步还是异步的.md"},e=l("",35),t=[e];function c(r,E,y,i,F,d){return n(),a("div",null,t)}const C=s(o,[["render",c]]);export{h as __pageData,C as default};
diff --git "a/assets/guide_React_\344\273\200\344\271\210\346\230\257Fiber.md.ff48a654.js" "b/assets/guide_React_\344\273\200\344\271\210\346\230\257Fiber.md.c7d34c1a.js"
similarity index 96%
rename from "assets/guide_React_\344\273\200\344\271\210\346\230\257Fiber.md.ff48a654.js"
rename to "assets/guide_React_\344\273\200\344\271\210\346\230\257Fiber.md.c7d34c1a.js"
index e0595f33..ba35ba26 100644
--- "a/assets/guide_React_\344\273\200\344\271\210\346\230\257Fiber.md.ff48a654.js"
+++ "b/assets/guide_React_\344\273\200\344\271\210\346\230\257Fiber.md.c7d34c1a.js"
@@ -1 +1 @@
-import{_ as e,o as t,c as o,Q as c}from"./chunks/framework.b6910bb2.js";const f=JSON.parse('{"title":"对 Fiber 的理解","description":"","frontmatter":{},"headers":[],"relativePath":"guide/React/什么是Fiber.md","filePath":"guide/React/什么是Fiber.md","lastUpdated":1718173557000}'),r={name:"guide/React/什么是Fiber.md"},a=c('

对 Fiber 的理解

在 React 15 中通过 递归 的形式进行对比,找到需要更新的节点,并同步更新它,在这段时间一直占据着浏览器主线程,可能会给用户带来卡顿的感受(在渲染进程中,js线程和渲染线程是互斥的

在 React 15 以后引入了 Fiber 架构,将对比的过程变成了异步可中断的过程,让出浏览器的使用权,让浏览器处理更高优先级的事情

Fiber 的调和过程(Reconciler)由分成了 beginWork 阶段 和 completeUnitOfWork 阶段。

beginWork 阶段自顶向下,根据当前工作的 Fiber 节点最新的 React Element 子元素与旧 Fiber 节点进行对比,决定是否需要复用旧 Fiber 节点并标记 Fiber 节点是否有副作用。

compeleteUnitOfWork 阶段自底向上构建副作用链表,生成的 DOM 节点挂在 Fiber 的 stateNode 属性

',6),i=[a];function d(_,n,s,p,b,l){return t(),o("div",null,i)}const m=e(r,[["render",d]]);export{f as __pageData,m as default}; +import{_ as e,o as t,c as o,Q as c}from"./chunks/framework.b6910bb2.js";const f=JSON.parse('{"title":"对 Fiber 的理解","description":"","frontmatter":{},"headers":[],"relativePath":"guide/React/什么是Fiber.md","filePath":"guide/React/什么是Fiber.md","lastUpdated":1718174182000}'),r={name:"guide/React/什么是Fiber.md"},a=c('

对 Fiber 的理解

在 React 15 中通过 递归 的形式进行对比,找到需要更新的节点,并同步更新它,在这段时间一直占据着浏览器主线程,可能会给用户带来卡顿的感受(在渲染进程中,js线程和渲染线程是互斥的

在 React 15 以后引入了 Fiber 架构,将对比的过程变成了异步可中断的过程,让出浏览器的使用权,让浏览器处理更高优先级的事情

Fiber 的调和过程(Reconciler)由分成了 beginWork 阶段 和 completeUnitOfWork 阶段。

beginWork 阶段自顶向下,根据当前工作的 Fiber 节点最新的 React Element 子元素与旧 Fiber 节点进行对比,决定是否需要复用旧 Fiber 节点并标记 Fiber 节点是否有副作用。

compeleteUnitOfWork 阶段自底向上构建副作用链表,生成的 DOM 节点挂在 Fiber 的 stateNode 属性

',6),i=[a];function d(_,n,s,p,b,l){return t(),o("div",null,i)}const m=e(r,[["render",d]]);export{f as __pageData,m as default}; diff --git "a/assets/guide_React_\344\273\200\344\271\210\346\230\257Fiber.md.ff48a654.lean.js" "b/assets/guide_React_\344\273\200\344\271\210\346\230\257Fiber.md.c7d34c1a.lean.js" similarity index 86% rename from "assets/guide_React_\344\273\200\344\271\210\346\230\257Fiber.md.ff48a654.lean.js" rename to "assets/guide_React_\344\273\200\344\271\210\346\230\257Fiber.md.c7d34c1a.lean.js" index 98e0b404..7e9311a6 100644 --- "a/assets/guide_React_\344\273\200\344\271\210\346\230\257Fiber.md.ff48a654.lean.js" +++ "b/assets/guide_React_\344\273\200\344\271\210\346\230\257Fiber.md.c7d34c1a.lean.js" @@ -1 +1 @@ -import{_ as e,o as t,c as o,Q as c}from"./chunks/framework.b6910bb2.js";const f=JSON.parse('{"title":"对 Fiber 的理解","description":"","frontmatter":{},"headers":[],"relativePath":"guide/React/什么是Fiber.md","filePath":"guide/React/什么是Fiber.md","lastUpdated":1718173557000}'),r={name:"guide/React/什么是Fiber.md"},a=c("",6),i=[a];function d(_,n,s,p,b,l){return t(),o("div",null,i)}const m=e(r,[["render",d]]);export{f as __pageData,m as default}; +import{_ as e,o as t,c as o,Q as c}from"./chunks/framework.b6910bb2.js";const f=JSON.parse('{"title":"对 Fiber 的理解","description":"","frontmatter":{},"headers":[],"relativePath":"guide/React/什么是Fiber.md","filePath":"guide/React/什么是Fiber.md","lastUpdated":1718174182000}'),r={name:"guide/React/什么是Fiber.md"},a=c("",6),i=[a];function d(_,n,s,p,b,l){return t(),o("div",null,i)}const m=e(r,[["render",d]]);export{f as __pageData,m as default}; diff --git "a/assets/guide_React_\345\246\202\344\275\225\350\256\276\350\256\241React\347\273\204\344\273\266.md.b55050d7.js" "b/assets/guide_React_\345\246\202\344\275\225\350\256\276\350\256\241React\347\273\204\344\273\266.md.a3612843.js" similarity index 95% rename from "assets/guide_React_\345\246\202\344\275\225\350\256\276\350\256\241React\347\273\204\344\273\266.md.b55050d7.js" rename to "assets/guide_React_\345\246\202\344\275\225\350\256\276\350\256\241React\347\273\204\344\273\266.md.a3612843.js" index f4ff968d..383f74d6 100644 --- "a/assets/guide_React_\345\246\202\344\275\225\350\256\276\350\256\241React\347\273\204\344\273\266.md.b55050d7.js" +++ "b/assets/guide_React_\345\246\202\344\275\225\350\256\276\350\256\241React\347\273\204\344\273\266.md.a3612843.js" @@ -1 +1 @@ -import{_ as a,o as e,c as t,Q as r}from"./chunks/framework.b6910bb2.js";const o="/vitePress-blob/assets/1.df8894ba.png",f=JSON.parse('{"title":"如何设计 React 组件","description":"","frontmatter":{},"headers":[],"relativePath":"guide/React/如何设计React组件.md","filePath":"guide/React/如何设计React组件.md","lastUpdated":1718173557000}'),c={name:"guide/React/如何设计React组件.md"},s=r('

如何设计 React 组件

设计分类

  • 展示组件: 只负责 UI 展示,不涉及业务逻辑

  • 业务组件: 复用负责业务逻辑

展示组件

展示组件一般受制于 props, 具有通用性、复用性

业务组件

业务组件一般受制于 state, 具有复用性

组件分类

',8),i=[s];function _(l,n,d,h,p,u){return e(),t("div",null,i)}const b=a(c,[["render",_]]);export{f as __pageData,b as default}; +import{_ as a,o as e,c as t,Q as r}from"./chunks/framework.b6910bb2.js";const o="/vitePress-blob/assets/1.df8894ba.png",f=JSON.parse('{"title":"如何设计 React 组件","description":"","frontmatter":{},"headers":[],"relativePath":"guide/React/如何设计React组件.md","filePath":"guide/React/如何设计React组件.md","lastUpdated":1718174182000}'),c={name:"guide/React/如何设计React组件.md"},s=r('

如何设计 React 组件

设计分类

  • 展示组件: 只负责 UI 展示,不涉及业务逻辑

  • 业务组件: 复用负责业务逻辑

展示组件

展示组件一般受制于 props, 具有通用性、复用性

业务组件

业务组件一般受制于 state, 具有复用性

组件分类

',8),i=[s];function _(l,n,d,h,p,u){return e(),t("div",null,i)}const b=a(c,[["render",_]]);export{f as __pageData,b as default}; diff --git "a/assets/guide_React_\345\246\202\344\275\225\350\256\276\350\256\241React\347\273\204\344\273\266.md.b55050d7.lean.js" "b/assets/guide_React_\345\246\202\344\275\225\350\256\276\350\256\241React\347\273\204\344\273\266.md.a3612843.lean.js" similarity index 88% rename from "assets/guide_React_\345\246\202\344\275\225\350\256\276\350\256\241React\347\273\204\344\273\266.md.b55050d7.lean.js" rename to "assets/guide_React_\345\246\202\344\275\225\350\256\276\350\256\241React\347\273\204\344\273\266.md.a3612843.lean.js" index efaa1001..641bf412 100644 --- "a/assets/guide_React_\345\246\202\344\275\225\350\256\276\350\256\241React\347\273\204\344\273\266.md.b55050d7.lean.js" +++ "b/assets/guide_React_\345\246\202\344\275\225\350\256\276\350\256\241React\347\273\204\344\273\266.md.a3612843.lean.js" @@ -1 +1 @@ -import{_ as a,o as e,c as t,Q as r}from"./chunks/framework.b6910bb2.js";const o="/vitePress-blob/assets/1.df8894ba.png",f=JSON.parse('{"title":"如何设计 React 组件","description":"","frontmatter":{},"headers":[],"relativePath":"guide/React/如何设计React组件.md","filePath":"guide/React/如何设计React组件.md","lastUpdated":1718173557000}'),c={name:"guide/React/如何设计React组件.md"},s=r("",8),i=[s];function _(l,n,d,h,p,u){return e(),t("div",null,i)}const b=a(c,[["render",_]]);export{f as __pageData,b as default}; +import{_ as a,o as e,c as t,Q as r}from"./chunks/framework.b6910bb2.js";const o="/vitePress-blob/assets/1.df8894ba.png",f=JSON.parse('{"title":"如何设计 React 组件","description":"","frontmatter":{},"headers":[],"relativePath":"guide/React/如何设计React组件.md","filePath":"guide/React/如何设计React组件.md","lastUpdated":1718174182000}'),c={name:"guide/React/如何设计React组件.md"},s=r("",8),i=[s];function _(l,n,d,h,p,u){return e(),t("div",null,i)}const b=a(c,[["render",_]]);export{f as __pageData,b as default}; diff --git "a/assets/guide_React_\345\270\270\350\247\201\347\232\204\351\227\256\351\242\230.md.0a97b65b.js" "b/assets/guide_React_\345\270\270\350\247\201\347\232\204\351\227\256\351\242\230.md.49923c54.js" similarity index 91% rename from "assets/guide_React_\345\270\270\350\247\201\347\232\204\351\227\256\351\242\230.md.0a97b65b.js" rename to "assets/guide_React_\345\270\270\350\247\201\347\232\204\351\227\256\351\242\230.md.49923c54.js" index 16ae0d1a..dd495ec6 100644 --- "a/assets/guide_React_\345\270\270\350\247\201\347\232\204\351\227\256\351\242\230.md.0a97b65b.js" +++ "b/assets/guide_React_\345\270\270\350\247\201\347\232\204\351\227\256\351\242\230.md.49923c54.js" @@ -1 +1 @@ -import{_ as a,o as t,c as r,k as e,a as s}from"./chunks/framework.b6910bb2.js";const x=JSON.parse('{"title":"常见的问题","description":"","frontmatter":{},"headers":[],"relativePath":"guide/React/常见的问题.md","filePath":"guide/React/常见的问题.md","lastUpdated":1718173557000}'),o={name:"guide/React/常见的问题.md"},c=e("h1",{id:"常见的问题",tabindex:"-1"},[s("常见的问题 "),e("a",{class:"header-anchor",href:"#常见的问题","aria-label":'Permalink to "常见的问题"'},"​")],-1),d=e("h2",{id:"",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#","aria-label":'Permalink to ""'},"​")],-1),n=[c,d];function i(_,l,h,p,m,f){return t(),r("div",null,n)}const k=a(o,[["render",i]]);export{x as __pageData,k as default}; +import{_ as a,o as t,c as r,k as e,a as s}from"./chunks/framework.b6910bb2.js";const x=JSON.parse('{"title":"常见的问题","description":"","frontmatter":{},"headers":[],"relativePath":"guide/React/常见的问题.md","filePath":"guide/React/常见的问题.md","lastUpdated":1718174182000}'),o={name:"guide/React/常见的问题.md"},c=e("h1",{id:"常见的问题",tabindex:"-1"},[s("常见的问题 "),e("a",{class:"header-anchor",href:"#常见的问题","aria-label":'Permalink to "常见的问题"'},"​")],-1),d=e("h2",{id:"",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#","aria-label":'Permalink to ""'},"​")],-1),n=[c,d];function i(_,l,h,p,m,f){return t(),r("div",null,n)}const k=a(o,[["render",i]]);export{x as __pageData,k as default}; diff --git "a/assets/guide_React_\345\270\270\350\247\201\347\232\204\351\227\256\351\242\230.md.0a97b65b.lean.js" "b/assets/guide_React_\345\270\270\350\247\201\347\232\204\351\227\256\351\242\230.md.49923c54.lean.js" similarity index 91% rename from "assets/guide_React_\345\270\270\350\247\201\347\232\204\351\227\256\351\242\230.md.0a97b65b.lean.js" rename to "assets/guide_React_\345\270\270\350\247\201\347\232\204\351\227\256\351\242\230.md.49923c54.lean.js" index 16ae0d1a..dd495ec6 100644 --- "a/assets/guide_React_\345\270\270\350\247\201\347\232\204\351\227\256\351\242\230.md.0a97b65b.lean.js" +++ "b/assets/guide_React_\345\270\270\350\247\201\347\232\204\351\227\256\351\242\230.md.49923c54.lean.js" @@ -1 +1 @@ -import{_ as a,o as t,c as r,k as e,a as s}from"./chunks/framework.b6910bb2.js";const x=JSON.parse('{"title":"常见的问题","description":"","frontmatter":{},"headers":[],"relativePath":"guide/React/常见的问题.md","filePath":"guide/React/常见的问题.md","lastUpdated":1718173557000}'),o={name:"guide/React/常见的问题.md"},c=e("h1",{id:"常见的问题",tabindex:"-1"},[s("常见的问题 "),e("a",{class:"header-anchor",href:"#常见的问题","aria-label":'Permalink to "常见的问题"'},"​")],-1),d=e("h2",{id:"",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#","aria-label":'Permalink to ""'},"​")],-1),n=[c,d];function i(_,l,h,p,m,f){return t(),r("div",null,n)}const k=a(o,[["render",i]]);export{x as __pageData,k as default}; +import{_ as a,o as t,c as r,k as e,a as s}from"./chunks/framework.b6910bb2.js";const x=JSON.parse('{"title":"常见的问题","description":"","frontmatter":{},"headers":[],"relativePath":"guide/React/常见的问题.md","filePath":"guide/React/常见的问题.md","lastUpdated":1718174182000}'),o={name:"guide/React/常见的问题.md"},c=e("h1",{id:"常见的问题",tabindex:"-1"},[s("常见的问题 "),e("a",{class:"header-anchor",href:"#常见的问题","aria-label":'Permalink to "常见的问题"'},"​")],-1),d=e("h2",{id:"",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#","aria-label":'Permalink to ""'},"​")],-1),n=[c,d];function i(_,l,h,p,m,f){return t(),r("div",null,n)}const k=a(o,[["render",i]]);export{x as __pageData,k as default}; diff --git "a/assets/guide_Redux_\346\272\220\347\240\201\350\247\243\350\257\273.md.a16d34cb.js" "b/assets/guide_Redux_\346\272\220\347\240\201\350\247\243\350\257\273.md.25f8a90e.js" similarity index 89% rename from "assets/guide_Redux_\346\272\220\347\240\201\350\247\243\350\257\273.md.a16d34cb.js" rename to "assets/guide_Redux_\346\272\220\347\240\201\350\247\243\350\257\273.md.25f8a90e.js" index dcaf5bb6..dda60a63 100644 --- "a/assets/guide_Redux_\346\272\220\347\240\201\350\247\243\350\257\273.md.a16d34cb.js" +++ "b/assets/guide_Redux_\346\272\220\347\240\201\350\247\243\350\257\273.md.25f8a90e.js" @@ -1 +1 @@ -import{_ as a,o as t,c as s,k as e,a as d}from"./chunks/framework.b6910bb2.js";const f=JSON.parse('{"title":"源码解读","description":"","frontmatter":{},"headers":[],"relativePath":"guide/Redux/源码解读.md","filePath":"guide/Redux/源码解读.md","lastUpdated":1718173557000}'),o={name:"guide/Redux/源码解读.md"},r=e("h1",{id:"源码解读",tabindex:"-1"},[d("源码解读 "),e("a",{class:"header-anchor",href:"#源码解读","aria-label":'Permalink to "源码解读"'},"​")],-1),c=[r];function n(i,_,l,p,u,h){return t(),s("div",null,c)}const x=a(o,[["render",n]]);export{f as __pageData,x as default}; +import{_ as a,o as t,c as s,k as e,a as d}from"./chunks/framework.b6910bb2.js";const f=JSON.parse('{"title":"源码解读","description":"","frontmatter":{},"headers":[],"relativePath":"guide/Redux/源码解读.md","filePath":"guide/Redux/源码解读.md","lastUpdated":1718174182000}'),o={name:"guide/Redux/源码解读.md"},r=e("h1",{id:"源码解读",tabindex:"-1"},[d("源码解读 "),e("a",{class:"header-anchor",href:"#源码解读","aria-label":'Permalink to "源码解读"'},"​")],-1),c=[r];function n(i,_,l,p,u,h){return t(),s("div",null,c)}const x=a(o,[["render",n]]);export{f as __pageData,x as default}; diff --git "a/assets/guide_Redux_\346\272\220\347\240\201\350\247\243\350\257\273.md.a16d34cb.lean.js" "b/assets/guide_Redux_\346\272\220\347\240\201\350\247\243\350\257\273.md.25f8a90e.lean.js" similarity index 89% rename from "assets/guide_Redux_\346\272\220\347\240\201\350\247\243\350\257\273.md.a16d34cb.lean.js" rename to "assets/guide_Redux_\346\272\220\347\240\201\350\247\243\350\257\273.md.25f8a90e.lean.js" index dcaf5bb6..dda60a63 100644 --- "a/assets/guide_Redux_\346\272\220\347\240\201\350\247\243\350\257\273.md.a16d34cb.lean.js" +++ "b/assets/guide_Redux_\346\272\220\347\240\201\350\247\243\350\257\273.md.25f8a90e.lean.js" @@ -1 +1 @@ -import{_ as a,o as t,c as s,k as e,a as d}from"./chunks/framework.b6910bb2.js";const f=JSON.parse('{"title":"源码解读","description":"","frontmatter":{},"headers":[],"relativePath":"guide/Redux/源码解读.md","filePath":"guide/Redux/源码解读.md","lastUpdated":1718173557000}'),o={name:"guide/Redux/源码解读.md"},r=e("h1",{id:"源码解读",tabindex:"-1"},[d("源码解读 "),e("a",{class:"header-anchor",href:"#源码解读","aria-label":'Permalink to "源码解读"'},"​")],-1),c=[r];function n(i,_,l,p,u,h){return t(),s("div",null,c)}const x=a(o,[["render",n]]);export{f as __pageData,x as default}; +import{_ as a,o as t,c as s,k as e,a as d}from"./chunks/framework.b6910bb2.js";const f=JSON.parse('{"title":"源码解读","description":"","frontmatter":{},"headers":[],"relativePath":"guide/Redux/源码解读.md","filePath":"guide/Redux/源码解读.md","lastUpdated":1718174182000}'),o={name:"guide/Redux/源码解读.md"},r=e("h1",{id:"源码解读",tabindex:"-1"},[d("源码解读 "),e("a",{class:"header-anchor",href:"#源码解读","aria-label":'Permalink to "源码解读"'},"​")],-1),c=[r];function n(i,_,l,p,u,h){return t(),s("div",null,c)}const x=a(o,[["render",n]]);export{f as __pageData,x as default}; diff --git "a/assets/guide_Redux_\350\256\276\350\256\241\347\220\206\345\277\265.md.53d3413a.lean.js" "b/assets/guide_Redux_\350\256\276\350\256\241\347\220\206\345\277\265.md.67b7623f.js" similarity index 89% rename from "assets/guide_Redux_\350\256\276\350\256\241\347\220\206\345\277\265.md.53d3413a.lean.js" rename to "assets/guide_Redux_\350\256\276\350\256\241\347\220\206\345\277\265.md.67b7623f.js" index d6cc947a..c3396a1d 100644 --- "a/assets/guide_Redux_\350\256\276\350\256\241\347\220\206\345\277\265.md.53d3413a.lean.js" +++ "b/assets/guide_Redux_\350\256\276\350\256\241\347\220\206\345\277\265.md.67b7623f.js" @@ -1 +1 @@ -import{_ as a,o as t,c as s,k as e,a as d}from"./chunks/framework.b6910bb2.js";const f=JSON.parse('{"title":"设计理念","description":"","frontmatter":{},"headers":[],"relativePath":"guide/Redux/设计理念.md","filePath":"guide/Redux/设计理念.md","lastUpdated":1718173557000}'),o={name:"guide/Redux/设计理念.md"},r=e("h1",{id:"设计理念",tabindex:"-1"},[d("设计理念 "),e("a",{class:"header-anchor",href:"#设计理念","aria-label":'Permalink to "设计理念"'},"​")],-1),c=[r];function n(i,_,l,p,u,h){return t(),s("div",null,c)}const x=a(o,[["render",n]]);export{f as __pageData,x as default}; +import{_ as a,o as t,c as s,k as e,a as d}from"./chunks/framework.b6910bb2.js";const f=JSON.parse('{"title":"设计理念","description":"","frontmatter":{},"headers":[],"relativePath":"guide/Redux/设计理念.md","filePath":"guide/Redux/设计理念.md","lastUpdated":1718174182000}'),o={name:"guide/Redux/设计理念.md"},r=e("h1",{id:"设计理念",tabindex:"-1"},[d("设计理念 "),e("a",{class:"header-anchor",href:"#设计理念","aria-label":'Permalink to "设计理念"'},"​")],-1),c=[r];function n(i,_,l,p,u,h){return t(),s("div",null,c)}const x=a(o,[["render",n]]);export{f as __pageData,x as default}; diff --git "a/assets/guide_Redux_\350\256\276\350\256\241\347\220\206\345\277\265.md.53d3413a.js" "b/assets/guide_Redux_\350\256\276\350\256\241\347\220\206\345\277\265.md.67b7623f.lean.js" similarity index 89% rename from "assets/guide_Redux_\350\256\276\350\256\241\347\220\206\345\277\265.md.53d3413a.js" rename to "assets/guide_Redux_\350\256\276\350\256\241\347\220\206\345\277\265.md.67b7623f.lean.js" index d6cc947a..c3396a1d 100644 --- "a/assets/guide_Redux_\350\256\276\350\256\241\347\220\206\345\277\265.md.53d3413a.js" +++ "b/assets/guide_Redux_\350\256\276\350\256\241\347\220\206\345\277\265.md.67b7623f.lean.js" @@ -1 +1 @@ -import{_ as a,o as t,c as s,k as e,a as d}from"./chunks/framework.b6910bb2.js";const f=JSON.parse('{"title":"设计理念","description":"","frontmatter":{},"headers":[],"relativePath":"guide/Redux/设计理念.md","filePath":"guide/Redux/设计理念.md","lastUpdated":1718173557000}'),o={name:"guide/Redux/设计理念.md"},r=e("h1",{id:"设计理念",tabindex:"-1"},[d("设计理念 "),e("a",{class:"header-anchor",href:"#设计理念","aria-label":'Permalink to "设计理念"'},"​")],-1),c=[r];function n(i,_,l,p,u,h){return t(),s("div",null,c)}const x=a(o,[["render",n]]);export{f as __pageData,x as default}; +import{_ as a,o as t,c as s,k as e,a as d}from"./chunks/framework.b6910bb2.js";const f=JSON.parse('{"title":"设计理念","description":"","frontmatter":{},"headers":[],"relativePath":"guide/Redux/设计理念.md","filePath":"guide/Redux/设计理念.md","lastUpdated":1718174182000}'),o={name:"guide/Redux/设计理念.md"},r=e("h1",{id:"设计理念",tabindex:"-1"},[d("设计理念 "),e("a",{class:"header-anchor",href:"#设计理念","aria-label":'Permalink to "设计理念"'},"​")],-1),c=[r];function n(i,_,l,p,u,h){return t(),s("div",null,c)}const x=a(o,[["render",n]]);export{f as __pageData,x as default}; diff --git "a/assets/guide_ai_Embedding\344\271\213\346\213\206\345\210\206\346\225\260\346\215\256.md.dce10d49.js" "b/assets/guide_ai_Embedding\344\271\213\346\213\206\345\210\206\346\225\260\346\215\256.md.dce10d49.js" new file mode 100644 index 00000000..6472fe62 --- /dev/null +++ "b/assets/guide_ai_Embedding\344\271\213\346\213\206\345\210\206\346\225\260\346\215\256.md.dce10d49.js" @@ -0,0 +1 @@ +import{_ as e,o as t,c as a}from"./chunks/framework.b6910bb2.js";const p=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"guide/ai/Embedding之拆分数据.md","filePath":"guide/ai/Embedding之拆分数据.md","lastUpdated":1718174182000}'),d={name:"guide/ai/Embedding之拆分数据.md"};function i(n,r,o,s,_,c){return t(),a("div")}const f=e(d,[["render",i]]);export{p as __pageData,f as default}; diff --git "a/assets/guide_ai_Embedding\344\271\213\346\213\206\345\210\206\346\225\260\346\215\256.md.dce10d49.lean.js" "b/assets/guide_ai_Embedding\344\271\213\346\213\206\345\210\206\346\225\260\346\215\256.md.dce10d49.lean.js" new file mode 100644 index 00000000..6472fe62 --- /dev/null +++ "b/assets/guide_ai_Embedding\344\271\213\346\213\206\345\210\206\346\225\260\346\215\256.md.dce10d49.lean.js" @@ -0,0 +1 @@ +import{_ as e,o as t,c as a}from"./chunks/framework.b6910bb2.js";const p=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"guide/ai/Embedding之拆分数据.md","filePath":"guide/ai/Embedding之拆分数据.md","lastUpdated":1718174182000}'),d={name:"guide/ai/Embedding之拆分数据.md"};function i(n,r,o,s,_,c){return t(),a("div")}const f=e(d,[["render",i]]);export{p as __pageData,f as default}; diff --git "a/assets/guide_ai_OutputParser\346\236\204\345\273\272\346\240\274\345\274\217\345\214\226\350\276\223\345\207\272.md.ace64382.js" "b/assets/guide_ai_OutputParser\346\236\204\345\273\272\346\240\274\345\274\217\345\214\226\350\276\223\345\207\272.md.309cc9be.js" similarity index 99% rename from "assets/guide_ai_OutputParser\346\236\204\345\273\272\346\240\274\345\274\217\345\214\226\350\276\223\345\207\272.md.ace64382.js" rename to "assets/guide_ai_OutputParser\346\236\204\345\273\272\346\240\274\345\274\217\345\214\226\350\276\223\345\207\272.md.309cc9be.js" index 8694063c..0aeaedb4 100644 --- "a/assets/guide_ai_OutputParser\346\236\204\345\273\272\346\240\274\345\274\217\345\214\226\350\276\223\345\207\272.md.ace64382.js" +++ "b/assets/guide_ai_OutputParser\346\236\204\345\273\272\346\240\274\345\274\217\345\214\226\350\276\223\345\207\272.md.309cc9be.js" @@ -1,4 +1,4 @@ -import{_ as s,o as n,c as a,Q as o}from"./chunks/framework.b6910bb2.js";const p="/vitePress-blob/assets/4.43d3c47e.png",m=JSON.parse('{"title":"OutputParser","description":"","frontmatter":{},"headers":[],"relativePath":"guide/ai/OutputParser构建格式化输出.md","filePath":"guide/ai/OutputParser构建格式化输出.md","lastUpdated":1718173557000}'),l={name:"guide/ai/OutputParser构建格式化输出.md"},t=o(`

OutputParser

OutputParser是一个用于解析模型输出的工具类,它可以帮助用户将模型输出解析为用户需要的格式。

String Output Parser

StringOutputParser是OutputParser的一个实现类,它可以将模型输出解析为字符串。

前面的例子中,我们使用了StringOutputParser来解析模型输出,这里就不过多赘述了。

StructuredOutputParser (结构化的输出)

StructuredOutputParser是OutputParser的另一个实现类,它可以将模型输出解析为结构化的数据。

例如,我们可以将模型输出解析为JSON格式的数据,这样我们就可以更方便地处理模型输出。

下面是一个使用StructuredOutputParser的例子:

js
import { StructuredOutputParser } from "langchain/output_parsers";
+import{_ as s,o as n,c as a,Q as o}from"./chunks/framework.b6910bb2.js";const p="/vitePress-blob/assets/4.43d3c47e.png",m=JSON.parse('{"title":"OutputParser","description":"","frontmatter":{},"headers":[],"relativePath":"guide/ai/OutputParser构建格式化输出.md","filePath":"guide/ai/OutputParser构建格式化输出.md","lastUpdated":1718174182000}'),l={name:"guide/ai/OutputParser构建格式化输出.md"},t=o(`

OutputParser

OutputParser是一个用于解析模型输出的工具类,它可以帮助用户将模型输出解析为用户需要的格式。

String Output Parser

StringOutputParser是OutputParser的一个实现类,它可以将模型输出解析为字符串。

前面的例子中,我们使用了StringOutputParser来解析模型输出,这里就不过多赘述了。

StructuredOutputParser (结构化的输出)

StructuredOutputParser是OutputParser的另一个实现类,它可以将模型输出解析为结构化的数据。

例如,我们可以将模型输出解析为JSON格式的数据,这样我们就可以更方便地处理模型输出。

下面是一个使用StructuredOutputParser的例子:

js
import { StructuredOutputParser } from "langchain/output_parsers";
 import { PromptTemplate } from "@langchain/core/prompts";
 
 const parser = StructuredOutputParser.fromNamesAndDescriptions({
diff --git "a/assets/guide_ai_OutputParser\346\236\204\345\273\272\346\240\274\345\274\217\345\214\226\350\276\223\345\207\272.md.ace64382.lean.js" "b/assets/guide_ai_OutputParser\346\236\204\345\273\272\346\240\274\345\274\217\345\214\226\350\276\223\345\207\272.md.309cc9be.lean.js"
similarity index 88%
rename from "assets/guide_ai_OutputParser\346\236\204\345\273\272\346\240\274\345\274\217\345\214\226\350\276\223\345\207\272.md.ace64382.lean.js"
rename to "assets/guide_ai_OutputParser\346\236\204\345\273\272\346\240\274\345\274\217\345\214\226\350\276\223\345\207\272.md.309cc9be.lean.js"
index 791a092c..cb4a7287 100644
--- "a/assets/guide_ai_OutputParser\346\236\204\345\273\272\346\240\274\345\274\217\345\214\226\350\276\223\345\207\272.md.ace64382.lean.js"
+++ "b/assets/guide_ai_OutputParser\346\236\204\345\273\272\346\240\274\345\274\217\345\214\226\350\276\223\345\207\272.md.309cc9be.lean.js"
@@ -1 +1 @@
-import{_ as s,o as n,c as a,Q as o}from"./chunks/framework.b6910bb2.js";const p="/vitePress-blob/assets/4.43d3c47e.png",m=JSON.parse('{"title":"OutputParser","description":"","frontmatter":{},"headers":[],"relativePath":"guide/ai/OutputParser构建格式化输出.md","filePath":"guide/ai/OutputParser构建格式化输出.md","lastUpdated":1718173557000}'),l={name:"guide/ai/OutputParser构建格式化输出.md"},t=o("",31),e=[t];function r(c,E,y,u,i,F){return n(),a("div",null,e)}const d=s(l,[["render",r]]);export{m as __pageData,d as default};
+import{_ as s,o as n,c as a,Q as o}from"./chunks/framework.b6910bb2.js";const p="/vitePress-blob/assets/4.43d3c47e.png",m=JSON.parse('{"title":"OutputParser","description":"","frontmatter":{},"headers":[],"relativePath":"guide/ai/OutputParser构建格式化输出.md","filePath":"guide/ai/OutputParser构建格式化输出.md","lastUpdated":1718174182000}'),l={name:"guide/ai/OutputParser构建格式化输出.md"},t=o("",31),e=[t];function r(c,E,y,u,i,F){return n(),a("div",null,e)}const d=s(l,[["render",r]]);export{m as __pageData,d as default};
diff --git "a/assets/guide_ai_RAG \346\243\200\347\264\242\345\242\236\345\274\272\347\224\237\346\210\220\347\232\204\346\265\201\347\250\213.md.a339dabc.js" "b/assets/guide_ai_RAG \346\243\200\347\264\242\345\242\236\345\274\272\347\224\237\346\210\220\347\232\204\346\265\201\347\250\213.md.5f0d5880.js"
similarity index 98%
rename from "assets/guide_ai_RAG \346\243\200\347\264\242\345\242\236\345\274\272\347\224\237\346\210\220\347\232\204\346\265\201\347\250\213.md.a339dabc.js"
rename to "assets/guide_ai_RAG \346\243\200\347\264\242\345\242\236\345\274\272\347\224\237\346\210\220\347\232\204\346\265\201\347\250\213.md.5f0d5880.js"
index c751c085..ffb2d024 100644
--- "a/assets/guide_ai_RAG \346\243\200\347\264\242\345\242\236\345\274\272\347\224\237\346\210\220\347\232\204\346\265\201\347\250\213.md.a339dabc.js"	
+++ "b/assets/guide_ai_RAG \346\243\200\347\264\242\345\242\236\345\274\272\347\224\237\346\210\220\347\232\204\346\265\201\347\250\213.md.5f0d5880.js"	
@@ -1 +1 @@
-import{_ as a,o as e,c as t,Q as r}from"./chunks/framework.b6910bb2.js";const i="/vitePress-blob/assets/5.ca3137a4.png",m=JSON.parse('{"title":"RAG 检索增强生成的流程","description":"","frontmatter":{},"headers":[],"relativePath":"guide/ai/RAG 检索增强生成的流程.md","filePath":"guide/ai/RAG 检索增强生成的流程.md","lastUpdated":1718173557000}'),o={name:"guide/ai/RAG 检索增强生成的流程.md"},l=r('

RAG 检索增强生成的流程

RAG 其全称是 Retrieval Augmented Generation,可以被翻译成 检索增强生成技术,从标题上也能了解其核心的流程 检索 => 增强 => 生成。

LLM 的局限

在介绍 RAG 之前,我们先来了解一下 LLM 的局限性。

首先是幻觉问题(hallucination),LLM 底层还不具备真正的逻辑推理能力,是根据大量的数据进行概率性预测,所以在某些情况下,LLM 会生成一些不合理的答案。

其次是对领域知识的欠缺,造成这个问题主要是俩个原因,第一个是对知识的更新慢,另一个是对专业领域的知识训练样本不足导致。

RAG 的优势

当我们了解了 LLM 的局限性后,RAG 会尽可能提供与答案相关的上下文,来增强它正确输出的可能性。

RAG 的优势主要体现在以下几个方面:

  1. 用户输入提问
  2. 检索:根据用户提问对 向量数据库 进行相似性检测,查找与回答用户问题最相关的内容
  3. 增强:根据检索的结果,生成 prompt。 一般都会涉及 “仅依赖下述信息源来回答问题” 这种限制 LLM 参考信息源的语句,来减少幻想,让回答更加聚焦
  4. 生成:将增强后的 prompt 传递给 LLM,返回数据给用户

所以 RAG 就是哪里有问题解决哪里,既然大模型无法获得最新和内部的数据集,那我们就使用外挂的向量数据库为 LLM 提供最新和内部的数据库。既然大模型有幻想问题,我们就将回答问题所需要的信息和知识编码到上下文中,强制大模型只参考这些内容进行回答。

注意:LLM 是逻辑推理引擎,而不是信息引擎。所以,由外挂的向量数据库提供最有效的知识,然后由 LLM 根据知识进行推理,提供有价值的回复。

RAG 流程

输出结果

后续章节,在下将针对 RAG 的各个流程做详细的介绍。

',15),_=[l];function p(s,n,c,d,h,L){return e(),t("div",null,_)}const R=a(o,[["render",p]]);export{m as __pageData,R as default}; +import{_ as a,o as e,c as t,Q as r}from"./chunks/framework.b6910bb2.js";const i="/vitePress-blob/assets/5.ca3137a4.png",m=JSON.parse('{"title":"RAG 检索增强生成的流程","description":"","frontmatter":{},"headers":[],"relativePath":"guide/ai/RAG 检索增强生成的流程.md","filePath":"guide/ai/RAG 检索增强生成的流程.md","lastUpdated":1718174182000}'),o={name:"guide/ai/RAG 检索增强生成的流程.md"},l=r('

RAG 检索增强生成的流程

RAG 其全称是 Retrieval Augmented Generation,可以被翻译成 检索增强生成技术,从标题上也能了解其核心的流程 检索 => 增强 => 生成。

LLM 的局限

在介绍 RAG 之前,我们先来了解一下 LLM 的局限性。

首先是幻觉问题(hallucination),LLM 底层还不具备真正的逻辑推理能力,是根据大量的数据进行概率性预测,所以在某些情况下,LLM 会生成一些不合理的答案。

其次是对领域知识的欠缺,造成这个问题主要是俩个原因,第一个是对知识的更新慢,另一个是对专业领域的知识训练样本不足导致。

RAG 的优势

当我们了解了 LLM 的局限性后,RAG 会尽可能提供与答案相关的上下文,来增强它正确输出的可能性。

RAG 的优势主要体现在以下几个方面:

  1. 用户输入提问
  2. 检索:根据用户提问对 向量数据库 进行相似性检测,查找与回答用户问题最相关的内容
  3. 增强:根据检索的结果,生成 prompt。 一般都会涉及 “仅依赖下述信息源来回答问题” 这种限制 LLM 参考信息源的语句,来减少幻想,让回答更加聚焦
  4. 生成:将增强后的 prompt 传递给 LLM,返回数据给用户

所以 RAG 就是哪里有问题解决哪里,既然大模型无法获得最新和内部的数据集,那我们就使用外挂的向量数据库为 LLM 提供最新和内部的数据库。既然大模型有幻想问题,我们就将回答问题所需要的信息和知识编码到上下文中,强制大模型只参考这些内容进行回答。

注意:LLM 是逻辑推理引擎,而不是信息引擎。所以,由外挂的向量数据库提供最有效的知识,然后由 LLM 根据知识进行推理,提供有价值的回复。

RAG 流程

输出结果

后续章节,在下将针对 RAG 的各个流程做详细的介绍。

',15),_=[l];function p(s,n,c,d,h,L){return e(),t("div",null,_)}const R=a(o,[["render",p]]);export{m as __pageData,R as default}; diff --git "a/assets/guide_ai_RAG \346\243\200\347\264\242\345\242\236\345\274\272\347\224\237\346\210\220\347\232\204\346\265\201\347\250\213.md.a339dabc.lean.js" "b/assets/guide_ai_RAG \346\243\200\347\264\242\345\242\236\345\274\272\347\224\237\346\210\220\347\232\204\346\265\201\347\250\213.md.5f0d5880.lean.js" similarity index 88% rename from "assets/guide_ai_RAG \346\243\200\347\264\242\345\242\236\345\274\272\347\224\237\346\210\220\347\232\204\346\265\201\347\250\213.md.a339dabc.lean.js" rename to "assets/guide_ai_RAG \346\243\200\347\264\242\345\242\236\345\274\272\347\224\237\346\210\220\347\232\204\346\265\201\347\250\213.md.5f0d5880.lean.js" index d1d0310c..a17b417e 100644 --- "a/assets/guide_ai_RAG \346\243\200\347\264\242\345\242\236\345\274\272\347\224\237\346\210\220\347\232\204\346\265\201\347\250\213.md.a339dabc.lean.js" +++ "b/assets/guide_ai_RAG \346\243\200\347\264\242\345\242\236\345\274\272\347\224\237\346\210\220\347\232\204\346\265\201\347\250\213.md.5f0d5880.lean.js" @@ -1 +1 @@ -import{_ as a,o as e,c as t,Q as r}from"./chunks/framework.b6910bb2.js";const i="/vitePress-blob/assets/5.ca3137a4.png",m=JSON.parse('{"title":"RAG 检索增强生成的流程","description":"","frontmatter":{},"headers":[],"relativePath":"guide/ai/RAG 检索增强生成的流程.md","filePath":"guide/ai/RAG 检索增强生成的流程.md","lastUpdated":1718173557000}'),o={name:"guide/ai/RAG 检索增强生成的流程.md"},l=r("",15),_=[l];function p(s,n,c,d,h,L){return e(),t("div",null,_)}const R=a(o,[["render",p]]);export{m as __pageData,R as default}; +import{_ as a,o as e,c as t,Q as r}from"./chunks/framework.b6910bb2.js";const i="/vitePress-blob/assets/5.ca3137a4.png",m=JSON.parse('{"title":"RAG 检索增强生成的流程","description":"","frontmatter":{},"headers":[],"relativePath":"guide/ai/RAG 检索增强生成的流程.md","filePath":"guide/ai/RAG 检索增强生成的流程.md","lastUpdated":1718174182000}'),o={name:"guide/ai/RAG 检索增强生成的流程.md"},l=r("",15),_=[l];function p(s,n,c,d,h,L){return e(),t("div",null,_)}const R=a(o,[["render",p]]);export{m as __pageData,R as default}; diff --git "a/assets/guide_ai_RAG\344\271\213embeding.md.9d57501d.js" "b/assets/guide_ai_RAG\344\271\213embeding.md.9d57501d.js" deleted file mode 100644 index 1de3c44e..00000000 --- "a/assets/guide_ai_RAG\344\271\213embeding.md.9d57501d.js" +++ /dev/null @@ -1 +0,0 @@ -import{_ as e,o as t,c as a}from"./chunks/framework.b6910bb2.js";const _=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"guide/ai/RAG之embeding.md","filePath":"guide/ai/RAG之embeding.md","lastUpdated":1718173557000}'),i={name:"guide/ai/RAG之embeding.md"};function d(n,r,o,s,c,m){return t(),a("div")}const f=e(i,[["render",d]]);export{_ as __pageData,f as default}; diff --git "a/assets/guide_ai_RAG\344\271\213embeding.md.9d57501d.lean.js" "b/assets/guide_ai_RAG\344\271\213embeding.md.9d57501d.lean.js" deleted file mode 100644 index 1de3c44e..00000000 --- "a/assets/guide_ai_RAG\344\271\213embeding.md.9d57501d.lean.js" +++ /dev/null @@ -1 +0,0 @@ -import{_ as e,o as t,c as a}from"./chunks/framework.b6910bb2.js";const _=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"guide/ai/RAG之embeding.md","filePath":"guide/ai/RAG之embeding.md","lastUpdated":1718173557000}'),i={name:"guide/ai/RAG之embeding.md"};function d(n,r,o,s,c,m){return t(),a("div")}const f=e(i,[["render",d]]);export{_ as __pageData,f as default}; diff --git "a/assets/guide_ai_RAG\344\271\213\345\212\240\350\275\275\346\225\260\346\215\256.md.7787c157.js" "b/assets/guide_ai_RAG\344\271\213\345\212\240\350\275\275\346\225\260\346\215\256.md.7787c157.js" deleted file mode 100644 index fd9b8411..00000000 --- "a/assets/guide_ai_RAG\344\271\213\345\212\240\350\275\275\346\225\260\346\215\256.md.7787c157.js" +++ /dev/null @@ -1,81 +0,0 @@ -import{_ as s,o as a,c as n,Q as o}from"./chunks/framework.b6910bb2.js";const l="/vitePress-blob/assets/6.fdcb22fa.png",p="/vitePress-blob/assets/7.522a2c1b.png",e="/vitePress-blob/assets/8.adec2266.png",m=JSON.parse('{"title":"RAG 之加载数据","description":"","frontmatter":{},"headers":[],"relativePath":"guide/ai/RAG之加载数据.md","filePath":"guide/ai/RAG之加载数据.md","lastUpdated":1718173557000}'),t={name:"guide/ai/RAG之加载数据.md"},c=o(`

RAG 之加载数据

因为 RAG 本质是给 Chat Bot 额外挂在数据源,而数据源存在的形式是多种多样的,有可能是文件/网页/数据库/代码等等其情况。

针对这个情况,langchain 提供了一系列开箱即用的数据加载器 (loader),方便用户快速加载数据。

Document 对象

Document 对象你可以理解成 langchain 对所有类型的数据的一个统一抽象,其中包含

pageContent 文本内容,即文档对象对应的文本数据 metadata 元数据,文本数据对应的元数据,例如 原始文档的标题、页数等信息,可以用于后面 Retriever 基于此进行筛选。

TypeScript
// Document 对象的定义
-interface Document {
-  pageContent: string;
-  metadata: Record<string, any>;
-}
// Document 对象的定义
-interface Document {
-  pageContent: string;
-  metadata: Record<string, any>;
-}

Loader

RAG 的第一步就是加载数据,而加载数据的方式有很多种,langchain 提供了一系列的 loader,方便用户快速加载数据。

下面将简单举一俩个 loader 的例子,更多的 loader 可以查看 传送门

DirectoryLoader

根据目录加载不同的文件数据

js
// DirectoryLoader 加载文件夹内的文件内容
-
-import { DirectoryLoader } from "langchain/document_loaders/fs/directory";
-import { TextLoader } from "langchain/document_loaders/fs/text";
-import { PDFLoader } from "langchain/document_loaders/fs/pdf";
-
-const loader = new DirectoryLoader(
-    "./data",
-    {
-      // 通过文件后缀名来指定加载器
-      ".pdf": (path) => new PDFLoader(path, { splitPages: false }),
-      ".txt": (path) => new TextLoader(path),
-    }
-  );
-const docs = await loader.load();
-
-console.log(docs);
// DirectoryLoader 加载文件夹内的文件内容
-
-import { DirectoryLoader } from "langchain/document_loaders/fs/directory";
-import { TextLoader } from "langchain/document_loaders/fs/text";
-import { PDFLoader } from "langchain/document_loaders/fs/pdf";
-
-const loader = new DirectoryLoader(
-    "./data",
-    {
-      // 通过文件后缀名来指定加载器
-      ".pdf": (path) => new PDFLoader(path, { splitPages: false }),
-      ".txt": (path) => new TextLoader(path),
-    }
-  );
-const docs = await loader.load();
-
-console.log(docs);

输出结果如下:👇

输出结果

WebLoader

对于 LLM 所需要提取的信息是网页中静态的信息时,一般使用 Cheerio 用来提取和处理 html 内容,类似于 python 中的 BeautifulSoup。 这两者都是只能针对静态的 html,无法运行其中的 js, 对大部分场景都是够用的。

js
import { CheerioWebBaseLoader } from "@langchain/community/document_loaders/web/cheerio";
-import "cheerio";
-
-const loader = new CheerioWebBaseLoader(
-  "https://enson0131.github.io/vitePress-blob/",
-  {
-    selector: "h3",
-  }
-);
-
-const docs = await loader.load();
-
-console.log(\`******爬取网页数据*********\`);
-console.log(docs);
-console.log(\`******爬取网页数据*********\`);
import { CheerioWebBaseLoader } from "@langchain/community/document_loaders/web/cheerio";
-import "cheerio";
-
-const loader = new CheerioWebBaseLoader(
-  "https://enson0131.github.io/vitePress-blob/",
-  {
-    selector: "h3",
-  }
-);
-
-const docs = await loader.load();
-
-console.log(\`******爬取网页数据*********\`);
-console.log(docs);
-console.log(\`******爬取网页数据*********\`);

输出结果

Search API

在 langchain 中 SearchApiLoader 和 SerpAPILoader 这个两个提供的都是接入搜索的能力,免费计划都是每个月 100 次 search 能力,除了 google 外,也支持 baidu/bing 等常用的搜索引擎。

首先我们需要在 SearchAPI 注册一个账号,然后获取到 API Key,然后将 API Key 设置为环境变量 SEARCH_KEY

js
import { SearchApiLoader } from "@langchain/community/document_loaders/web/searchapi";
-import 'dotenv/config'
-// https://js.langchain.com/v0.2/docs/integrations/document_loaders/web_loaders/searchapi
-const apiKey = process.env["SEARCH_KEY"]
-const question = "什么 github copliot"
-const searchLoader = new SearchApiLoader({ q: question, apiKey, engine: "google" });
-const searchRes = await searchLoader.load();
import { SearchApiLoader } from "@langchain/community/document_loaders/web/searchapi";
-import 'dotenv/config'
-// https://js.langchain.com/v0.2/docs/integrations/document_loaders/web_loaders/searchapi
-const apiKey = process.env["SEARCH_KEY"]
-const question = "什么 github copliot"
-const searchLoader = new SearchApiLoader({ q: question, apiKey, engine: "google" });
-const searchRes = await searchLoader.load();

输出结果如下:👇

输出结果

参考文档

',27),r=[c];function E(y,i,d,h,F,u){return a(),n("div",null,r)}const A=s(t,[["render",E]]);export{m as __pageData,A as default}; diff --git "a/assets/guide_ai_RAG\344\271\213\345\212\240\350\275\275\346\225\260\346\215\256.md.7787c157.lean.js" "b/assets/guide_ai_RAG\344\271\213\345\212\240\350\275\275\346\225\260\346\215\256.md.7787c157.lean.js" deleted file mode 100644 index c173a38c..00000000 --- "a/assets/guide_ai_RAG\344\271\213\345\212\240\350\275\275\346\225\260\346\215\256.md.7787c157.lean.js" +++ /dev/null @@ -1 +0,0 @@ -import{_ as s,o as a,c as n,Q as o}from"./chunks/framework.b6910bb2.js";const l="/vitePress-blob/assets/6.fdcb22fa.png",p="/vitePress-blob/assets/7.522a2c1b.png",e="/vitePress-blob/assets/8.adec2266.png",m=JSON.parse('{"title":"RAG 之加载数据","description":"","frontmatter":{},"headers":[],"relativePath":"guide/ai/RAG之加载数据.md","filePath":"guide/ai/RAG之加载数据.md","lastUpdated":1718173557000}'),t={name:"guide/ai/RAG之加载数据.md"},c=o("",27),r=[c];function E(y,i,d,h,F,u){return a(),n("div",null,r)}const A=s(t,[["render",E]]);export{m as __pageData,A as default}; diff --git "a/assets/guide_ai_RAG\344\271\213\345\220\221\351\207\217\346\225\260\346\215\256\345\272\223.md.6db527a5.js" "b/assets/guide_ai_RAG\344\271\213\345\220\221\351\207\217\346\225\260\346\215\256\345\272\223.md.6db527a5.js" deleted file mode 100644 index a6653091..00000000 --- "a/assets/guide_ai_RAG\344\271\213\345\220\221\351\207\217\346\225\260\346\215\256\345\272\223.md.6db527a5.js" +++ /dev/null @@ -1 +0,0 @@ -import{_ as e,o as t,c as a}from"./chunks/framework.b6910bb2.js";const m=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"guide/ai/RAG之向量数据库.md","filePath":"guide/ai/RAG之向量数据库.md","lastUpdated":1718173557000}'),r={name:"guide/ai/RAG之向量数据库.md"};function o(s,_,i,c,d,n){return t(),a("div")}const f=e(r,[["render",o]]);export{m as __pageData,f as default}; diff --git "a/assets/guide_ai_RAG\344\271\213\345\220\221\351\207\217\346\225\260\346\215\256\345\272\223.md.6db527a5.lean.js" "b/assets/guide_ai_RAG\344\271\213\345\220\221\351\207\217\346\225\260\346\215\256\345\272\223.md.6db527a5.lean.js" deleted file mode 100644 index a6653091..00000000 --- "a/assets/guide_ai_RAG\344\271\213\345\220\221\351\207\217\346\225\260\346\215\256\345\272\223.md.6db527a5.lean.js" +++ /dev/null @@ -1 +0,0 @@ -import{_ as e,o as t,c as a}from"./chunks/framework.b6910bb2.js";const m=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"guide/ai/RAG之向量数据库.md","filePath":"guide/ai/RAG之向量数据库.md","lastUpdated":1718173557000}'),r={name:"guide/ai/RAG之向量数据库.md"};function o(s,_,i,c,d,n){return t(),a("div")}const f=e(r,[["render",o]]);export{m as __pageData,f as default}; diff --git "a/assets/guide_ai_RAG\344\271\213\346\213\206\345\210\206\346\225\260\346\215\256.md.c7dc2891.js" "b/assets/guide_ai_RAG\344\271\213\346\213\206\345\210\206\346\225\260\346\215\256.md.c7dc2891.js" deleted file mode 100644 index 3a9368dc..00000000 --- "a/assets/guide_ai_RAG\344\271\213\346\213\206\345\210\206\346\225\260\346\215\256.md.c7dc2891.js" +++ /dev/null @@ -1 +0,0 @@ -import{_ as e,o as t,c as a}from"./chunks/framework.b6910bb2.js";const m=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"guide/ai/RAG之拆分数据.md","filePath":"guide/ai/RAG之拆分数据.md","lastUpdated":1718173557000}'),r={name:"guide/ai/RAG之拆分数据.md"};function o(s,i,_,c,d,n){return t(),a("div")}const f=e(r,[["render",o]]);export{m as __pageData,f as default}; diff --git "a/assets/guide_ai_RAG\344\271\213\346\213\206\345\210\206\346\225\260\346\215\256.md.c7dc2891.lean.js" "b/assets/guide_ai_RAG\344\271\213\346\213\206\345\210\206\346\225\260\346\215\256.md.c7dc2891.lean.js" deleted file mode 100644 index 3a9368dc..00000000 --- "a/assets/guide_ai_RAG\344\271\213\346\213\206\345\210\206\346\225\260\346\215\256.md.c7dc2891.lean.js" +++ /dev/null @@ -1 +0,0 @@ -import{_ as e,o as t,c as a}from"./chunks/framework.b6910bb2.js";const m=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"guide/ai/RAG之拆分数据.md","filePath":"guide/ai/RAG之拆分数据.md","lastUpdated":1718173557000}'),r={name:"guide/ai/RAG之拆分数据.md"};function o(s,i,_,c,d,n){return t(),a("div")}const f=e(r,[["render",o]]);export{m as __pageData,f as default}; diff --git "a/assets/guide_ai_Retriever \345\270\270\350\247\201\347\232\204\344\274\230\345\214\226\346\226\271\345\274\217.md.77046314.js" "b/assets/guide_ai_Retriever \345\270\270\350\247\201\347\232\204\344\274\230\345\214\226\346\226\271\345\274\217.md.a80c6c4a.js" similarity index 86% rename from "assets/guide_ai_Retriever \345\270\270\350\247\201\347\232\204\344\274\230\345\214\226\346\226\271\345\274\217.md.77046314.js" rename to "assets/guide_ai_Retriever \345\270\270\350\247\201\347\232\204\344\274\230\345\214\226\346\226\271\345\274\217.md.a80c6c4a.js" index a692f763..d2f18be8 100644 --- "a/assets/guide_ai_Retriever \345\270\270\350\247\201\347\232\204\344\274\230\345\214\226\346\226\271\345\274\217.md.77046314.js" +++ "b/assets/guide_ai_Retriever \345\270\270\350\247\201\347\232\204\344\274\230\345\214\226\346\226\271\345\274\217.md.a80c6c4a.js" @@ -1 +1 @@ -import{_ as e,o as t,c as r}from"./chunks/framework.b6910bb2.js";const m=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"guide/ai/Retriever 常见的优化方式.md","filePath":"guide/ai/Retriever 常见的优化方式.md","lastUpdated":1718173557000}'),a={name:"guide/ai/Retriever 常见的优化方式.md"};function i(_,o,s,c,d,n){return t(),r("div")}const f=e(a,[["render",i]]);export{m as __pageData,f as default}; +import{_ as e,o as t,c as r}from"./chunks/framework.b6910bb2.js";const m=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"guide/ai/Retriever 常见的优化方式.md","filePath":"guide/ai/Retriever 常见的优化方式.md","lastUpdated":1718174182000}'),a={name:"guide/ai/Retriever 常见的优化方式.md"};function i(_,o,s,c,d,n){return t(),r("div")}const f=e(a,[["render",i]]);export{m as __pageData,f as default}; diff --git "a/assets/guide_ai_Retriever \345\270\270\350\247\201\347\232\204\344\274\230\345\214\226\346\226\271\345\274\217.md.77046314.lean.js" "b/assets/guide_ai_Retriever \345\270\270\350\247\201\347\232\204\344\274\230\345\214\226\346\226\271\345\274\217.md.a80c6c4a.lean.js" similarity index 86% rename from "assets/guide_ai_Retriever \345\270\270\350\247\201\347\232\204\344\274\230\345\214\226\346\226\271\345\274\217.md.77046314.lean.js" rename to "assets/guide_ai_Retriever \345\270\270\350\247\201\347\232\204\344\274\230\345\214\226\346\226\271\345\274\217.md.a80c6c4a.lean.js" index a692f763..d2f18be8 100644 --- "a/assets/guide_ai_Retriever \345\270\270\350\247\201\347\232\204\344\274\230\345\214\226\346\226\271\345\274\217.md.77046314.lean.js" +++ "b/assets/guide_ai_Retriever \345\270\270\350\247\201\347\232\204\344\274\230\345\214\226\346\226\271\345\274\217.md.a80c6c4a.lean.js" @@ -1 +1 @@ -import{_ as e,o as t,c as r}from"./chunks/framework.b6910bb2.js";const m=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"guide/ai/Retriever 常见的优化方式.md","filePath":"guide/ai/Retriever 常见的优化方式.md","lastUpdated":1718173557000}'),a={name:"guide/ai/Retriever 常见的优化方式.md"};function i(_,o,s,c,d,n){return t(),r("div")}const f=e(a,[["render",i]]);export{m as __pageData,f as default}; +import{_ as e,o as t,c as r}from"./chunks/framework.b6910bb2.js";const m=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"guide/ai/Retriever 常见的优化方式.md","filePath":"guide/ai/Retriever 常见的优化方式.md","lastUpdated":1718174182000}'),a={name:"guide/ai/Retriever 常见的优化方式.md"};function i(_,o,s,c,d,n){return t(),r("div")}const f=e(a,[["render",i]]);export{m as __pageData,f as default}; diff --git "a/assets/guide_ai_Retriever\344\271\213\345\220\221\351\207\217\346\225\260\346\215\256\345\272\223.md.877a77bf.js" "b/assets/guide_ai_Retriever\344\271\213\345\220\221\351\207\217\346\225\260\346\215\256\345\272\223.md.877a77bf.js" new file mode 100644 index 00000000..d7533606 --- /dev/null +++ "b/assets/guide_ai_Retriever\344\271\213\345\220\221\351\207\217\346\225\260\346\215\256\345\272\223.md.877a77bf.js" @@ -0,0 +1 @@ +import{_ as e,o as t,c as r}from"./chunks/framework.b6910bb2.js";const m=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"guide/ai/Retriever之向量数据库.md","filePath":"guide/ai/Retriever之向量数据库.md","lastUpdated":1718174182000}'),a={name:"guide/ai/Retriever之向量数据库.md"};function i(o,s,_,c,d,n){return t(),r("div")}const f=e(a,[["render",i]]);export{m as __pageData,f as default}; diff --git "a/assets/guide_ai_Retriever\344\271\213\345\220\221\351\207\217\346\225\260\346\215\256\345\272\223.md.877a77bf.lean.js" "b/assets/guide_ai_Retriever\344\271\213\345\220\221\351\207\217\346\225\260\346\215\256\345\272\223.md.877a77bf.lean.js" new file mode 100644 index 00000000..d7533606 --- /dev/null +++ "b/assets/guide_ai_Retriever\344\271\213\345\220\221\351\207\217\346\225\260\346\215\256\345\272\223.md.877a77bf.lean.js" @@ -0,0 +1 @@ +import{_ as e,o as t,c as r}from"./chunks/framework.b6910bb2.js";const m=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"guide/ai/Retriever之向量数据库.md","filePath":"guide/ai/Retriever之向量数据库.md","lastUpdated":1718174182000}'),a={name:"guide/ai/Retriever之向量数据库.md"};function i(o,s,_,c,d,n){return t(),r("div")}const f=e(a,[["render",i]]);export{m as __pageData,f as default}; diff --git "a/assets/guide_ai_langchain\345\277\253\351\200\237\345\205\245\351\227\250.md.6e950c2e.js" "b/assets/guide_ai_langchain\345\277\253\351\200\237\345\205\245\351\227\250.md.e62e22b3.js" similarity index 99% rename from "assets/guide_ai_langchain\345\277\253\351\200\237\345\205\245\351\227\250.md.6e950c2e.js" rename to "assets/guide_ai_langchain\345\277\253\351\200\237\345\205\245\351\227\250.md.e62e22b3.js" index 3a2000f0..5a436ec7 100644 --- "a/assets/guide_ai_langchain\345\277\253\351\200\237\345\205\245\351\227\250.md.6e950c2e.js" +++ "b/assets/guide_ai_langchain\345\277\253\351\200\237\345\205\245\351\227\250.md.e62e22b3.js" @@ -1,4 +1,4 @@ -import{_ as s,o as a,c as n,Q as l}from"./chunks/framework.b6910bb2.js";const o="/vitePress-blob/assets/1.111604b1.png",p="/vitePress-blob/assets/2.3cc0a64c.png",e="/vitePress-blob/assets/3.6ba488f9.png",F=JSON.parse('{"title":"LangChain 快速入门","description":"","frontmatter":{},"headers":[],"relativePath":"guide/ai/langchain快速入门.md","filePath":"guide/ai/langchain快速入门.md","lastUpdated":1718173557000}'),t={name:"guide/ai/langchain快速入门.md"},c=l(`

LangChain 快速入门

安装

要安装这个包,你可以使用 npm 或 yarn:

bash
yarn add langchain
yarn add langchain

安装环境

node >= 18.x

什么是 LCEL (LangChain Expression Language)

LangChain Expression Language is a way to create arbitrary custom chains. It is built on the Runnable protocol.

LCEL 无论是 python 还是 js 版本都在主推的新设计,能创建自定义的链,它是基于 Runnable 协议构建的。

通过 LangChain 加载大模型

本地大模型

在 mac 平台下,推荐用 ollama,使用简单,下载好模型后,点击这个 app,就会自动在 http://localhost:11434 起一个 llm 的服务。

安装 llama3 模型

可以通过 ollama list 查看所有的模型,然后通过 ollama pull 安装模型。

bash
# 模型列表参考:https://ollama.com/library
+import{_ as s,o as a,c as n,Q as l}from"./chunks/framework.b6910bb2.js";const o="/vitePress-blob/assets/1.111604b1.png",p="/vitePress-blob/assets/2.3cc0a64c.png",e="/vitePress-blob/assets/3.6ba488f9.png",F=JSON.parse('{"title":"LangChain 快速入门","description":"","frontmatter":{},"headers":[],"relativePath":"guide/ai/langchain快速入门.md","filePath":"guide/ai/langchain快速入门.md","lastUpdated":1718174182000}'),t={name:"guide/ai/langchain快速入门.md"},c=l(`

LangChain 快速入门

安装

要安装这个包,你可以使用 npm 或 yarn:

bash
yarn add langchain
yarn add langchain

安装环境

node >= 18.x

什么是 LCEL (LangChain Expression Language)

LangChain Expression Language is a way to create arbitrary custom chains. It is built on the Runnable protocol.

LCEL 无论是 python 还是 js 版本都在主推的新设计,能创建自定义的链,它是基于 Runnable 协议构建的。

通过 LangChain 加载大模型

本地大模型

在 mac 平台下,推荐用 ollama,使用简单,下载好模型后,点击这个 app,就会自动在 http://localhost:11434 起一个 llm 的服务。

安装 llama3 模型

可以通过 ollama list 查看所有的模型,然后通过 ollama pull 安装模型。

bash
# 模型列表参考:https://ollama.com/library
 ollama pull [model]
# 模型列表参考:https://ollama.com/library
 ollama pull [model]

目前下载了一个 ollama3 的模型

初始状态图

当我们在本地启动了一个模型后,我们就可以通过 LangChain 来调用这个模型了。

js
import { Ollama } from '@langchain/community/llms/ollama';
 
diff --git "a/assets/guide_ai_langchain\345\277\253\351\200\237\345\205\245\351\227\250.md.6e950c2e.lean.js" "b/assets/guide_ai_langchain\345\277\253\351\200\237\345\205\245\351\227\250.md.e62e22b3.lean.js"
similarity index 89%
rename from "assets/guide_ai_langchain\345\277\253\351\200\237\345\205\245\351\227\250.md.6e950c2e.lean.js"
rename to "assets/guide_ai_langchain\345\277\253\351\200\237\345\205\245\351\227\250.md.e62e22b3.lean.js"
index 848515e4..3f5e04e4 100644
--- "a/assets/guide_ai_langchain\345\277\253\351\200\237\345\205\245\351\227\250.md.6e950c2e.lean.js"
+++ "b/assets/guide_ai_langchain\345\277\253\351\200\237\345\205\245\351\227\250.md.e62e22b3.lean.js"
@@ -1 +1 @@
-import{_ as s,o as a,c as n,Q as l}from"./chunks/framework.b6910bb2.js";const o="/vitePress-blob/assets/1.111604b1.png",p="/vitePress-blob/assets/2.3cc0a64c.png",e="/vitePress-blob/assets/3.6ba488f9.png",F=JSON.parse('{"title":"LangChain 快速入门","description":"","frontmatter":{},"headers":[],"relativePath":"guide/ai/langchain快速入门.md","filePath":"guide/ai/langchain快速入门.md","lastUpdated":1718173557000}'),t={name:"guide/ai/langchain快速入门.md"},c=l("",44),r=[c];function i(E,y,h,d,u,g){return a(),n("div",null,r)}const b=s(t,[["render",i]]);export{F as __pageData,b as default};
+import{_ as s,o as a,c as n,Q as l}from"./chunks/framework.b6910bb2.js";const o="/vitePress-blob/assets/1.111604b1.png",p="/vitePress-blob/assets/2.3cc0a64c.png",e="/vitePress-blob/assets/3.6ba488f9.png",F=JSON.parse('{"title":"LangChain 快速入门","description":"","frontmatter":{},"headers":[],"relativePath":"guide/ai/langchain快速入门.md","filePath":"guide/ai/langchain快速入门.md","lastUpdated":1718174182000}'),t={name:"guide/ai/langchain快速入门.md"},c=l("",44),r=[c];function i(E,y,h,d,u,g){return a(),n("div",null,r)}const b=s(t,[["render",i]]);export{F as __pageData,b as default};
diff --git "a/assets/guide_ai_\344\273\200\344\271\210\346\230\257langchain.md.331802ff.js" "b/assets/guide_ai_\344\273\200\344\271\210\346\230\257langchain.md.61520c2b.js"
similarity index 98%
rename from "assets/guide_ai_\344\273\200\344\271\210\346\230\257langchain.md.331802ff.js"
rename to "assets/guide_ai_\344\273\200\344\271\210\346\230\257langchain.md.61520c2b.js"
index 1d35fcaa..ce3f983b 100644
--- "a/assets/guide_ai_\344\273\200\344\271\210\346\230\257langchain.md.331802ff.js"
+++ "b/assets/guide_ai_\344\273\200\344\271\210\346\230\257langchain.md.61520c2b.js"
@@ -1 +1 @@
-import{_ as a,o as n,c as i,Q as e}from"./chunks/framework.b6910bb2.js";const _=JSON.parse('{"title":"什么是 LangChain","description":"","frontmatter":{},"headers":[],"relativePath":"guide/ai/什么是langchain.md","filePath":"guide/ai/什么是langchain.md","lastUpdated":1718173557000}'),t={name:"guide/ai/什么是langchain.md"},r=e('

什么是 LangChain

LangChain 是一个用于开发由大型语言模型 (LLMs) 驱动的应用程序的框架。

为什么是 LangChain

因为 LLM 的 API 只是提供了一个非常基础的调用方式,当我们需要构建一个复杂的 Chat Bot 时,就需要考虑如何保存聊天的上下文、网络搜索、加载 PDF 等工程问题, 而LangChain 提供了一种解决方案,让开发者可以专注于业务逻辑的开发。

足够的流行度和认可度,目前已经在 Github 获得 83k star,并且其上升速度非常恐怖:

Star History Chart

而 LangChain.js 并不是 Python 版本的套壳,而是一个完整的团队从 0 开始构建的生态,足以看出官方对 JavaScript 生态的重视:

Star History Chart

基于此,在下将以 LangChain.js 为例,去使用大模型领域最流行的框架去构建应用,感受大模型的魅力。

支持的环境

  • Node.js (ESM and CommonJS) - 18.x, 19.x, 20.x
  • Cloudflare Workers Cloudflare
  • Vercel / Next.js (Browser, Serverless and Edge functions)
  • Supabase Edge Functions Supabase
  • Browser
  • Deno

相关文档

',13),l=[r];function h(s,o,c,g,p,d){return n(),i("div",null,l)}const u=a(t,[["render",h]]);export{_ as __pageData,u as default}; +import{_ as a,o as n,c as i,Q as e}from"./chunks/framework.b6910bb2.js";const _=JSON.parse('{"title":"什么是 LangChain","description":"","frontmatter":{},"headers":[],"relativePath":"guide/ai/什么是langchain.md","filePath":"guide/ai/什么是langchain.md","lastUpdated":1718174182000}'),t={name:"guide/ai/什么是langchain.md"},r=e('

什么是 LangChain

LangChain 是一个用于开发由大型语言模型 (LLMs) 驱动的应用程序的框架。

为什么是 LangChain

因为 LLM 的 API 只是提供了一个非常基础的调用方式,当我们需要构建一个复杂的 Chat Bot 时,就需要考虑如何保存聊天的上下文、网络搜索、加载 PDF 等工程问题, 而LangChain 提供了一种解决方案,让开发者可以专注于业务逻辑的开发。

足够的流行度和认可度,目前已经在 Github 获得 83k star,并且其上升速度非常恐怖:

Star History Chart

而 LangChain.js 并不是 Python 版本的套壳,而是一个完整的团队从 0 开始构建的生态,足以看出官方对 JavaScript 生态的重视:

Star History Chart

基于此,在下将以 LangChain.js 为例,去使用大模型领域最流行的框架去构建应用,感受大模型的魅力。

支持的环境

  • Node.js (ESM and CommonJS) - 18.x, 19.x, 20.x
  • Cloudflare Workers Cloudflare
  • Vercel / Next.js (Browser, Serverless and Edge functions)
  • Supabase Edge Functions Supabase
  • Browser
  • Deno

相关文档

',13),l=[r];function h(s,o,c,g,p,d){return n(),i("div",null,l)}const u=a(t,[["render",h]]);export{_ as __pageData,u as default}; diff --git "a/assets/guide_ai_\344\273\200\344\271\210\346\230\257langchain.md.331802ff.lean.js" "b/assets/guide_ai_\344\273\200\344\271\210\346\230\257langchain.md.61520c2b.lean.js" similarity index 86% rename from "assets/guide_ai_\344\273\200\344\271\210\346\230\257langchain.md.331802ff.lean.js" rename to "assets/guide_ai_\344\273\200\344\271\210\346\230\257langchain.md.61520c2b.lean.js" index 5c7490ec..d668f643 100644 --- "a/assets/guide_ai_\344\273\200\344\271\210\346\230\257langchain.md.331802ff.lean.js" +++ "b/assets/guide_ai_\344\273\200\344\271\210\346\230\257langchain.md.61520c2b.lean.js" @@ -1 +1 @@ -import{_ as a,o as n,c as i,Q as e}from"./chunks/framework.b6910bb2.js";const _=JSON.parse('{"title":"什么是 LangChain","description":"","frontmatter":{},"headers":[],"relativePath":"guide/ai/什么是langchain.md","filePath":"guide/ai/什么是langchain.md","lastUpdated":1718173557000}'),t={name:"guide/ai/什么是langchain.md"},r=e("",13),l=[r];function h(s,o,c,g,p,d){return n(),i("div",null,l)}const u=a(t,[["render",h]]);export{_ as __pageData,u as default}; +import{_ as a,o as n,c as i,Q as e}from"./chunks/framework.b6910bb2.js";const _=JSON.parse('{"title":"什么是 LangChain","description":"","frontmatter":{},"headers":[],"relativePath":"guide/ai/什么是langchain.md","filePath":"guide/ai/什么是langchain.md","lastUpdated":1718174182000}'),t={name:"guide/ai/什么是langchain.md"},r=e("",13),l=[r];function h(s,o,c,g,p,d){return n(),i("div",null,l)}const u=a(t,[["render",h]]);export{_ as __pageData,u as default}; diff --git "a/assets/guide_ai_\346\236\204\345\273\272\345\217\257\345\244\215\347\224\250\347\232\204PromptTemplate.md.ab8f853f.js" "b/assets/guide_ai_\346\236\204\345\273\272\345\217\257\345\244\215\347\224\250\347\232\204PromptTemplate.md.ba95d8c7.js" similarity index 99% rename from "assets/guide_ai_\346\236\204\345\273\272\345\217\257\345\244\215\347\224\250\347\232\204PromptTemplate.md.ab8f853f.js" rename to "assets/guide_ai_\346\236\204\345\273\272\345\217\257\345\244\215\347\224\250\347\232\204PromptTemplate.md.ba95d8c7.js" index e8585b31..d2bec71b 100644 --- "a/assets/guide_ai_\346\236\204\345\273\272\345\217\257\345\244\215\347\224\250\347\232\204PromptTemplate.md.ab8f853f.js" +++ "b/assets/guide_ai_\346\236\204\345\273\272\345\217\257\345\244\215\347\224\250\347\232\204PromptTemplate.md.ba95d8c7.js" @@ -1,4 +1,4 @@ -import{_ as s,o as a,c as n,Q as p}from"./chunks/framework.b6910bb2.js";const u=JSON.parse('{"title":"构建可复用的 PromptTemplate","description":"","frontmatter":{},"headers":[],"relativePath":"guide/ai/构建可复用的PromptTemplate.md","filePath":"guide/ai/构建可复用的PromptTemplate.md","lastUpdated":1718173557000}'),l={name:"guide/ai/构建可复用的PromptTemplate.md"},o=p(`

构建可复用的 PromptTemplate

Prompt 是大模型的核心,传统的方式一般是通过字符串或者字符串模版来构建 Prompt,但是这种方式不够灵活,也不够易用。为了解决这个问题,LangChain 引入了 PromptTemplate,它是一个可以复用的 Prompt 模版,可以通过参数化的方式来构建 Prompt。

基础的 Prompt 模版使用

js
// 基础的 Prompt 模版使用
+import{_ as s,o as a,c as n,Q as p}from"./chunks/framework.b6910bb2.js";const u=JSON.parse('{"title":"构建可复用的 PromptTemplate","description":"","frontmatter":{},"headers":[],"relativePath":"guide/ai/构建可复用的PromptTemplate.md","filePath":"guide/ai/构建可复用的PromptTemplate.md","lastUpdated":1718174182000}'),l={name:"guide/ai/构建可复用的PromptTemplate.md"},o=p(`

构建可复用的 PromptTemplate

Prompt 是大模型的核心,传统的方式一般是通过字符串或者字符串模版来构建 Prompt,但是这种方式不够灵活,也不够易用。为了解决这个问题,LangChain 引入了 PromptTemplate,它是一个可以复用的 Prompt 模版,可以通过参数化的方式来构建 Prompt。

基础的 Prompt 模版使用

js
// 基础的 Prompt 模版使用
 import { PromptTemplate } from "@langchain/core/prompts";
 
 const greetingPrompt = new PromptTemplate({
diff --git "a/assets/guide_ai_\346\236\204\345\273\272\345\217\257\345\244\215\347\224\250\347\232\204PromptTemplate.md.ab8f853f.lean.js" "b/assets/guide_ai_\346\236\204\345\273\272\345\217\257\345\244\215\347\224\250\347\232\204PromptTemplate.md.ba95d8c7.lean.js"
similarity index 87%
rename from "assets/guide_ai_\346\236\204\345\273\272\345\217\257\345\244\215\347\224\250\347\232\204PromptTemplate.md.ab8f853f.lean.js"
rename to "assets/guide_ai_\346\236\204\345\273\272\345\217\257\345\244\215\347\224\250\347\232\204PromptTemplate.md.ba95d8c7.lean.js"
index 098ea9e2..1f5d72f5 100644
--- "a/assets/guide_ai_\346\236\204\345\273\272\345\217\257\345\244\215\347\224\250\347\232\204PromptTemplate.md.ab8f853f.lean.js"
+++ "b/assets/guide_ai_\346\236\204\345\273\272\345\217\257\345\244\215\347\224\250\347\232\204PromptTemplate.md.ba95d8c7.lean.js"
@@ -1 +1 @@
-import{_ as s,o as a,c as n,Q as p}from"./chunks/framework.b6910bb2.js";const u=JSON.parse('{"title":"构建可复用的 PromptTemplate","description":"","frontmatter":{},"headers":[],"relativePath":"guide/ai/构建可复用的PromptTemplate.md","filePath":"guide/ai/构建可复用的PromptTemplate.md","lastUpdated":1718173557000}'),l={name:"guide/ai/构建可复用的PromptTemplate.md"},o=p("",18),e=[o];function t(c,r,E,y,i,m){return a(),n("div",null,e)}const d=s(l,[["render",t]]);export{u as __pageData,d as default};
+import{_ as s,o as a,c as n,Q as p}from"./chunks/framework.b6910bb2.js";const u=JSON.parse('{"title":"构建可复用的 PromptTemplate","description":"","frontmatter":{},"headers":[],"relativePath":"guide/ai/构建可复用的PromptTemplate.md","filePath":"guide/ai/构建可复用的PromptTemplate.md","lastUpdated":1718174182000}'),l={name:"guide/ai/构建可复用的PromptTemplate.md"},o=p("",18),e=[o];function t(c,r,E,y,i,m){return a(),n("div",null,e)}const d=s(l,[["render",t]]);export{u as __pageData,d as default};
diff --git "a/assets/guide_canvas_Canvas\345\260\272\345\257\270\345\217\212\345\210\206\350\276\250\347\216\207\347\237\253\346\255\243.md.47adbdaf.js" "b/assets/guide_canvas_Canvas\345\260\272\345\257\270\345\217\212\345\210\206\350\276\250\347\216\207\347\237\253\346\255\243.md.be47a824.js"
similarity index 99%
rename from "assets/guide_canvas_Canvas\345\260\272\345\257\270\345\217\212\345\210\206\350\276\250\347\216\207\347\237\253\346\255\243.md.47adbdaf.js"
rename to "assets/guide_canvas_Canvas\345\260\272\345\257\270\345\217\212\345\210\206\350\276\250\347\216\207\347\237\253\346\255\243.md.be47a824.js"
index b71611f4..a79d626e 100644
--- "a/assets/guide_canvas_Canvas\345\260\272\345\257\270\345\217\212\345\210\206\350\276\250\347\216\207\347\237\253\346\255\243.md.47adbdaf.js"
+++ "b/assets/guide_canvas_Canvas\345\260\272\345\257\270\345\217\212\345\210\206\350\276\250\347\216\207\347\237\253\346\255\243.md.be47a824.js"
@@ -1,4 +1,4 @@
-import{_ as s,o as a,c as n,Q as l}from"./chunks/framework.b6910bb2.js";const p="/vitePress-blob/assets/1.15edf814.png",o="/vitePress-blob/assets/2.19007fd9.png",t="/vitePress-blob/assets/3.59bb2b90.png",v=JSON.parse('{"title":"Canvas 尺寸与分辨率矫正","description":"","frontmatter":{},"headers":[],"relativePath":"guide/canvas/Canvas尺寸及分辨率矫正.md","filePath":"guide/canvas/Canvas尺寸及分辨率矫正.md","lastUpdated":1718173557000}'),e={name:"guide/canvas/Canvas尺寸及分辨率矫正.md"},c=l(`

Canvas 尺寸与分辨率矫正

前言

Canvas 的默认大小为 300 像素 ×150 像素(宽 × 高,像素的单位是 px)

html
<canvas id="tutorial" width="150" height="150"></canvas>
<canvas id="tutorial" width="150" height="150"></canvas>

canvas 看起来和 img 元素很相像,唯一的不同就是它并没有 src 和 alt 属性。实际上,canvas 标签只有两个属性: width 和 height。

正文

设置画布的 css 大小

canvas 可以使用CSS来定义大小,但在绘制时图像会伸缩以适应它的框架尺寸:如果 CSS 的尺寸与初始画布的比例不一致,它会出现扭曲。

假设一个场景,当我们给 canvas 设置了 css 的宽高 500px * 500px, 但是我们在 canvas 中绘制的图形是 100px * 100px, 那么最终的图形会被拉伸,如下图所示:

html
<canvas id="test-canvas"></canvas>
+import{_ as s,o as a,c as n,Q as l}from"./chunks/framework.b6910bb2.js";const p="/vitePress-blob/assets/1.15edf814.png",o="/vitePress-blob/assets/2.19007fd9.png",t="/vitePress-blob/assets/3.59bb2b90.png",v=JSON.parse('{"title":"Canvas 尺寸与分辨率矫正","description":"","frontmatter":{},"headers":[],"relativePath":"guide/canvas/Canvas尺寸及分辨率矫正.md","filePath":"guide/canvas/Canvas尺寸及分辨率矫正.md","lastUpdated":1718174182000}'),e={name:"guide/canvas/Canvas尺寸及分辨率矫正.md"},c=l(`

Canvas 尺寸与分辨率矫正

前言

Canvas 的默认大小为 300 像素 ×150 像素(宽 × 高,像素的单位是 px)

html
<canvas id="tutorial" width="150" height="150"></canvas>
<canvas id="tutorial" width="150" height="150"></canvas>

canvas 看起来和 img 元素很相像,唯一的不同就是它并没有 src 和 alt 属性。实际上,canvas 标签只有两个属性: width 和 height。

正文

设置画布的 css 大小

canvas 可以使用CSS来定义大小,但在绘制时图像会伸缩以适应它的框架尺寸:如果 CSS 的尺寸与初始画布的比例不一致,它会出现扭曲。

假设一个场景,当我们给 canvas 设置了 css 的宽高 500px * 500px, 但是我们在 canvas 中绘制的图形是 100px * 100px, 那么最终的图形会被拉伸,如下图所示:

html
<canvas id="test-canvas"></canvas>
 <script>
     const canvas = document.getElementById('test-canvas');
     const ctx = canvas.getContext('2d');
diff --git "a/assets/guide_canvas_Canvas\345\260\272\345\257\270\345\217\212\345\210\206\350\276\250\347\216\207\347\237\253\346\255\243.md.47adbdaf.lean.js" "b/assets/guide_canvas_Canvas\345\260\272\345\257\270\345\217\212\345\210\206\350\276\250\347\216\207\347\237\253\346\255\243.md.be47a824.lean.js"
similarity index 90%
rename from "assets/guide_canvas_Canvas\345\260\272\345\257\270\345\217\212\345\210\206\350\276\250\347\216\207\347\237\253\346\255\243.md.47adbdaf.lean.js"
rename to "assets/guide_canvas_Canvas\345\260\272\345\257\270\345\217\212\345\210\206\350\276\250\347\216\207\347\237\253\346\255\243.md.be47a824.lean.js"
index d7828044..61f51fb0 100644
--- "a/assets/guide_canvas_Canvas\345\260\272\345\257\270\345\217\212\345\210\206\350\276\250\347\216\207\347\237\253\346\255\243.md.47adbdaf.lean.js"
+++ "b/assets/guide_canvas_Canvas\345\260\272\345\257\270\345\217\212\345\210\206\350\276\250\347\216\207\347\237\253\346\255\243.md.be47a824.lean.js"
@@ -1 +1 @@
-import{_ as s,o as a,c as n,Q as l}from"./chunks/framework.b6910bb2.js";const p="/vitePress-blob/assets/1.15edf814.png",o="/vitePress-blob/assets/2.19007fd9.png",t="/vitePress-blob/assets/3.59bb2b90.png",v=JSON.parse('{"title":"Canvas 尺寸与分辨率矫正","description":"","frontmatter":{},"headers":[],"relativePath":"guide/canvas/Canvas尺寸及分辨率矫正.md","filePath":"guide/canvas/Canvas尺寸及分辨率矫正.md","lastUpdated":1718173557000}'),e={name:"guide/canvas/Canvas尺寸及分辨率矫正.md"},c=l("",29),r=[c];function E(y,i,F,d,h,C){return a(),n("div",null,r)}const u=s(e,[["render",E]]);export{v as __pageData,u as default};
+import{_ as s,o as a,c as n,Q as l}from"./chunks/framework.b6910bb2.js";const p="/vitePress-blob/assets/1.15edf814.png",o="/vitePress-blob/assets/2.19007fd9.png",t="/vitePress-blob/assets/3.59bb2b90.png",v=JSON.parse('{"title":"Canvas 尺寸与分辨率矫正","description":"","frontmatter":{},"headers":[],"relativePath":"guide/canvas/Canvas尺寸及分辨率矫正.md","filePath":"guide/canvas/Canvas尺寸及分辨率矫正.md","lastUpdated":1718174182000}'),e={name:"guide/canvas/Canvas尺寸及分辨率矫正.md"},c=l("",29),r=[c];function E(y,i,F,d,h,C){return a(),n("div",null,r)}const u=s(e,[["render",E]]);export{v as __pageData,u as default};
diff --git "a/assets/guide_canvas_\345\217\257\350\247\206\345\214\272\345\237\237\345\206\205\346\270\262\346\237\223\346\217\220\351\253\230Canvas\344\271\246\345\206\231\346\200\247\350\203\275.md.2bec03da.js" "b/assets/guide_canvas_\345\217\257\350\247\206\345\214\272\345\237\237\345\206\205\346\270\262\346\237\223\346\217\220\351\253\230Canvas\344\271\246\345\206\231\346\200\247\350\203\275.md.4ff663e0.js"
similarity index 99%
rename from "assets/guide_canvas_\345\217\257\350\247\206\345\214\272\345\237\237\345\206\205\346\270\262\346\237\223\346\217\220\351\253\230Canvas\344\271\246\345\206\231\346\200\247\350\203\275.md.2bec03da.js"
rename to "assets/guide_canvas_\345\217\257\350\247\206\345\214\272\345\237\237\345\206\205\346\270\262\346\237\223\346\217\220\351\253\230Canvas\344\271\246\345\206\231\346\200\247\350\203\275.md.4ff663e0.js"
index 1a592ded..a524a109 100644
--- "a/assets/guide_canvas_\345\217\257\350\247\206\345\214\272\345\237\237\345\206\205\346\270\262\346\237\223\346\217\220\351\253\230Canvas\344\271\246\345\206\231\346\200\247\350\203\275.md.2bec03da.js"
+++ "b/assets/guide_canvas_\345\217\257\350\247\206\345\214\272\345\237\237\345\206\205\346\270\262\346\237\223\346\217\220\351\253\230Canvas\344\271\246\345\206\231\346\200\247\350\203\275.md.4ff663e0.js"
@@ -1,4 +1,4 @@
-import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.b6910bb2.js";const p="/vitePress-blob/assets/13.ebfa1a54.png",o="/vitePress-blob/assets/14.92ddec45.png",e="/vitePress-blob/assets/15.3e4e2641.gif",t="/vitePress-blob/assets/17.75314470.png",c="/vitePress-blob/assets/18.34b0479f.gif",D=JSON.parse('{"title":"可视区域内渲染提高 Canvas 的书写性能","description":"","frontmatter":{},"headers":[],"relativePath":"guide/canvas/可视区域内渲染提高Canvas书写性能.md","filePath":"guide/canvas/可视区域内渲染提高Canvas书写性能.md","lastUpdated":1718173557000}'),r={name:"guide/canvas/可视区域内渲染提高Canvas书写性能.md"},E=l('

可视区域内渲染提高 Canvas 的书写性能

前言

上一节我们通过离屏渲染提高了 Canvas 的渲染性能,但是离屏渲染也有一些缺点,比如会增加内存的使用,而且在某些场景下,离屏渲染的性能并不会比直接在 Canvas 上绘制要高。本节我们将介绍如何通过可视区域内渲染提高 Canvas 的书写性能。

前提

一般我们说的可视区域内渲染,是指在 Canvas 上只绘制可视区域内的内容,而不是绘制整个 Canvas 的内容。这样做的好处是可以减少 Canvas 的绘制区域,从而提高 Canvas 的渲染性能。

对于 Canvas 而言,无法无限制地扩大 Canvas 的面积,因此浏览器对 Canvas 的大小也有一定的限制。从 MDN 文档 可知, 在 Chrome 浏览器中,Canvas 的大小限制为 32767px * 32767px。由于 Canvas 的大小限制,因此我们在实现 无限画布 的功能时,不能无限拓展 Canvas 的大小,可以通过坐标的切换,来实现无限画布的功能。

实现无限画布

实现思路

记初始坐标A (x, y), 横向滚动距离为 scrollX, 纵向滚动距离为 scrollY

在初始状态下, scrollX、scrollY 均为 0

初始状态图

假设现在,我们在水平方向向右滚动了scrollX,垂直方向向下滚动scrollY。那么滚动后的坐标就是

x1 = x - scrollX

y1 = y - scrollY

这里大家可能会有疑惑,为什么是减法呢?因为向下滚动后,绘制的图形应该是往上移动的,因此我们需要减去滚动的距离。

滚动后的状态图

在代码中,我们可以通过监听 Canvas 的 WheelEvent 事件,来获取滚动的距离,然后根据上面的公式计算出滚动后的坐标,最后重新绘制 Canvas。

具体实现如下

jsx
ctx.clearRect(0, 0, window.innerWidth, window.innerHeight);
+import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.b6910bb2.js";const p="/vitePress-blob/assets/13.ebfa1a54.png",o="/vitePress-blob/assets/14.92ddec45.png",e="/vitePress-blob/assets/15.3e4e2641.gif",t="/vitePress-blob/assets/17.75314470.png",c="/vitePress-blob/assets/18.34b0479f.gif",D=JSON.parse('{"title":"可视区域内渲染提高 Canvas 的书写性能","description":"","frontmatter":{},"headers":[],"relativePath":"guide/canvas/可视区域内渲染提高Canvas书写性能.md","filePath":"guide/canvas/可视区域内渲染提高Canvas书写性能.md","lastUpdated":1718174182000}'),r={name:"guide/canvas/可视区域内渲染提高Canvas书写性能.md"},E=l('

可视区域内渲染提高 Canvas 的书写性能

前言

上一节我们通过离屏渲染提高了 Canvas 的渲染性能,但是离屏渲染也有一些缺点,比如会增加内存的使用,而且在某些场景下,离屏渲染的性能并不会比直接在 Canvas 上绘制要高。本节我们将介绍如何通过可视区域内渲染提高 Canvas 的书写性能。

前提

一般我们说的可视区域内渲染,是指在 Canvas 上只绘制可视区域内的内容,而不是绘制整个 Canvas 的内容。这样做的好处是可以减少 Canvas 的绘制区域,从而提高 Canvas 的渲染性能。

对于 Canvas 而言,无法无限制地扩大 Canvas 的面积,因此浏览器对 Canvas 的大小也有一定的限制。从 MDN 文档 可知, 在 Chrome 浏览器中,Canvas 的大小限制为 32767px * 32767px。由于 Canvas 的大小限制,因此我们在实现 无限画布 的功能时,不能无限拓展 Canvas 的大小,可以通过坐标的切换,来实现无限画布的功能。

实现无限画布

实现思路

记初始坐标A (x, y), 横向滚动距离为 scrollX, 纵向滚动距离为 scrollY

在初始状态下, scrollX、scrollY 均为 0

初始状态图

假设现在,我们在水平方向向右滚动了scrollX,垂直方向向下滚动scrollY。那么滚动后的坐标就是

x1 = x - scrollX

y1 = y - scrollY

这里大家可能会有疑惑,为什么是减法呢?因为向下滚动后,绘制的图形应该是往上移动的,因此我们需要减去滚动的距离。

滚动后的状态图

在代码中,我们可以通过监听 Canvas 的 WheelEvent 事件,来获取滚动的距离,然后根据上面的公式计算出滚动后的坐标,最后重新绘制 Canvas。

具体实现如下

jsx
ctx.clearRect(0, 0, window.innerWidth, window.innerHeight);
 ctx.save();
 ctx.translate(scrollX, scrollY);
 // 绘制相关的逻辑
diff --git "a/assets/guide_canvas_\345\217\257\350\247\206\345\214\272\345\237\237\345\206\205\346\270\262\346\237\223\346\217\220\351\253\230Canvas\344\271\246\345\206\231\346\200\247\350\203\275.md.2bec03da.lean.js" "b/assets/guide_canvas_\345\217\257\350\247\206\345\214\272\345\237\237\345\206\205\346\270\262\346\237\223\346\217\220\351\253\230Canvas\344\271\246\345\206\231\346\200\247\350\203\275.md.4ff663e0.lean.js"
similarity index 92%
rename from "assets/guide_canvas_\345\217\257\350\247\206\345\214\272\345\237\237\345\206\205\346\270\262\346\237\223\346\217\220\351\253\230Canvas\344\271\246\345\206\231\346\200\247\350\203\275.md.2bec03da.lean.js"
rename to "assets/guide_canvas_\345\217\257\350\247\206\345\214\272\345\237\237\345\206\205\346\270\262\346\237\223\346\217\220\351\253\230Canvas\344\271\246\345\206\231\346\200\247\350\203\275.md.4ff663e0.lean.js"
index b18fc30b..c0c31988 100644
--- "a/assets/guide_canvas_\345\217\257\350\247\206\345\214\272\345\237\237\345\206\205\346\270\262\346\237\223\346\217\220\351\253\230Canvas\344\271\246\345\206\231\346\200\247\350\203\275.md.2bec03da.lean.js"
+++ "b/assets/guide_canvas_\345\217\257\350\247\206\345\214\272\345\237\237\345\206\205\346\270\262\346\237\223\346\217\220\351\253\230Canvas\344\271\246\345\206\231\346\200\247\350\203\275.md.4ff663e0.lean.js"
@@ -1 +1 @@
-import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.b6910bb2.js";const p="/vitePress-blob/assets/13.ebfa1a54.png",o="/vitePress-blob/assets/14.92ddec45.png",e="/vitePress-blob/assets/15.3e4e2641.gif",t="/vitePress-blob/assets/17.75314470.png",c="/vitePress-blob/assets/18.34b0479f.gif",D=JSON.parse('{"title":"可视区域内渲染提高 Canvas 的书写性能","description":"","frontmatter":{},"headers":[],"relativePath":"guide/canvas/可视区域内渲染提高Canvas书写性能.md","filePath":"guide/canvas/可视区域内渲染提高Canvas书写性能.md","lastUpdated":1718173557000}'),r={name:"guide/canvas/可视区域内渲染提高Canvas书写性能.md"},E=l("",46),y=[E];function i(F,d,m,h,C,A){return n(),a("div",null,y)}const x=s(r,[["render",i]]);export{D as __pageData,x as default};
+import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.b6910bb2.js";const p="/vitePress-blob/assets/13.ebfa1a54.png",o="/vitePress-blob/assets/14.92ddec45.png",e="/vitePress-blob/assets/15.3e4e2641.gif",t="/vitePress-blob/assets/17.75314470.png",c="/vitePress-blob/assets/18.34b0479f.gif",D=JSON.parse('{"title":"可视区域内渲染提高 Canvas 的书写性能","description":"","frontmatter":{},"headers":[],"relativePath":"guide/canvas/可视区域内渲染提高Canvas书写性能.md","filePath":"guide/canvas/可视区域内渲染提高Canvas书写性能.md","lastUpdated":1718174182000}'),r={name:"guide/canvas/可视区域内渲染提高Canvas书写性能.md"},E=l("",46),y=[E];function i(F,d,m,h,C,A){return n(),a("div",null,y)}const x=s(r,[["render",i]]);export{D as __pageData,x as default};
diff --git "a/assets/guide_canvas_\345\246\202\344\275\225\345\234\250Canvas\347\224\273\346\235\277\344\270\212\350\207\252\347\224\261\344\271\246\345\206\231.md.3d7cf139.js" "b/assets/guide_canvas_\345\246\202\344\275\225\345\234\250Canvas\347\224\273\346\235\277\344\270\212\350\207\252\347\224\261\344\271\246\345\206\231.md.a5b8d602.js"
similarity index 99%
rename from "assets/guide_canvas_\345\246\202\344\275\225\345\234\250Canvas\347\224\273\346\235\277\344\270\212\350\207\252\347\224\261\344\271\246\345\206\231.md.3d7cf139.js"
rename to "assets/guide_canvas_\345\246\202\344\275\225\345\234\250Canvas\347\224\273\346\235\277\344\270\212\350\207\252\347\224\261\344\271\246\345\206\231.md.a5b8d602.js"
index 5dee51c6..5086a5ed 100644
--- "a/assets/guide_canvas_\345\246\202\344\275\225\345\234\250Canvas\347\224\273\346\235\277\344\270\212\350\207\252\347\224\261\344\271\246\345\206\231.md.3d7cf139.js"
+++ "b/assets/guide_canvas_\345\246\202\344\275\225\345\234\250Canvas\347\224\273\346\235\277\344\270\212\350\207\252\347\224\261\344\271\246\345\206\231.md.a5b8d602.js"
@@ -1,4 +1,4 @@
-import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.b6910bb2.js";const p="/vitePress-blob/assets/4.6c4ce0eb.gif",o="/vitePress-blob/assets/6.bb9fb817.png",e="/vitePress-blob/assets/5.016fbc65.png",t="/vitePress-blob/assets/7.2b4ce5bb.gif",h=JSON.parse('{"title":"如何实现一个自由绘制的 Canvas 画板","description":"","frontmatter":{},"headers":[],"relativePath":"guide/canvas/如何在Canvas画板上自由书写.md","filePath":"guide/canvas/如何在Canvas画板上自由书写.md","lastUpdated":1718173557000}'),c={name:"guide/canvas/如何在Canvas画板上自由书写.md"},r=l(`

如何实现一个自由绘制的 Canvas 画板

前言

承接上文,当我们了解了如何去设置一个 Canvas 尺寸,并通过分辨率对 Canvas 进行矫正后,我们就可以开始实现一个自由绘制的 Canvas 画板了。

正文

实现思路

自由画笔的实现可以通过:

    1. 监听鼠标事件
    1. 将鼠标移动的点记录下来
    1. 将这些点连成线,就可以实现自由画笔了。

实现代码

html
<!DOCTYPE html>
+import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.b6910bb2.js";const p="/vitePress-blob/assets/4.6c4ce0eb.gif",o="/vitePress-blob/assets/6.bb9fb817.png",e="/vitePress-blob/assets/5.016fbc65.png",t="/vitePress-blob/assets/7.2b4ce5bb.gif",h=JSON.parse('{"title":"如何实现一个自由绘制的 Canvas 画板","description":"","frontmatter":{},"headers":[],"relativePath":"guide/canvas/如何在Canvas画板上自由书写.md","filePath":"guide/canvas/如何在Canvas画板上自由书写.md","lastUpdated":1718174182000}'),c={name:"guide/canvas/如何在Canvas画板上自由书写.md"},r=l(`

如何实现一个自由绘制的 Canvas 画板

前言

承接上文,当我们了解了如何去设置一个 Canvas 尺寸,并通过分辨率对 Canvas 进行矫正后,我们就可以开始实现一个自由绘制的 Canvas 画板了。

正文

实现思路

自由画笔的实现可以通过:

    1. 监听鼠标事件
    1. 将鼠标移动的点记录下来
    1. 将这些点连成线,就可以实现自由画笔了。

实现代码

html
<!DOCTYPE html>
 <html lang="en">
 
 <head>
diff --git "a/assets/guide_canvas_\345\246\202\344\275\225\345\234\250Canvas\347\224\273\346\235\277\344\270\212\350\207\252\347\224\261\344\271\246\345\206\231.md.3d7cf139.lean.js" "b/assets/guide_canvas_\345\246\202\344\275\225\345\234\250Canvas\347\224\273\346\235\277\344\270\212\350\207\252\347\224\261\344\271\246\345\206\231.md.a5b8d602.lean.js"
similarity index 91%
rename from "assets/guide_canvas_\345\246\202\344\275\225\345\234\250Canvas\347\224\273\346\235\277\344\270\212\350\207\252\347\224\261\344\271\246\345\206\231.md.3d7cf139.lean.js"
rename to "assets/guide_canvas_\345\246\202\344\275\225\345\234\250Canvas\347\224\273\346\235\277\344\270\212\350\207\252\347\224\261\344\271\246\345\206\231.md.a5b8d602.lean.js"
index 127b52b7..08caa221 100644
--- "a/assets/guide_canvas_\345\246\202\344\275\225\345\234\250Canvas\347\224\273\346\235\277\344\270\212\350\207\252\347\224\261\344\271\246\345\206\231.md.3d7cf139.lean.js"
+++ "b/assets/guide_canvas_\345\246\202\344\275\225\345\234\250Canvas\347\224\273\346\235\277\344\270\212\350\207\252\347\224\261\344\271\246\345\206\231.md.a5b8d602.lean.js"
@@ -1 +1 @@
-import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.b6910bb2.js";const p="/vitePress-blob/assets/4.6c4ce0eb.gif",o="/vitePress-blob/assets/6.bb9fb817.png",e="/vitePress-blob/assets/5.016fbc65.png",t="/vitePress-blob/assets/7.2b4ce5bb.gif",h=JSON.parse('{"title":"如何实现一个自由绘制的 Canvas 画板","description":"","frontmatter":{},"headers":[],"relativePath":"guide/canvas/如何在Canvas画板上自由书写.md","filePath":"guide/canvas/如何在Canvas画板上自由书写.md","lastUpdated":1718173557000}'),c={name:"guide/canvas/如何在Canvas画板上自由书写.md"},r=l("",23),E=[r];function y(i,F,C,A,D,d){return n(),a("div",null,E)}const B=s(c,[["render",y]]);export{h as __pageData,B as default};
+import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.b6910bb2.js";const p="/vitePress-blob/assets/4.6c4ce0eb.gif",o="/vitePress-blob/assets/6.bb9fb817.png",e="/vitePress-blob/assets/5.016fbc65.png",t="/vitePress-blob/assets/7.2b4ce5bb.gif",h=JSON.parse('{"title":"如何实现一个自由绘制的 Canvas 画板","description":"","frontmatter":{},"headers":[],"relativePath":"guide/canvas/如何在Canvas画板上自由书写.md","filePath":"guide/canvas/如何在Canvas画板上自由书写.md","lastUpdated":1718174182000}'),c={name:"guide/canvas/如何在Canvas画板上自由书写.md"},r=l("",23),E=[r];function y(i,F,C,A,D,d){return n(),a("div",null,E)}const B=s(c,[["render",y]]);export{h as __pageData,B as default};
diff --git "a/assets/guide_canvas_\351\200\232\350\277\207 OffscreenCanvas _ Worker \346\217\220\351\253\230\344\271\246\345\206\231\346\200\247\350\203\275.md.61b3946b.js" "b/assets/guide_canvas_\351\200\232\350\277\207 OffscreenCanvas _ Worker \346\217\220\351\253\230\344\271\246\345\206\231\346\200\247\350\203\275.md.0f8f23b4.js"
similarity index 99%
rename from "assets/guide_canvas_\351\200\232\350\277\207 OffscreenCanvas _ Worker \346\217\220\351\253\230\344\271\246\345\206\231\346\200\247\350\203\275.md.61b3946b.js"
rename to "assets/guide_canvas_\351\200\232\350\277\207 OffscreenCanvas _ Worker \346\217\220\351\253\230\344\271\246\345\206\231\346\200\247\350\203\275.md.0f8f23b4.js"
index 48c15dc5..3c9d0f81 100644
--- "a/assets/guide_canvas_\351\200\232\350\277\207 OffscreenCanvas _ Worker \346\217\220\351\253\230\344\271\246\345\206\231\346\200\247\350\203\275.md.61b3946b.js"	
+++ "b/assets/guide_canvas_\351\200\232\350\277\207 OffscreenCanvas _ Worker \346\217\220\351\253\230\344\271\246\345\206\231\346\200\247\350\203\275.md.0f8f23b4.js"	
@@ -1,4 +1,4 @@
-import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.b6910bb2.js";const p="/vitePress-blob/assets/19.ad6d5c6e.gif",h=JSON.parse('{"title":"通过 OffscreenCanvas + Worker 提高书写性能","description":"","frontmatter":{},"headers":[],"relativePath":"guide/canvas/通过 OffscreenCanvas + Worker 提高书写性能.md","filePath":"guide/canvas/通过 OffscreenCanvas + Worker 提高书写性能.md","lastUpdated":1718173557000}'),o={name:"guide/canvas/通过 OffscreenCanvas + Worker 提高书写性能.md"},e=l(`

通过 OffscreenCanvas + Worker 提高书写性能

前言

上一节我们通过离屏渲染提高了 Canvas 的渲染性能,但是在绘制的过程中,我们会发现,当绘制的图形越来越多时,Canvas 的渲染性能会越来越差,这是因为我们在绘制图形会阻塞主线程,如果主线程中还有其他的任务也会表现出卡顿的效果,Canvas 的渲染性能越来越差。

这节我们将通过 OffscreenCanvas + Worker 将绘制图形的任务放到 Worker 中进行,避免阻塞主线程,从而提高 Canvas 的渲染性能。

实现思路

在 worker 线程中是无法操作 DOM 的,但 OffscreenCanvas 可以在 worker 线程中进行操作,因此我们可以通过 OffscreenCanvas 将绘制图形的任务放到 worker 线程中进行。这样可以减少主线程的任务,从而提高书写性能。

具体实现

创建 OffscreenCanvas

js
const canvas = document.getElementById('draw');
+import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.b6910bb2.js";const p="/vitePress-blob/assets/19.ad6d5c6e.gif",h=JSON.parse('{"title":"通过 OffscreenCanvas + Worker 提高书写性能","description":"","frontmatter":{},"headers":[],"relativePath":"guide/canvas/通过 OffscreenCanvas + Worker 提高书写性能.md","filePath":"guide/canvas/通过 OffscreenCanvas + Worker 提高书写性能.md","lastUpdated":1718174182000}'),o={name:"guide/canvas/通过 OffscreenCanvas + Worker 提高书写性能.md"},e=l(`

通过 OffscreenCanvas + Worker 提高书写性能

前言

上一节我们通过离屏渲染提高了 Canvas 的渲染性能,但是在绘制的过程中,我们会发现,当绘制的图形越来越多时,Canvas 的渲染性能会越来越差,这是因为我们在绘制图形会阻塞主线程,如果主线程中还有其他的任务也会表现出卡顿的效果,Canvas 的渲染性能越来越差。

这节我们将通过 OffscreenCanvas + Worker 将绘制图形的任务放到 Worker 中进行,避免阻塞主线程,从而提高 Canvas 的渲染性能。

实现思路

在 worker 线程中是无法操作 DOM 的,但 OffscreenCanvas 可以在 worker 线程中进行操作,因此我们可以通过 OffscreenCanvas 将绘制图形的任务放到 worker 线程中进行。这样可以减少主线程的任务,从而提高书写性能。

具体实现

创建 OffscreenCanvas

js
const canvas = document.getElementById('draw');
 const offScreenCanvas = canvas.transferControlToOffscreen(); // 将 canvas 转换为 offScreenCanvas
const canvas = document.getElementById('draw');
 const offScreenCanvas = canvas.transferControlToOffscreen(); // 将 canvas 转换为 offScreenCanvas

将 offScreenCanvas 传递给 worker 线程

js
const worker = new Worker('./worker.js'); // 创建一个 webWorker
 const offScreenCanvas = canvas.transferControlToOffscreen(); // 将 canvas 转换为 offScreenCanvas
diff --git "a/assets/guide_canvas_\351\200\232\350\277\207 OffscreenCanvas _ Worker \346\217\220\351\253\230\344\271\246\345\206\231\346\200\247\350\203\275.md.61b3946b.lean.js" "b/assets/guide_canvas_\351\200\232\350\277\207 OffscreenCanvas _ Worker \346\217\220\351\253\230\344\271\246\345\206\231\346\200\247\350\203\275.md.0f8f23b4.lean.js"
similarity index 90%
rename from "assets/guide_canvas_\351\200\232\350\277\207 OffscreenCanvas _ Worker \346\217\220\351\253\230\344\271\246\345\206\231\346\200\247\350\203\275.md.61b3946b.lean.js"
rename to "assets/guide_canvas_\351\200\232\350\277\207 OffscreenCanvas _ Worker \346\217\220\351\253\230\344\271\246\345\206\231\346\200\247\350\203\275.md.0f8f23b4.lean.js"
index c2ab8928..7193100e 100644
--- "a/assets/guide_canvas_\351\200\232\350\277\207 OffscreenCanvas _ Worker \346\217\220\351\253\230\344\271\246\345\206\231\346\200\247\350\203\275.md.61b3946b.lean.js"	
+++ "b/assets/guide_canvas_\351\200\232\350\277\207 OffscreenCanvas _ Worker \346\217\220\351\253\230\344\271\246\345\206\231\346\200\247\350\203\275.md.0f8f23b4.lean.js"	
@@ -1 +1 @@
-import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.b6910bb2.js";const p="/vitePress-blob/assets/19.ad6d5c6e.gif",h=JSON.parse('{"title":"通过 OffscreenCanvas + Worker 提高书写性能","description":"","frontmatter":{},"headers":[],"relativePath":"guide/canvas/通过 OffscreenCanvas + Worker 提高书写性能.md","filePath":"guide/canvas/通过 OffscreenCanvas + Worker 提高书写性能.md","lastUpdated":1718173557000}'),o={name:"guide/canvas/通过 OffscreenCanvas + Worker 提高书写性能.md"},e=l("",18),r=[e];function c(t,E,y,i,d,f){return n(),a("div",null,r)}const v=s(o,[["render",c]]);export{h as __pageData,v as default};
+import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.b6910bb2.js";const p="/vitePress-blob/assets/19.ad6d5c6e.gif",h=JSON.parse('{"title":"通过 OffscreenCanvas + Worker 提高书写性能","description":"","frontmatter":{},"headers":[],"relativePath":"guide/canvas/通过 OffscreenCanvas + Worker 提高书写性能.md","filePath":"guide/canvas/通过 OffscreenCanvas + Worker 提高书写性能.md","lastUpdated":1718174182000}'),o={name:"guide/canvas/通过 OffscreenCanvas + Worker 提高书写性能.md"},e=l("",18),r=[e];function c(t,E,y,i,d,f){return n(),a("div",null,r)}const v=s(o,[["render",c]]);export{h as __pageData,v as default};
diff --git "a/assets/guide_canvas_\351\200\232\350\277\207\344\270\212\344\270\213\345\210\206\345\261\202\344\274\230\345\214\226Canvas\344\271\246\345\206\231\346\200\247\350\203\275.md.94e516ad.js" "b/assets/guide_canvas_\351\200\232\350\277\207\344\270\212\344\270\213\345\210\206\345\261\202\344\274\230\345\214\226Canvas\344\271\246\345\206\231\346\200\247\350\203\275.md.0754eb3f.js"
similarity index 99%
rename from "assets/guide_canvas_\351\200\232\350\277\207\344\270\212\344\270\213\345\210\206\345\261\202\344\274\230\345\214\226Canvas\344\271\246\345\206\231\346\200\247\350\203\275.md.94e516ad.js"
rename to "assets/guide_canvas_\351\200\232\350\277\207\344\270\212\344\270\213\345\210\206\345\261\202\344\274\230\345\214\226Canvas\344\271\246\345\206\231\346\200\247\350\203\275.md.0754eb3f.js"
index 994feab2..53dc3f02 100644
--- "a/assets/guide_canvas_\351\200\232\350\277\207\344\270\212\344\270\213\345\210\206\345\261\202\344\274\230\345\214\226Canvas\344\271\246\345\206\231\346\200\247\350\203\275.md.94e516ad.js"
+++ "b/assets/guide_canvas_\351\200\232\350\277\207\344\270\212\344\270\213\345\210\206\345\261\202\344\274\230\345\214\226Canvas\344\271\246\345\206\231\346\200\247\350\203\275.md.0754eb3f.js"
@@ -1,4 +1,4 @@
-import{_ as s,o as a,c as n,Q as l}from"./chunks/framework.b6910bb2.js";const p="/vitePress-blob/assets/10.57bb4969.gif",o="/vitePress-blob/assets/11.298d6f19.gif",h=JSON.parse('{"title":"通过上下分层优化 Canvas 书写性能","description":"","frontmatter":{},"headers":[],"relativePath":"guide/canvas/通过上下分层优化Canvas书写性能.md","filePath":"guide/canvas/通过上下分层优化Canvas书写性能.md","lastUpdated":1718173557000}'),e={name:"guide/canvas/通过上下分层优化Canvas书写性能.md"},t=l(`

通过上下分层优化 Canvas 书写性能

前言

上一节,我们通过点稀疏的方式,优化了 Canvas 的绘制性能。但在书写的过程中,因为点的数量减少导致书写的效果不够理想,因此通过贝塞尔曲线的方式,将点连接起来,形成平滑的曲线,从而达到书写的效果。 这节,我们将通过上下分层的方式,优化 Canvas 的书写性能。

基本思路

这里我将 Canvas 分为上下两层,上层称之为动态层,下层称之为静态层,动态层用于书写,静态层用于显示书写的效果。当书写的时候,将书写的点绘制到上层,当书写完成后,将上层的内容绘制到下层,然后清空上层的内容,这样就可以达到书写的效果。

因为 Canvas 每次渲染都会将整个 Canvas 清空,所以我们需要将静态层的内容保存下来,然后在每次书写的时候,只需要渲染当前动态层的内容即可。

实现

创建 2 个 Canvas

首先创建 2 个 Canvas, 上层 Canvas 用于书写, 书写完成后将上层 Canvas 的内容绘制到下层 Canvas 中, 然后清空上层 Canvas 的内容, 这样就可以达到书写的效果。

这样的好处在于, 每次书写的时候, 只需要渲染上层 Canvas 的书写内容即可, 不需要每次都渲染整个 Canvas, 从而达到优化性能的目的。

html
<style>
+import{_ as s,o as a,c as n,Q as l}from"./chunks/framework.b6910bb2.js";const p="/vitePress-blob/assets/10.57bb4969.gif",o="/vitePress-blob/assets/11.298d6f19.gif",h=JSON.parse('{"title":"通过上下分层优化 Canvas 书写性能","description":"","frontmatter":{},"headers":[],"relativePath":"guide/canvas/通过上下分层优化Canvas书写性能.md","filePath":"guide/canvas/通过上下分层优化Canvas书写性能.md","lastUpdated":1718174182000}'),e={name:"guide/canvas/通过上下分层优化Canvas书写性能.md"},t=l(`

通过上下分层优化 Canvas 书写性能

前言

上一节,我们通过点稀疏的方式,优化了 Canvas 的绘制性能。但在书写的过程中,因为点的数量减少导致书写的效果不够理想,因此通过贝塞尔曲线的方式,将点连接起来,形成平滑的曲线,从而达到书写的效果。 这节,我们将通过上下分层的方式,优化 Canvas 的书写性能。

基本思路

这里我将 Canvas 分为上下两层,上层称之为动态层,下层称之为静态层,动态层用于书写,静态层用于显示书写的效果。当书写的时候,将书写的点绘制到上层,当书写完成后,将上层的内容绘制到下层,然后清空上层的内容,这样就可以达到书写的效果。

因为 Canvas 每次渲染都会将整个 Canvas 清空,所以我们需要将静态层的内容保存下来,然后在每次书写的时候,只需要渲染当前动态层的内容即可。

实现

创建 2 个 Canvas

首先创建 2 个 Canvas, 上层 Canvas 用于书写, 书写完成后将上层 Canvas 的内容绘制到下层 Canvas 中, 然后清空上层 Canvas 的内容, 这样就可以达到书写的效果。

这样的好处在于, 每次书写的时候, 只需要渲染上层 Canvas 的书写内容即可, 不需要每次都渲染整个 Canvas, 从而达到优化性能的目的。

html
<style>
     #draw {
         border: 1px solid black;
         position: absolute;
diff --git "a/assets/guide_canvas_\351\200\232\350\277\207\344\270\212\344\270\213\345\210\206\345\261\202\344\274\230\345\214\226Canvas\344\271\246\345\206\231\346\200\247\350\203\275.md.94e516ad.lean.js" "b/assets/guide_canvas_\351\200\232\350\277\207\344\270\212\344\270\213\345\210\206\345\261\202\344\274\230\345\214\226Canvas\344\271\246\345\206\231\346\200\247\350\203\275.md.0754eb3f.lean.js"
similarity index 90%
rename from "assets/guide_canvas_\351\200\232\350\277\207\344\270\212\344\270\213\345\210\206\345\261\202\344\274\230\345\214\226Canvas\344\271\246\345\206\231\346\200\247\350\203\275.md.94e516ad.lean.js"
rename to "assets/guide_canvas_\351\200\232\350\277\207\344\270\212\344\270\213\345\210\206\345\261\202\344\274\230\345\214\226Canvas\344\271\246\345\206\231\346\200\247\350\203\275.md.0754eb3f.lean.js"
index a2fbdcee..47bcf8ca 100644
--- "a/assets/guide_canvas_\351\200\232\350\277\207\344\270\212\344\270\213\345\210\206\345\261\202\344\274\230\345\214\226Canvas\344\271\246\345\206\231\346\200\247\350\203\275.md.94e516ad.lean.js"
+++ "b/assets/guide_canvas_\351\200\232\350\277\207\344\270\212\344\270\213\345\210\206\345\261\202\344\274\230\345\214\226Canvas\344\271\246\345\206\231\346\200\247\350\203\275.md.0754eb3f.lean.js"
@@ -1 +1 @@
-import{_ as s,o as a,c as n,Q as l}from"./chunks/framework.b6910bb2.js";const p="/vitePress-blob/assets/10.57bb4969.gif",o="/vitePress-blob/assets/11.298d6f19.gif",h=JSON.parse('{"title":"通过上下分层优化 Canvas 书写性能","description":"","frontmatter":{},"headers":[],"relativePath":"guide/canvas/通过上下分层优化Canvas书写性能.md","filePath":"guide/canvas/通过上下分层优化Canvas书写性能.md","lastUpdated":1718173557000}'),e={name:"guide/canvas/通过上下分层优化Canvas书写性能.md"},t=l("",22),c=[t];function r(E,y,i,d,C,v){return a(),n("div",null,c)}const u=s(e,[["render",r]]);export{h as __pageData,u as default};
+import{_ as s,o as a,c as n,Q as l}from"./chunks/framework.b6910bb2.js";const p="/vitePress-blob/assets/10.57bb4969.gif",o="/vitePress-blob/assets/11.298d6f19.gif",h=JSON.parse('{"title":"通过上下分层优化 Canvas 书写性能","description":"","frontmatter":{},"headers":[],"relativePath":"guide/canvas/通过上下分层优化Canvas书写性能.md","filePath":"guide/canvas/通过上下分层优化Canvas书写性能.md","lastUpdated":1718174182000}'),e={name:"guide/canvas/通过上下分层优化Canvas书写性能.md"},t=l("",22),c=[t];function r(E,y,i,d,C,v){return a(),n("div",null,c)}const u=s(e,[["render",r]]);export{h as __pageData,u as default};
diff --git "a/assets/guide_canvas_\351\200\232\350\277\207\347\246\273\345\261\217\346\270\262\346\237\223\346\217\220\351\253\230Canvas\344\271\246\345\206\231\346\200\247\350\203\275.md.95d73a61.js" "b/assets/guide_canvas_\351\200\232\350\277\207\347\246\273\345\261\217\346\270\262\346\237\223\346\217\220\351\253\230Canvas\344\271\246\345\206\231\346\200\247\350\203\275.md.c367c715.js"
similarity index 99%
rename from "assets/guide_canvas_\351\200\232\350\277\207\347\246\273\345\261\217\346\270\262\346\237\223\346\217\220\351\253\230Canvas\344\271\246\345\206\231\346\200\247\350\203\275.md.95d73a61.js"
rename to "assets/guide_canvas_\351\200\232\350\277\207\347\246\273\345\261\217\346\270\262\346\237\223\346\217\220\351\253\230Canvas\344\271\246\345\206\231\346\200\247\350\203\275.md.c367c715.js"
index 2baf28ad..c3c74591 100644
--- "a/assets/guide_canvas_\351\200\232\350\277\207\347\246\273\345\261\217\346\270\262\346\237\223\346\217\220\351\253\230Canvas\344\271\246\345\206\231\346\200\247\350\203\275.md.95d73a61.js"
+++ "b/assets/guide_canvas_\351\200\232\350\277\207\347\246\273\345\261\217\346\270\262\346\237\223\346\217\220\351\253\230Canvas\344\271\246\345\206\231\346\200\247\350\203\275.md.c367c715.js"
@@ -1,4 +1,4 @@
-import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.b6910bb2.js";const p="/vitePress-blob/assets/12.31e4f330.gif",D=JSON.parse('{"title":"通过离屏渲染提高 Canvas 书写性能","description":"","frontmatter":{},"headers":[],"relativePath":"guide/canvas/通过离屏渲染提高Canvas书写性能.md","filePath":"guide/canvas/通过离屏渲染提高Canvas书写性能.md","lastUpdated":1718173557000}'),o={name:"guide/canvas/通过离屏渲染提高Canvas书写性能.md"},e=l(`

通过离屏渲染提高 Canvas 书写性能

前言

前面我们通过上下分层的方式,优化了 Canvas 的书写性能,接下来我们通过离屏渲染的方式,进一步优化 Canvas 的书写性能。

基本思路

在书写的过程中,每绘制一笔都需要不断地调用 Canvas 的 API,重新渲染整个 Canvas,这样就会导致性能的浪费。 而离屏渲染则是将 绘制内容存储到离屏的 Canvas 中,相当于一个缓冲区,然后将需要绘制的画面在离屏的 Canvas 缓冲好,最后将离屏的 Canvas 转化成图片,渲染到屏幕上,这样就可以达到优化性能的目的。

实现

创建离屏 Canvas

思路如下: 基于上一节的基础,我们改写 render 函数,如果是离屏渲染的话,将绘制的内容存储到离屏的 Canvas 中,然后将离屏的 Canvas 缓存起来,下次绘制的时候,如果命中缓存的话,就直接使用缓存的 Canvas,从而达到优化性能的目的。

操作如下:

  • 1 在执行 render 函数之前,先判断是否存在缓存的 Canvas,如果存在的话,就直接使用缓存的 Canvas
  • 2 如果命中缓存,使用离屏 Canvas 转化成图片进行绘制
  • 3 如果不存在缓存的 Canvas,就创建一个离屏的 Canvas,然后将绘制的内容存储到离屏的 Canvas 中,最后将离屏的 Canvas 缓存起来
html
<script>
+import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.b6910bb2.js";const p="/vitePress-blob/assets/12.31e4f330.gif",D=JSON.parse('{"title":"通过离屏渲染提高 Canvas 书写性能","description":"","frontmatter":{},"headers":[],"relativePath":"guide/canvas/通过离屏渲染提高Canvas书写性能.md","filePath":"guide/canvas/通过离屏渲染提高Canvas书写性能.md","lastUpdated":1718174182000}'),o={name:"guide/canvas/通过离屏渲染提高Canvas书写性能.md"},e=l(`

通过离屏渲染提高 Canvas 书写性能

前言

前面我们通过上下分层的方式,优化了 Canvas 的书写性能,接下来我们通过离屏渲染的方式,进一步优化 Canvas 的书写性能。

基本思路

在书写的过程中,每绘制一笔都需要不断地调用 Canvas 的 API,重新渲染整个 Canvas,这样就会导致性能的浪费。 而离屏渲染则是将 绘制内容存储到离屏的 Canvas 中,相当于一个缓冲区,然后将需要绘制的画面在离屏的 Canvas 缓冲好,最后将离屏的 Canvas 转化成图片,渲染到屏幕上,这样就可以达到优化性能的目的。

实现

创建离屏 Canvas

思路如下: 基于上一节的基础,我们改写 render 函数,如果是离屏渲染的话,将绘制的内容存储到离屏的 Canvas 中,然后将离屏的 Canvas 缓存起来,下次绘制的时候,如果命中缓存的话,就直接使用缓存的 Canvas,从而达到优化性能的目的。

操作如下:

  • 1 在执行 render 函数之前,先判断是否存在缓存的 Canvas,如果存在的话,就直接使用缓存的 Canvas
  • 2 如果命中缓存,使用离屏 Canvas 转化成图片进行绘制
  • 3 如果不存在缓存的 Canvas,就创建一个离屏的 Canvas,然后将绘制的内容存储到离屏的 Canvas 中,最后将离屏的 Canvas 缓存起来
html
<script>
         const elementWithCanvasCache = new WeakMap(); // 用于存储离屏 Canvas 的缓存
         const generateOffScreenCanvas = (points) => {
             const padding = 20; // 避免笔记被 Canvas 
diff --git "a/assets/guide_canvas_\351\200\232\350\277\207\347\246\273\345\261\217\346\270\262\346\237\223\346\217\220\351\253\230Canvas\344\271\246\345\206\231\346\200\247\350\203\275.md.95d73a61.lean.js" "b/assets/guide_canvas_\351\200\232\350\277\207\347\246\273\345\261\217\346\270\262\346\237\223\346\217\220\351\253\230Canvas\344\271\246\345\206\231\346\200\247\350\203\275.md.c367c715.lean.js"
similarity index 89%
rename from "assets/guide_canvas_\351\200\232\350\277\207\347\246\273\345\261\217\346\270\262\346\237\223\346\217\220\351\253\230Canvas\344\271\246\345\206\231\346\200\247\350\203\275.md.95d73a61.lean.js"
rename to "assets/guide_canvas_\351\200\232\350\277\207\347\246\273\345\261\217\346\270\262\346\237\223\346\217\220\351\253\230Canvas\344\271\246\345\206\231\346\200\247\350\203\275.md.c367c715.lean.js"
index b38fe876..2e585202 100644
--- "a/assets/guide_canvas_\351\200\232\350\277\207\347\246\273\345\261\217\346\270\262\346\237\223\346\217\220\351\253\230Canvas\344\271\246\345\206\231\346\200\247\350\203\275.md.95d73a61.lean.js"
+++ "b/assets/guide_canvas_\351\200\232\350\277\207\347\246\273\345\261\217\346\270\262\346\237\223\346\217\220\351\253\230Canvas\344\271\246\345\206\231\346\200\247\350\203\275.md.c367c715.lean.js"
@@ -1 +1 @@
-import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.b6910bb2.js";const p="/vitePress-blob/assets/12.31e4f330.gif",D=JSON.parse('{"title":"通过离屏渲染提高 Canvas 书写性能","description":"","frontmatter":{},"headers":[],"relativePath":"guide/canvas/通过离屏渲染提高Canvas书写性能.md","filePath":"guide/canvas/通过离屏渲染提高Canvas书写性能.md","lastUpdated":1718173557000}'),o={name:"guide/canvas/通过离屏渲染提高Canvas书写性能.md"},e=l("",19),t=[e];function c(r,E,y,i,F,C){return n(),a("div",null,t)}const h=s(o,[["render",c]]);export{D as __pageData,h as default};
+import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.b6910bb2.js";const p="/vitePress-blob/assets/12.31e4f330.gif",D=JSON.parse('{"title":"通过离屏渲染提高 Canvas 书写性能","description":"","frontmatter":{},"headers":[],"relativePath":"guide/canvas/通过离屏渲染提高Canvas书写性能.md","filePath":"guide/canvas/通过离屏渲染提高Canvas书写性能.md","lastUpdated":1718174182000}'),o={name:"guide/canvas/通过离屏渲染提高Canvas书写性能.md"},e=l("",19),t=[e];function c(r,E,y,i,F,C){return n(),a("div",null,t)}const h=s(o,[["render",c]]);export{D as __pageData,h as default};
diff --git "a/assets/guide_canvas_\351\200\232\350\277\207\350\264\235\345\241\236\345\260\224\346\233\262\347\272\277\344\274\230\345\214\226Canvas\344\271\246\345\206\231\346\200\247\350\203\275.md.158a433c.js" "b/assets/guide_canvas_\351\200\232\350\277\207\350\264\235\345\241\236\345\260\224\346\233\262\347\272\277\344\274\230\345\214\226Canvas\344\271\246\345\206\231\346\200\247\350\203\275.md.c60e183e.js"
similarity index 99%
rename from "assets/guide_canvas_\351\200\232\350\277\207\350\264\235\345\241\236\345\260\224\346\233\262\347\272\277\344\274\230\345\214\226Canvas\344\271\246\345\206\231\346\200\247\350\203\275.md.158a433c.js"
rename to "assets/guide_canvas_\351\200\232\350\277\207\350\264\235\345\241\236\345\260\224\346\233\262\347\272\277\344\274\230\345\214\226Canvas\344\271\246\345\206\231\346\200\247\350\203\275.md.c60e183e.js"
index 87cc6945..9cf075c5 100644
--- "a/assets/guide_canvas_\351\200\232\350\277\207\350\264\235\345\241\236\345\260\224\346\233\262\347\272\277\344\274\230\345\214\226Canvas\344\271\246\345\206\231\346\200\247\350\203\275.md.158a433c.js"
+++ "b/assets/guide_canvas_\351\200\232\350\277\207\350\264\235\345\241\236\345\260\224\346\233\262\347\272\277\344\274\230\345\214\226Canvas\344\271\246\345\206\231\346\200\247\350\203\275.md.c60e183e.js"
@@ -1,4 +1,4 @@
-import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.b6910bb2.js";const p="/vitePress-blob/assets/8.4bb53b64.gif",o="/vitePress-blob/assets/9.4148f2f2.gif",d=JSON.parse('{"title":"通过贝塞尔曲线解决 Canvas 书写的圆滑问题","description":"","frontmatter":{},"headers":[],"relativePath":"guide/canvas/通过贝塞尔曲线优化Canvas书写性能.md","filePath":"guide/canvas/通过贝塞尔曲线优化Canvas书写性能.md","lastUpdated":1718173557000}'),e={name:"guide/canvas/通过贝塞尔曲线优化Canvas书写性能.md"},t=l('

通过贝塞尔曲线解决 Canvas 书写的圆滑问题

前言

书接上回,当我们实现了一个自由书写的 Canvas 画板后,我们发现采集的点越少,画出来的圈圈越不圆润,这时候我们可以使用贝塞尔曲线来优化书写。

canvas

正文

贝塞尔曲线

贝塞尔曲线是一种数学曲线,常见的有: 线性贝塞尔曲线、二次·贝塞尔曲线、三次贝塞尔曲线等, 它可以用来实现平滑曲线,我们可以通过贝塞尔曲线以相对圆滑的方式来优化我们的 Canvas 书写。

优化思路

我们可以通过贝塞尔曲线来优化我们的 Canvas 书写性能,将笔直的线变的更加圆滑弯曲。

在 Canvas2D API 中有一个方法叫做 quadraticCurveTo 用于创建二次贝塞尔曲线。它需要两个点:一个控制点和一个终点。曲线从当前的绘图位置开始绘制,并以控制点为参考,向终点绘制曲线。

这个方法的语法是:context.quadraticCurveTo(cp1x, cp1y, x, y);

其中:

cp1x 和 cp1y 是控制点坐标。
+import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.b6910bb2.js";const p="/vitePress-blob/assets/8.4bb53b64.gif",o="/vitePress-blob/assets/9.4148f2f2.gif",d=JSON.parse('{"title":"通过贝塞尔曲线解决 Canvas 书写的圆滑问题","description":"","frontmatter":{},"headers":[],"relativePath":"guide/canvas/通过贝塞尔曲线优化Canvas书写性能.md","filePath":"guide/canvas/通过贝塞尔曲线优化Canvas书写性能.md","lastUpdated":1718174182000}'),e={name:"guide/canvas/通过贝塞尔曲线优化Canvas书写性能.md"},t=l('

通过贝塞尔曲线解决 Canvas 书写的圆滑问题

前言

书接上回,当我们实现了一个自由书写的 Canvas 画板后,我们发现采集的点越少,画出来的圈圈越不圆润,这时候我们可以使用贝塞尔曲线来优化书写。

canvas

正文

贝塞尔曲线

贝塞尔曲线是一种数学曲线,常见的有: 线性贝塞尔曲线、二次·贝塞尔曲线、三次贝塞尔曲线等, 它可以用来实现平滑曲线,我们可以通过贝塞尔曲线以相对圆滑的方式来优化我们的 Canvas 书写。

优化思路

我们可以通过贝塞尔曲线来优化我们的 Canvas 书写性能,将笔直的线变的更加圆滑弯曲。

在 Canvas2D API 中有一个方法叫做 quadraticCurveTo 用于创建二次贝塞尔曲线。它需要两个点:一个控制点和一个终点。曲线从当前的绘图位置开始绘制,并以控制点为参考,向终点绘制曲线。

这个方法的语法是:context.quadraticCurveTo(cp1x, cp1y, x, y);

其中:

cp1x 和 cp1y 是控制点坐标。
 x 和 y 是终点坐标。
 

这个方法不会直接绘制曲线,而是将曲线添加到当前的路径中。要在画布上实际绘制曲线,你需要使用 stroke 或 fill 方法

优化实现

1 采集到所有的点集 2 前一个点作为控制点,当前点作为终点,绘制二次贝塞尔曲线

html
<!DOCTYPE html>
 <html lang="en">
diff --git "a/assets/guide_canvas_\351\200\232\350\277\207\350\264\235\345\241\236\345\260\224\346\233\262\347\272\277\344\274\230\345\214\226Canvas\344\271\246\345\206\231\346\200\247\350\203\275.md.158a433c.lean.js" "b/assets/guide_canvas_\351\200\232\350\277\207\350\264\235\345\241\236\345\260\224\346\233\262\347\272\277\344\274\230\345\214\226Canvas\344\271\246\345\206\231\346\200\247\350\203\275.md.c60e183e.lean.js"
similarity index 90%
rename from "assets/guide_canvas_\351\200\232\350\277\207\350\264\235\345\241\236\345\260\224\346\233\262\347\272\277\344\274\230\345\214\226Canvas\344\271\246\345\206\231\346\200\247\350\203\275.md.158a433c.lean.js"
rename to "assets/guide_canvas_\351\200\232\350\277\207\350\264\235\345\241\236\345\260\224\346\233\262\347\272\277\344\274\230\345\214\226Canvas\344\271\246\345\206\231\346\200\247\350\203\275.md.c60e183e.lean.js"
index 9752e3a6..73cb3a30 100644
--- "a/assets/guide_canvas_\351\200\232\350\277\207\350\264\235\345\241\236\345\260\224\346\233\262\347\272\277\344\274\230\345\214\226Canvas\344\271\246\345\206\231\346\200\247\350\203\275.md.158a433c.lean.js"
+++ "b/assets/guide_canvas_\351\200\232\350\277\207\350\264\235\345\241\236\345\260\224\346\233\262\347\272\277\344\274\230\345\214\226Canvas\344\271\246\345\206\231\346\200\247\350\203\275.md.c60e183e.lean.js"
@@ -1 +1 @@
-import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.b6910bb2.js";const p="/vitePress-blob/assets/8.4bb53b64.gif",o="/vitePress-blob/assets/9.4148f2f2.gif",d=JSON.parse('{"title":"通过贝塞尔曲线解决 Canvas 书写的圆滑问题","description":"","frontmatter":{},"headers":[],"relativePath":"guide/canvas/通过贝塞尔曲线优化Canvas书写性能.md","filePath":"guide/canvas/通过贝塞尔曲线优化Canvas书写性能.md","lastUpdated":1718173557000}'),e={name:"guide/canvas/通过贝塞尔曲线优化Canvas书写性能.md"},t=l("",21),c=[t];function r(E,y,i,F,A,C){return n(),a("div",null,c)}const u=s(e,[["render",r]]);export{d as __pageData,u as default};
+import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.b6910bb2.js";const p="/vitePress-blob/assets/8.4bb53b64.gif",o="/vitePress-blob/assets/9.4148f2f2.gif",d=JSON.parse('{"title":"通过贝塞尔曲线解决 Canvas 书写的圆滑问题","description":"","frontmatter":{},"headers":[],"relativePath":"guide/canvas/通过贝塞尔曲线优化Canvas书写性能.md","filePath":"guide/canvas/通过贝塞尔曲线优化Canvas书写性能.md","lastUpdated":1718174182000}'),e={name:"guide/canvas/通过贝塞尔曲线优化Canvas书写性能.md"},t=l("",21),c=[t];function r(E,y,i,F,A,C){return n(),a("div",null,c)}const u=s(e,[["render",r]]);export{d as __pageData,u as default};
diff --git "a/assets/guide_css\347\233\270\345\205\263_BFC.md.52abcc52.js" "b/assets/guide_css\347\233\270\345\205\263_BFC.md.9c93da99.js"
similarity index 96%
rename from "assets/guide_css\347\233\270\345\205\263_BFC.md.52abcc52.js"
rename to "assets/guide_css\347\233\270\345\205\263_BFC.md.9c93da99.js"
index 3505942b..86a85ed0 100644
--- "a/assets/guide_css\347\233\270\345\205\263_BFC.md.52abcc52.js"
+++ "b/assets/guide_css\347\233\270\345\205\263_BFC.md.9c93da99.js"
@@ -1 +1 @@
-import{_ as i,o as a,c as l,Q as e}from"./chunks/framework.b6910bb2.js";const m=JSON.parse('{"title":"BFC","description":"","frontmatter":{},"headers":[],"relativePath":"guide/css相关/BFC.md","filePath":"guide/css相关/BFC.md","lastUpdated":1718173557000}'),o={name:"guide/css相关/BFC.md"},t=e('

BFC

块级格式化上下文

条件

  1. 根元素 (html)
  2. 浮动元素
  3. position 为绝对定位元素 (absolute/fixed)
  4. display: inline-block、inline-flex等
  5. overflow: auto/scroll/hidden (overflow 值不为 visible 或 clip 的块级元素)

特点

  1. BFC 内部元素不影响外部元素
  2. 计算高度需要计算浮动元素
  3. BFC 区域不会与浮动容器发生重叠
  4. 在 BFC 中上下相邻的俩个容器的 margin 会重叠
  5. 每个元素的左 margin 值和容器的左 border 相接触

作用

  1. 清除浮动带来的高度塌陷问题
  2. 解决俩个元素的 margin 重叠问题
  3. 创建自适应的俩栏布局
',8),r=[t];function s(n,c,d,h,_,f){return a(),l("div",null,r)}const p=i(o,[["render",s]]);export{m as __pageData,p as default}; +import{_ as i,o as a,c as l,Q as e}from"./chunks/framework.b6910bb2.js";const m=JSON.parse('{"title":"BFC","description":"","frontmatter":{},"headers":[],"relativePath":"guide/css相关/BFC.md","filePath":"guide/css相关/BFC.md","lastUpdated":1718174182000}'),o={name:"guide/css相关/BFC.md"},t=e('

BFC

块级格式化上下文

条件

  1. 根元素 (html)
  2. 浮动元素
  3. position 为绝对定位元素 (absolute/fixed)
  4. display: inline-block、inline-flex等
  5. overflow: auto/scroll/hidden (overflow 值不为 visible 或 clip 的块级元素)

特点

  1. BFC 内部元素不影响外部元素
  2. 计算高度需要计算浮动元素
  3. BFC 区域不会与浮动容器发生重叠
  4. 在 BFC 中上下相邻的俩个容器的 margin 会重叠
  5. 每个元素的左 margin 值和容器的左 border 相接触

作用

  1. 清除浮动带来的高度塌陷问题
  2. 解决俩个元素的 margin 重叠问题
  3. 创建自适应的俩栏布局
',8),r=[t];function s(n,c,d,h,_,f){return a(),l("div",null,r)}const p=i(o,[["render",s]]);export{m as __pageData,p as default}; diff --git "a/assets/guide_css\347\233\270\345\205\263_BFC.md.52abcc52.lean.js" "b/assets/guide_css\347\233\270\345\205\263_BFC.md.9c93da99.lean.js" similarity index 85% rename from "assets/guide_css\347\233\270\345\205\263_BFC.md.52abcc52.lean.js" rename to "assets/guide_css\347\233\270\345\205\263_BFC.md.9c93da99.lean.js" index aab219cf..f9c7cc99 100644 --- "a/assets/guide_css\347\233\270\345\205\263_BFC.md.52abcc52.lean.js" +++ "b/assets/guide_css\347\233\270\345\205\263_BFC.md.9c93da99.lean.js" @@ -1 +1 @@ -import{_ as i,o as a,c as l,Q as e}from"./chunks/framework.b6910bb2.js";const m=JSON.parse('{"title":"BFC","description":"","frontmatter":{},"headers":[],"relativePath":"guide/css相关/BFC.md","filePath":"guide/css相关/BFC.md","lastUpdated":1718173557000}'),o={name:"guide/css相关/BFC.md"},t=e("",8),r=[t];function s(n,c,d,h,_,f){return a(),l("div",null,r)}const p=i(o,[["render",s]]);export{m as __pageData,p as default}; +import{_ as i,o as a,c as l,Q as e}from"./chunks/framework.b6910bb2.js";const m=JSON.parse('{"title":"BFC","description":"","frontmatter":{},"headers":[],"relativePath":"guide/css相关/BFC.md","filePath":"guide/css相关/BFC.md","lastUpdated":1718174182000}'),o={name:"guide/css相关/BFC.md"},t=e("",8),r=[t];function s(n,c,d,h,_,f){return a(),l("div",null,r)}const p=i(o,[["render",s]]);export{m as __pageData,p as default}; diff --git "a/assets/guide_css\347\233\270\345\205\263_display.md.7b78972d.js" "b/assets/guide_css\347\233\270\345\205\263_display.md.1a4136c3.js" similarity index 99% rename from "assets/guide_css\347\233\270\345\205\263_display.md.7b78972d.js" rename to "assets/guide_css\347\233\270\345\205\263_display.md.1a4136c3.js" index af270740..9d576411 100644 --- "a/assets/guide_css\347\233\270\345\205\263_display.md.7b78972d.js" +++ "b/assets/guide_css\347\233\270\345\205\263_display.md.1a4136c3.js" @@ -1,4 +1,4 @@ -import{_ as s,o as n,c as l,Q as a}from"./chunks/framework.b6910bb2.js";const d=JSON.parse('{"title":"display","description":"","frontmatter":{},"headers":[],"relativePath":"guide/css相关/display.md","filePath":"guide/css相关/display.md","lastUpdated":1718173557000}'),p={name:"guide/css相关/display.md"},o=a(`

display

none

不显示元素,脱离文档流

inline 行内元素

不能设置宽高、不换行

水平 padding、margin 有效

垂直方向 padding、margin 无效

line-block

可以设置宽高、不换行

block

块级元素,可以设置宽高,独占一行

flex

弹性布局

table

元素作为块级表格元素使用

inherit

继承父元素 display 值

常见的问题

line-block、inline 都会有空格问题

因为浏览器会将换行符当空格字符处理

解决方案:

  1. 使用 font-size 时,可通过设置 font-size: 0、letter-spacing、word-spacing 解决
  2. 使用弹性布局
  3. 使用 margin 负值

浏览器对于空格的默认表现

  1. 元素的头尾的空白符会直接忽略
  2. 内容中间有多个空格,会被合并成一个空格
js
<!DOCTYPE html>
+import{_ as s,o as n,c as l,Q as a}from"./chunks/framework.b6910bb2.js";const d=JSON.parse('{"title":"display","description":"","frontmatter":{},"headers":[],"relativePath":"guide/css相关/display.md","filePath":"guide/css相关/display.md","lastUpdated":1718174182000}'),p={name:"guide/css相关/display.md"},o=a(`

display

none

不显示元素,脱离文档流

inline 行内元素

不能设置宽高、不换行

水平 padding、margin 有效

垂直方向 padding、margin 无效

line-block

可以设置宽高、不换行

block

块级元素,可以设置宽高,独占一行

flex

弹性布局

table

元素作为块级表格元素使用

inherit

继承父元素 display 值

常见的问题

line-block、inline 都会有空格问题

因为浏览器会将换行符当空格字符处理

解决方案:

  1. 使用 font-size 时,可通过设置 font-size: 0、letter-spacing、word-spacing 解决
  2. 使用弹性布局
  3. 使用 margin 负值

浏览器对于空格的默认表现

  1. 元素的头尾的空白符会直接忽略
  2. 内容中间有多个空格,会被合并成一个空格
js
<!DOCTYPE html>
 <html lang="en">
 
 <head>
diff --git "a/assets/guide_css\347\233\270\345\205\263_display.md.7b78972d.lean.js" "b/assets/guide_css\347\233\270\345\205\263_display.md.1a4136c3.lean.js"
similarity index 85%
rename from "assets/guide_css\347\233\270\345\205\263_display.md.7b78972d.lean.js"
rename to "assets/guide_css\347\233\270\345\205\263_display.md.1a4136c3.lean.js"
index 2634b16f..24bcd401 100644
--- "a/assets/guide_css\347\233\270\345\205\263_display.md.7b78972d.lean.js"
+++ "b/assets/guide_css\347\233\270\345\205\263_display.md.1a4136c3.lean.js"
@@ -1 +1 @@
-import{_ as s,o as n,c as l,Q as a}from"./chunks/framework.b6910bb2.js";const d=JSON.parse('{"title":"display","description":"","frontmatter":{},"headers":[],"relativePath":"guide/css相关/display.md","filePath":"guide/css相关/display.md","lastUpdated":1718173557000}'),p={name:"guide/css相关/display.md"},o=a("",25),t=[o];function e(c,E,r,y,i,g){return n(),l("div",null,t)}const u=s(p,[["render",e]]);export{d as __pageData,u as default};
+import{_ as s,o as n,c as l,Q as a}from"./chunks/framework.b6910bb2.js";const d=JSON.parse('{"title":"display","description":"","frontmatter":{},"headers":[],"relativePath":"guide/css相关/display.md","filePath":"guide/css相关/display.md","lastUpdated":1718174182000}'),p={name:"guide/css相关/display.md"},o=a("",25),t=[o];function e(c,E,r,y,i,g){return n(),l("div",null,t)}const u=s(p,[["render",e]]);export{d as __pageData,u as default};
diff --git "a/assets/guide_css\347\233\270\345\205\263_display\343\200\201float\343\200\201position\347\232\204\345\205\263\347\263\273.md.7a72077f.js" "b/assets/guide_css\347\233\270\345\205\263_display\343\200\201float\343\200\201position\347\232\204\345\205\263\347\263\273.md.446e1f0c.js"
similarity index 99%
rename from "assets/guide_css\347\233\270\345\205\263_display\343\200\201float\343\200\201position\347\232\204\345\205\263\347\263\273.md.7a72077f.js"
rename to "assets/guide_css\347\233\270\345\205\263_display\343\200\201float\343\200\201position\347\232\204\345\205\263\347\263\273.md.446e1f0c.js"
index 90613ca1..284a7419 100644
--- "a/assets/guide_css\347\233\270\345\205\263_display\343\200\201float\343\200\201position\347\232\204\345\205\263\347\263\273.md.7a72077f.js"
+++ "b/assets/guide_css\347\233\270\345\205\263_display\343\200\201float\343\200\201position\347\232\204\345\205\263\347\263\273.md.446e1f0c.js"
@@ -1,4 +1,4 @@
-import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.b6910bb2.js";const C=JSON.parse('{"title":"display、float、position的关系","description":"","frontmatter":{},"headers":[],"relativePath":"guide/css相关/display、float、position的关系.md","filePath":"guide/css相关/display、float、position的关系.md","lastUpdated":1718173557000}'),p={name:"guide/css相关/display、float、position的关系.md"},o=l(`

display、float、position的关系

  • 如果元素的 display 为 none 直接隐藏
  • 如果元素的 position 为 absolute 或者 fixed 时,float 失效,display 会提升块级元素
  • 如果元素的 position 为 relative, 会在浮动后的元素进行定位,display 会被提升成块级元素
  • 如果是根元素,display 会被提升为块级元素
  • 浮动元素会将 display 提升为块级元素
html
<!DOCTYPE html>
+import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.b6910bb2.js";const C=JSON.parse('{"title":"display、float、position的关系","description":"","frontmatter":{},"headers":[],"relativePath":"guide/css相关/display、float、position的关系.md","filePath":"guide/css相关/display、float、position的关系.md","lastUpdated":1718174182000}'),p={name:"guide/css相关/display、float、position的关系.md"},o=l(`

display、float、position的关系

  • 如果元素的 display 为 none 直接隐藏
  • 如果元素的 position 为 absolute 或者 fixed 时,float 失效,display 会提升块级元素
  • 如果元素的 position 为 relative, 会在浮动后的元素进行定位,display 会被提升成块级元素
  • 如果是根元素,display 会被提升为块级元素
  • 浮动元素会将 display 提升为块级元素
html
<!DOCTYPE html>
 <html lang="en">
 
 <head>
diff --git "a/assets/guide_css\347\233\270\345\205\263_display\343\200\201float\343\200\201position\347\232\204\345\205\263\347\263\273.md.7a72077f.lean.js" "b/assets/guide_css\347\233\270\345\205\263_display\343\200\201float\343\200\201position\347\232\204\345\205\263\347\263\273.md.446e1f0c.lean.js"
similarity index 88%
rename from "assets/guide_css\347\233\270\345\205\263_display\343\200\201float\343\200\201position\347\232\204\345\205\263\347\263\273.md.7a72077f.lean.js"
rename to "assets/guide_css\347\233\270\345\205\263_display\343\200\201float\343\200\201position\347\232\204\345\205\263\347\263\273.md.446e1f0c.lean.js"
index 289f7a19..1c70624b 100644
--- "a/assets/guide_css\347\233\270\345\205\263_display\343\200\201float\343\200\201position\347\232\204\345\205\263\347\263\273.md.7a72077f.lean.js"
+++ "b/assets/guide_css\347\233\270\345\205\263_display\343\200\201float\343\200\201position\347\232\204\345\205\263\347\263\273.md.446e1f0c.lean.js"
@@ -1 +1 @@
-import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.b6910bb2.js";const C=JSON.parse('{"title":"display、float、position的关系","description":"","frontmatter":{},"headers":[],"relativePath":"guide/css相关/display、float、position的关系.md","filePath":"guide/css相关/display、float、position的关系.md","lastUpdated":1718173557000}'),p={name:"guide/css相关/display、float、position的关系.md"},o=l("",3),t=[o];function e(c,E,r,y,i,d){return n(),a("div",null,t)}const u=s(p,[["render",e]]);export{C as __pageData,u as default};
+import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.b6910bb2.js";const C=JSON.parse('{"title":"display、float、position的关系","description":"","frontmatter":{},"headers":[],"relativePath":"guide/css相关/display、float、position的关系.md","filePath":"guide/css相关/display、float、position的关系.md","lastUpdated":1718174182000}'),p={name:"guide/css相关/display、float、position的关系.md"},o=l("",3),t=[o];function e(c,E,r,y,i,d){return n(),a("div",null,t)}const u=s(p,[["render",e]]);export{C as __pageData,u as default};
diff --git "a/assets/guide_css\347\233\270\345\205\263_display\343\200\201visibility\343\200\201opacity\345\214\272\345\210\253.md.4c0532c6.js" "b/assets/guide_css\347\233\270\345\205\263_display\343\200\201visibility\343\200\201opacity\345\214\272\345\210\253.md.b7b1bec8.js"
similarity index 96%
rename from "assets/guide_css\347\233\270\345\205\263_display\343\200\201visibility\343\200\201opacity\345\214\272\345\210\253.md.4c0532c6.js"
rename to "assets/guide_css\347\233\270\345\205\263_display\343\200\201visibility\343\200\201opacity\345\214\272\345\210\253.md.b7b1bec8.js"
index 98b2d98d..4dfa6a53 100644
--- "a/assets/guide_css\347\233\270\345\205\263_display\343\200\201visibility\343\200\201opacity\345\214\272\345\210\253.md.4c0532c6.js"
+++ "b/assets/guide_css\347\233\270\345\205\263_display\343\200\201visibility\343\200\201opacity\345\214\272\345\210\253.md.b7b1bec8.js"
@@ -1 +1 @@
-import{_ as i,o as l,c as a,Q as t}from"./chunks/framework.b6910bb2.js";const b=JSON.parse('{"title":"display、visibility、opacity区别","description":"","frontmatter":{},"headers":[],"relativePath":"guide/css相关/display、visibility、opacity区别.md","filePath":"guide/css相关/display、visibility、opacity区别.md","lastUpdated":1718173557000}'),s={name:"guide/css相关/display、visibility、opacity区别.md"},e=t('

display、visibility、opacity区别

  • 占据空间

    • opacity、visibility 占据空间,不会引起回流,但是会重绘
    • display 不占据空间,但会引起页面的回流和重绘
  • 绑定事件

    • display、visibility 不会触发绑定事件
    • opacity 会触发绑定事件

display: none 和 visibility: hidden 的区别

  • 从渲染树上看
    • display: none 不存在渲染树中
    • visibility: hidden 的元素存在渲染树中,还会占据空间
  • 从继承上看
    • display 不会被继承
    • visibility 会被继承
  • 从渲染上看
    • display 会影响回流重绘
    • visibility 只会引起重绘
',4),d=[e];function y(o,p,n,c,_,r){return l(),a("div",null,d)}const h=i(s,[["render",y]]);export{b as __pageData,h as default}; +import{_ as i,o as l,c as a,Q as t}from"./chunks/framework.b6910bb2.js";const b=JSON.parse('{"title":"display、visibility、opacity区别","description":"","frontmatter":{},"headers":[],"relativePath":"guide/css相关/display、visibility、opacity区别.md","filePath":"guide/css相关/display、visibility、opacity区别.md","lastUpdated":1718174182000}'),s={name:"guide/css相关/display、visibility、opacity区别.md"},e=t('

display、visibility、opacity区别

  • 占据空间

    • opacity、visibility 占据空间,不会引起回流,但是会重绘
    • display 不占据空间,但会引起页面的回流和重绘
  • 绑定事件

    • display、visibility 不会触发绑定事件
    • opacity 会触发绑定事件

display: none 和 visibility: hidden 的区别

  • 从渲染树上看
    • display: none 不存在渲染树中
    • visibility: hidden 的元素存在渲染树中,还会占据空间
  • 从继承上看
    • display 不会被继承
    • visibility 会被继承
  • 从渲染上看
    • display 会影响回流重绘
    • visibility 只会引起重绘
',4),d=[e];function y(o,p,n,c,_,r){return l(),a("div",null,d)}const h=i(s,[["render",y]]);export{b as __pageData,h as default}; diff --git "a/assets/guide_css\347\233\270\345\205\263_display\343\200\201visibility\343\200\201opacity\345\214\272\345\210\253.md.4c0532c6.lean.js" "b/assets/guide_css\347\233\270\345\205\263_display\343\200\201visibility\343\200\201opacity\345\214\272\345\210\253.md.b7b1bec8.lean.js" similarity index 88% rename from "assets/guide_css\347\233\270\345\205\263_display\343\200\201visibility\343\200\201opacity\345\214\272\345\210\253.md.4c0532c6.lean.js" rename to "assets/guide_css\347\233\270\345\205\263_display\343\200\201visibility\343\200\201opacity\345\214\272\345\210\253.md.b7b1bec8.lean.js" index 472b9b20..0ca0468a 100644 --- "a/assets/guide_css\347\233\270\345\205\263_display\343\200\201visibility\343\200\201opacity\345\214\272\345\210\253.md.4c0532c6.lean.js" +++ "b/assets/guide_css\347\233\270\345\205\263_display\343\200\201visibility\343\200\201opacity\345\214\272\345\210\253.md.b7b1bec8.lean.js" @@ -1 +1 @@ -import{_ as i,o as l,c as a,Q as t}from"./chunks/framework.b6910bb2.js";const b=JSON.parse('{"title":"display、visibility、opacity区别","description":"","frontmatter":{},"headers":[],"relativePath":"guide/css相关/display、visibility、opacity区别.md","filePath":"guide/css相关/display、visibility、opacity区别.md","lastUpdated":1718173557000}'),s={name:"guide/css相关/display、visibility、opacity区别.md"},e=t("",4),d=[e];function y(o,p,n,c,_,r){return l(),a("div",null,d)}const h=i(s,[["render",y]]);export{b as __pageData,h as default}; +import{_ as i,o as l,c as a,Q as t}from"./chunks/framework.b6910bb2.js";const b=JSON.parse('{"title":"display、visibility、opacity区别","description":"","frontmatter":{},"headers":[],"relativePath":"guide/css相关/display、visibility、opacity区别.md","filePath":"guide/css相关/display、visibility、opacity区别.md","lastUpdated":1718174182000}'),s={name:"guide/css相关/display、visibility、opacity区别.md"},e=t("",4),d=[e];function y(o,p,n,c,_,r){return l(),a("div",null,d)}const h=i(s,[["render",y]]);export{b as __pageData,h as default}; diff --git "a/assets/guide_css\347\233\270\345\205\263_position.md.066644ce.js" "b/assets/guide_css\347\233\270\345\205\263_position.md.e15b98ea.js" similarity index 99% rename from "assets/guide_css\347\233\270\345\205\263_position.md.066644ce.js" rename to "assets/guide_css\347\233\270\345\205\263_position.md.e15b98ea.js" index 91a25e67..8927661e 100644 --- "a/assets/guide_css\347\233\270\345\205\263_position.md.066644ce.js" +++ "b/assets/guide_css\347\233\270\345\205\263_position.md.e15b98ea.js" @@ -1,4 +1,4 @@ -import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.b6910bb2.js";const p="data:image/jpeg;base64,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",o="/vitePress-blob/assets/2.bf4501cf.jpg",t="data:image/jpeg;base64,iVBORw0KGgoAAAANSUhEUgAAAgQAAACHCAIAAAGR3OYIAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAmfSURBVHhe7d3NjhPHGsZx3xpHuYhIZ5NNNqwC0rkBlGvIJgiJj0WyYEUkJHYnC1hNNgiUCQsmC2IFZcRoJiEzYIY89ltTqlS3zbTdXR/d/58eOeVy29Pu6rffcRiY2cf6tb+H/377zI1qMOw6zGYp1nm851JdxvsexlDTeg+lxe1Zm7G8h/t7r+2O0d3o+Vvk5HQxPzrbOzi2u3pZ/9B2sX1rxbmUMG7P2rS/h7rwHsrAeyhD9e+h5Q1cvbfvRjUY4wrUhTeQ20jfQPStVfZcuXbT7VlD/W9AD7vhhfCZW0cfdO48ntt499cc9Qq4//5b9Pzs6fwGKsIbyI03kFuHN/Dl7Z/dCL2q8iSaXbCxnwzvVqTKNTA1Hu5WI3kbVWMN8mMN8uuwBosP526EXnVYg+hTK2lmwyf5DapZg+YO+D9tt5SwkzutQfRzCRF7NPp6WXJyulA0uPN4rjUoZK98Rl4HVWTwNdAXIJ+MO1hddFgDDIQ1yI81yI81yI81yI81yK/l5yla1fXDdhXR8b/sGmgz/ixzCB3WoCizFT/2Az+uSK1rIHa4o1sb1KXiNRgN1iA/1iA/1iA/1iA/1iA/1iC/DmugzfjZliFQB/l1WwNtSTbHHaku9CzWoM+4I9WFnsUa9Bl3pLrQs+pYg/nRWTTTTPadVGwfOtGzlmvwySdrg4dPD23LLDk5XWg3/ErcePDy0bPl/vjds7ENMsb2pxM9a7kGd5/M3cQatoH/Sulja+B/wNR+0NHGqx0sZRlsZzrRs+gHfcYdqS70LNagz7gj1YWexRr0GXekutCzOqxB9MOtpBl3pLrotgYYAmuQH2uQH2uQH2uQH2uQH2uQH2uQH2uQH2uQ33IN7D+ETDmuDFZV0YN3i3N73b/Oln/oApSv/zLABv4vCYV/W8jGNf79odGgDBKJzvvLnPS2zWW2xI4og0TCc1q3NghnottQcwb9ogxS0zlt/F0/MH4cDjAoygCgDADKABDKAKAMgCHK4OsfDvRqyvXvX7gpoGz9l4GoEqgBVGSQMpDoL8cRsl3c+TSwocpAL0jIjqEMCKEMphF3sC60TorffmrJUwYPnx5u/iWZm+m5egUb+3cytdiv7vxk7Bd7NukhNwqET5xUMpSBZccysBe5+2TuX3BqsTLQ0dCtzvU7j5eHwo6P+H/tzQ8seigcR/xDUwvfFI0/0VGKjpsfh5NTC2VACGVACGVAiFJ9GQAVoQwAygCgDAChDADKAKAMAKEMAMoAoAwAcWUATBxlAKzKQE2BkMnGlUGP7Jc+8RufUJeey+DqvX2VwZe3f3b3gRr0WQb+9//REFCX/j8iqwbcCCvrfmNN67xNLn/LzcVgNY1h9X+UKYNW/sz2wrt+vNrqX2weg6IM0uGcLhZlkAiX9pJRBmWJSoXKSYMyGJydyste0HZOR/M29pN2i6H1f5Qpg6bwbPbjaNLu2iBkG2BQ/R9lygDVoQwAygCgDAChDADKAKAMAKEMAMoAoAwAoQyAvstANWBZfDh3U0Dxei6Dr384UA1c//6Fuw/UYJBvimgFqEv/ZfDtj6/cCKhE/2Vw5dpNQnaPO5+SGKQM/AdlQraOO5+SoAxIoXHnUxKUASk07nxKgjIghcadT0lQBqTQuPMpCcogW9zxWmmdFD8/wbhDkARl0Gf09qOZZuZHZ9FMGDuGXvTopOIOQRKuDN4tzq/e27fxdvR0vYgGky2DR88Oo5nWWBnYQQu1Top/4tTi3n8SMyuA3b+wvYJe6j/Xb9l4arEyuPHgpWLnumb2Do41sFs7Sv5YtWZ1LJei+QnGHYgkZkdv339x6/nuX9heQS/12f9u23hqCctAAzsmJ6fu151o8sXvbzXjvymyDaLYxl706KTiDkES7psiKwYbb0dP14toMPFvisJuoCZgfcCig+Nv1+Uy20wkOgjJ8BE5f+y42SC8O/HYcUiDMiCFxp1PSVAGpNC48ykJyoAUGnc+JUEZkELjzqckKANSaNz5lARlQAqNO5+SGKQMCNk97nxKov8yAKpDGQCUAUAZAEIZAJQBQBkAQhkAlAFAGQBCGQCUAUAZAEIZAJQBQBkAQhkAlAFAGQBCGQCUAVBLGdi/lQ0AGIhrBon/caROHj5d/tqA+3uv3X0AQH/s+l96M7BOYKEfAEDvKmgGYSew0A8AoF+6tOq23Gbw6s2pLv0WawOWgz/+dlsAbWazlj8Ja52UcH7dE0OtM0DVSm8GocJ3DyUIr8vNa3Q04++Gg4ift4HYuDkDVI1mgPFoXpT9TPMKLtGjoeZMq0tuBpSPZoARal7lbdC8dmtmHbfFxm1CbmugTjQDjEp4UW6Om5fszduHNHPJSaBGNAOMR3hdtnF0pW5euJtPMc0nhlpngKrRDDAe/qIcXp3XjT1N+vlog9Z5GzdngKrRDAAANAMAAM0AACA0AwAAzQAAQDMAAAjNAABAMwAA0AwAAEIzAADQDAAA5TeDgz/+/uq7XyzaPT/+6ddjtwUAYGelNwN5/tuf2rEw/99/4x4DAPRBl1bdlv6/icJ+QCcAgN7V0QzE+gGdAACGUE0zkMWHczcCAPSqpmZw5dpN7SEhhGSPLkfuwjQWelO6pRkQQkiH0AxyohkQQgoJzSAnmgEhpJDQDHKiGRBCCgnNICeaASkhOhWjGTLB0AxyohmQEqJTMZohE8y0msG7xfmrN6fuTlr6uvrq7s4FmsHUcufxXOsejnXrH+2a+dHZ3sFxNLlF/C6RKWf8zUCX4IdPD6/e27c3fH/vtT2UmL6u7YD2RPtjjYFmMKnowm0ng7z4/e2NBy810O2jZ4c20DbWIWysbZabrvgXsY1FnaC1GYQbh+Nmokc3b0xGn9E2g9fH7+yfBS05n3/zUzRDxh1dyk9OFzb2zcDuaqyHdH23uxprYxv7LXXp9xsoOzYDS7TNZZ5CRpnxfzI4evv+7pP5F7ee2xvO/slAe6L90V5pkk8GU8u6ZmBjfRTwj4bNwOeTzUAvsuHuumz3LDKyjL8Z2MDoEhx+9E5JX9caQIhmMLW0NgNd0P3kuv9N5DfQxjajRxXfDDRjgzDh5LpxdLf1dcgUMq1mUBqaASGkkNAMcqIZEEIKCc0gJ5oBIaSQ0AxyohkQQgoJzSAnmgEhpJDQDHKiGRBCCgnNICeaASGkkNAMAAAjRDMAANAMAAA0AwCA0AwAADQDAADNAAAgNAMAAM0AAEAzAAAIzQAAQDMAANAMAABCMwAA0AwAADQDAIDQDAAANAMAAM0AACA0AwBAoxkQQgiZZj5+/PgP1K+IGLarznwAAAAASUVORK5CYII=",u=JSON.parse('{"title":"Position","description":"","frontmatter":{},"headers":[],"relativePath":"guide/css相关/position.md","filePath":"guide/css相关/position.md","lastUpdated":1718173557000}'),e={name:"guide/css相关/position.md"},c=l('

Position

static [ˈstætɪk]

默认值,没有定位,元素出现在正常的文档流中,会忽略 top,bottom,left,right 或者 z-index 声明

relative

生成相对定位元素,相对于其原来位置进行定位,元素的位置通过 left、top、right、bottom 属性规定

relative

元素定位永远相对于元素自身位置,和其他元素没有关系,也不会影响其他元素。

absolute

生成绝对定位的元素,相对于 static 定位以外的一个父元素进行定位

元素位置通过 left、top、right、bottom 属性规定

relative

浏览器会递归查找该元素的所有父元素,如果找到一个设置了非 static 的定位元素,就以该元素为基准定位,如果没有找到,就以浏览器边界定位

但是它具有破坏性,会导致其他元素位置的变化

fixed

生成绝对定位的元素,指定元素相对于屏幕视口的位置来制定元素位置。

relative

但是它具有破坏性,会导致其他元素位置的变化

sticky [ˈstɪki]

相对它的最近滚动祖先(nearest scrolling ancestor)和 containing block (最近块级祖先 nearest block-level ancestor),包括table-related元素,基于top, right, bottom, 和 left的值进行偏移。偏移值不会影响任何其他元素的位置。

inherit

规定从父元素继承 position 属性的值

js
<!DOCTYPE html>
+import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.b6910bb2.js";const p="data:image/jpeg;base64,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",o="/vitePress-blob/assets/2.bf4501cf.jpg",t="data:image/jpeg;base64,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",u=JSON.parse('{"title":"Position","description":"","frontmatter":{},"headers":[],"relativePath":"guide/css相关/position.md","filePath":"guide/css相关/position.md","lastUpdated":1718174182000}'),e={name:"guide/css相关/position.md"},c=l('

Position

static [ˈstætɪk]

默认值,没有定位,元素出现在正常的文档流中,会忽略 top,bottom,left,right 或者 z-index 声明

relative

生成相对定位元素,相对于其原来位置进行定位,元素的位置通过 left、top、right、bottom 属性规定

relative

元素定位永远相对于元素自身位置,和其他元素没有关系,也不会影响其他元素。

absolute

生成绝对定位的元素,相对于 static 定位以外的一个父元素进行定位

元素位置通过 left、top、right、bottom 属性规定

relative

浏览器会递归查找该元素的所有父元素,如果找到一个设置了非 static 的定位元素,就以该元素为基准定位,如果没有找到,就以浏览器边界定位

但是它具有破坏性,会导致其他元素位置的变化

fixed

生成绝对定位的元素,指定元素相对于屏幕视口的位置来制定元素位置。

relative

但是它具有破坏性,会导致其他元素位置的变化

sticky [ˈstɪki]

相对它的最近滚动祖先(nearest scrolling ancestor)和 containing block (最近块级祖先 nearest block-level ancestor),包括table-related元素,基于top, right, bottom, 和 left的值进行偏移。偏移值不会影响任何其他元素的位置。

inherit

规定从父元素继承 position 属性的值

js
<!DOCTYPE html>
 <html lang="en">
 
 <head>
diff --git "a/assets/guide_css\347\233\270\345\205\263_position.md.066644ce.lean.js" "b/assets/guide_css\347\233\270\345\205\263_position.md.e15b98ea.lean.js"
similarity index 99%
rename from "assets/guide_css\347\233\270\345\205\263_position.md.066644ce.lean.js"
rename to "assets/guide_css\347\233\270\345\205\263_position.md.e15b98ea.lean.js"
index 5bfb5833..1ef7799a 100644
--- "a/assets/guide_css\347\233\270\345\205\263_position.md.066644ce.lean.js"
+++ "b/assets/guide_css\347\233\270\345\205\263_position.md.e15b98ea.lean.js"
@@ -1 +1 @@
-import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.b6910bb2.js";const p="data:image/jpeg;base64,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",o="/vitePress-blob/assets/2.bf4501cf.jpg",t="data:image/jpeg;base64,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",u=JSON.parse('{"title":"Position","description":"","frontmatter":{},"headers":[],"relativePath":"guide/css相关/position.md","filePath":"guide/css相关/position.md","lastUpdated":1718173557000}'),e={name:"guide/css相关/position.md"},c=l("",22),r=[c];function E(i,A,y,g,d,h){return n(),a("div",null,r)}const Q=s(e,[["render",E]]);export{u as __pageData,Q as default};
+import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.b6910bb2.js";const p="data:image/jpeg;base64,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",o="/vitePress-blob/assets/2.bf4501cf.jpg",t="data:image/jpeg;base64,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",u=JSON.parse('{"title":"Position","description":"","frontmatter":{},"headers":[],"relativePath":"guide/css相关/position.md","filePath":"guide/css相关/position.md","lastUpdated":1718174182000}'),e={name:"guide/css相关/position.md"},c=l("",22),r=[c];function E(i,A,y,g,d,h){return n(),a("div",null,r)}const Q=s(e,[["render",E]]);export{u as __pageData,Q as default};
diff --git "a/assets/guide_css\347\233\270\345\205\263_\345\257\271 line-height \347\232\204\347\220\206\350\247\243\345\217\212\345\205\266\350\265\213\345\200\274\346\226\271\345\274\217.md.ed9187dc.js" "b/assets/guide_css\347\233\270\345\205\263_\345\257\271 line-height \347\232\204\347\220\206\350\247\243\345\217\212\345\205\266\350\265\213\345\200\274\346\226\271\345\274\217.md.1574e386.js"
similarity index 97%
rename from "assets/guide_css\347\233\270\345\205\263_\345\257\271 line-height \347\232\204\347\220\206\350\247\243\345\217\212\345\205\266\350\265\213\345\200\274\346\226\271\345\274\217.md.ed9187dc.js"
rename to "assets/guide_css\347\233\270\345\205\263_\345\257\271 line-height \347\232\204\347\220\206\350\247\243\345\217\212\345\205\266\350\265\213\345\200\274\346\226\271\345\274\217.md.1574e386.js"
index 52858233..f794b68e 100644
--- "a/assets/guide_css\347\233\270\345\205\263_\345\257\271 line-height \347\232\204\347\220\206\350\247\243\345\217\212\345\205\266\350\265\213\345\200\274\346\226\271\345\274\217.md.ed9187dc.js"	
+++ "b/assets/guide_css\347\233\270\345\205\263_\345\257\271 line-height \347\232\204\347\220\206\350\247\243\345\217\212\345\205\266\350\265\213\345\200\274\346\226\271\345\274\217.md.1574e386.js"	
@@ -1 +1 @@
-import{_ as e,o as a,c as t,Q as i}from"./chunks/framework.b6910bb2.js";const u=JSON.parse('{"title":"对 line-height 的理解及其赋值方式","description":"","frontmatter":{},"headers":[],"relativePath":"guide/css相关/对 line-height 的理解及其赋值方式.md","filePath":"guide/css相关/对 line-height 的理解及其赋值方式.md","lastUpdated":1718173557000}'),h={name:"guide/css相关/对 line-height 的理解及其赋值方式.md"},n=i('

对 line-height 的理解及其赋值方式

概念

line-height 指一行文本的高度,包含了字间距,实际上是下一行基线到上一行基线的距离

line-height 和 height 都能撑开元素高度 (如果 line-height 和 height 一致时可以实现单行文字的垂直居中)

计算方式

带单位的px

line-height 为 固定值

纯数字

直接 line-height 会把比例传递给后代

例如,父级行高为 1.5,子元素字体为 18px,则子元素行高为 1.5 * 18 = 27px

百分比

父元素将计算后的值传递给后代

例如,父元素行高为 200%,父元素字体为 18px,那么子元素行高为 18 * 200% = 36px

',13),r=[n];function l(o,s,_,d,c,p){return a(),t("div",null,r)}const x=e(h,[["render",l]]);export{u as __pageData,x as default}; +import{_ as e,o as a,c as t,Q as i}from"./chunks/framework.b6910bb2.js";const u=JSON.parse('{"title":"对 line-height 的理解及其赋值方式","description":"","frontmatter":{},"headers":[],"relativePath":"guide/css相关/对 line-height 的理解及其赋值方式.md","filePath":"guide/css相关/对 line-height 的理解及其赋值方式.md","lastUpdated":1718174182000}'),h={name:"guide/css相关/对 line-height 的理解及其赋值方式.md"},n=i('

对 line-height 的理解及其赋值方式

概念

line-height 指一行文本的高度,包含了字间距,实际上是下一行基线到上一行基线的距离

line-height 和 height 都能撑开元素高度 (如果 line-height 和 height 一致时可以实现单行文字的垂直居中)

计算方式

带单位的px

line-height 为 固定值

纯数字

直接 line-height 会把比例传递给后代

例如,父级行高为 1.5,子元素字体为 18px,则子元素行高为 1.5 * 18 = 27px

百分比

父元素将计算后的值传递给后代

例如,父元素行高为 200%,父元素字体为 18px,那么子元素行高为 18 * 200% = 36px

',13),r=[n];function l(o,s,_,d,c,p){return a(),t("div",null,r)}const x=e(h,[["render",l]]);export{u as __pageData,x as default}; diff --git "a/assets/guide_css\347\233\270\345\205\263_\345\257\271 line-height \347\232\204\347\220\206\350\247\243\345\217\212\345\205\266\350\265\213\345\200\274\346\226\271\345\274\217.md.ed9187dc.lean.js" "b/assets/guide_css\347\233\270\345\205\263_\345\257\271 line-height \347\232\204\347\220\206\350\247\243\345\217\212\345\205\266\350\265\213\345\200\274\346\226\271\345\274\217.md.1574e386.lean.js" similarity index 89% rename from "assets/guide_css\347\233\270\345\205\263_\345\257\271 line-height \347\232\204\347\220\206\350\247\243\345\217\212\345\205\266\350\265\213\345\200\274\346\226\271\345\274\217.md.ed9187dc.lean.js" rename to "assets/guide_css\347\233\270\345\205\263_\345\257\271 line-height \347\232\204\347\220\206\350\247\243\345\217\212\345\205\266\350\265\213\345\200\274\346\226\271\345\274\217.md.1574e386.lean.js" index 2b76f316..3c0aec98 100644 --- "a/assets/guide_css\347\233\270\345\205\263_\345\257\271 line-height \347\232\204\347\220\206\350\247\243\345\217\212\345\205\266\350\265\213\345\200\274\346\226\271\345\274\217.md.ed9187dc.lean.js" +++ "b/assets/guide_css\347\233\270\345\205\263_\345\257\271 line-height \347\232\204\347\220\206\350\247\243\345\217\212\345\205\266\350\265\213\345\200\274\346\226\271\345\274\217.md.1574e386.lean.js" @@ -1 +1 @@ -import{_ as e,o as a,c as t,Q as i}from"./chunks/framework.b6910bb2.js";const u=JSON.parse('{"title":"对 line-height 的理解及其赋值方式","description":"","frontmatter":{},"headers":[],"relativePath":"guide/css相关/对 line-height 的理解及其赋值方式.md","filePath":"guide/css相关/对 line-height 的理解及其赋值方式.md","lastUpdated":1718173557000}'),h={name:"guide/css相关/对 line-height 的理解及其赋值方式.md"},n=i("",13),r=[n];function l(o,s,_,d,c,p){return a(),t("div",null,r)}const x=e(h,[["render",l]]);export{u as __pageData,x as default}; +import{_ as e,o as a,c as t,Q as i}from"./chunks/framework.b6910bb2.js";const u=JSON.parse('{"title":"对 line-height 的理解及其赋值方式","description":"","frontmatter":{},"headers":[],"relativePath":"guide/css相关/对 line-height 的理解及其赋值方式.md","filePath":"guide/css相关/对 line-height 的理解及其赋值方式.md","lastUpdated":1718174182000}'),h={name:"guide/css相关/对 line-height 的理解及其赋值方式.md"},n=i("",13),r=[n];function l(o,s,_,d,c,p){return a(),t("div",null,r)}const x=e(h,[["render",l]]);export{u as __pageData,x as default}; diff --git "a/assets/guide_css\347\233\270\345\205\263_\346\246\202\350\246\201.md.caec95d5.js" "b/assets/guide_css\347\233\270\345\205\263_\346\246\202\350\246\201.md.1a81ce4c.js" similarity index 87% rename from "assets/guide_css\347\233\270\345\205\263_\346\246\202\350\246\201.md.caec95d5.js" rename to "assets/guide_css\347\233\270\345\205\263_\346\246\202\350\246\201.md.1a81ce4c.js" index 0b0e7a9d..9efe8cda 100644 --- "a/assets/guide_css\347\233\270\345\205\263_\346\246\202\350\246\201.md.caec95d5.js" +++ "b/assets/guide_css\347\233\270\345\205\263_\346\246\202\350\246\201.md.1a81ce4c.js" @@ -1 +1 @@ -import{_ as e}from"./chunks/container.fad5294e.js";import{o as t,c as a,H as s}from"./chunks/framework.b6910bb2.js";const m=JSON.parse('{"title":"","description":"","frontmatter":{"aside":false,"outline":false},"headers":[],"relativePath":"guide/css相关/概要.md","filePath":"guide/css相关/概要.md","lastUpdated":1718173557000}'),c={name:"guide/css相关/概要.md"},n=Object.assign(c,{setup(o){return(r,d)=>(t(),a("div",null,[s(e,{url:"https://www.mubu.com/doc/1bKlzv2cCSK#m"})]))}});export{m as __pageData,n as default}; +import{_ as e}from"./chunks/container.fad5294e.js";import{o as t,c as a,H as s}from"./chunks/framework.b6910bb2.js";const m=JSON.parse('{"title":"","description":"","frontmatter":{"aside":false,"outline":false},"headers":[],"relativePath":"guide/css相关/概要.md","filePath":"guide/css相关/概要.md","lastUpdated":1718174182000}'),c={name:"guide/css相关/概要.md"},n=Object.assign(c,{setup(o){return(r,d)=>(t(),a("div",null,[s(e,{url:"https://www.mubu.com/doc/1bKlzv2cCSK#m"})]))}});export{m as __pageData,n as default}; diff --git "a/assets/guide_css\347\233\270\345\205\263_\346\246\202\350\246\201.md.caec95d5.lean.js" "b/assets/guide_css\347\233\270\345\205\263_\346\246\202\350\246\201.md.1a81ce4c.lean.js" similarity index 87% rename from "assets/guide_css\347\233\270\345\205\263_\346\246\202\350\246\201.md.caec95d5.lean.js" rename to "assets/guide_css\347\233\270\345\205\263_\346\246\202\350\246\201.md.1a81ce4c.lean.js" index 0b0e7a9d..9efe8cda 100644 --- "a/assets/guide_css\347\233\270\345\205\263_\346\246\202\350\246\201.md.caec95d5.lean.js" +++ "b/assets/guide_css\347\233\270\345\205\263_\346\246\202\350\246\201.md.1a81ce4c.lean.js" @@ -1 +1 @@ -import{_ as e}from"./chunks/container.fad5294e.js";import{o as t,c as a,H as s}from"./chunks/framework.b6910bb2.js";const m=JSON.parse('{"title":"","description":"","frontmatter":{"aside":false,"outline":false},"headers":[],"relativePath":"guide/css相关/概要.md","filePath":"guide/css相关/概要.md","lastUpdated":1718173557000}'),c={name:"guide/css相关/概要.md"},n=Object.assign(c,{setup(o){return(r,d)=>(t(),a("div",null,[s(e,{url:"https://www.mubu.com/doc/1bKlzv2cCSK#m"})]))}});export{m as __pageData,n as default}; +import{_ as e}from"./chunks/container.fad5294e.js";import{o as t,c as a,H as s}from"./chunks/framework.b6910bb2.js";const m=JSON.parse('{"title":"","description":"","frontmatter":{"aside":false,"outline":false},"headers":[],"relativePath":"guide/css相关/概要.md","filePath":"guide/css相关/概要.md","lastUpdated":1718174182000}'),c={name:"guide/css相关/概要.md"},n=Object.assign(c,{setup(o){return(r,d)=>(t(),a("div",null,[s(e,{url:"https://www.mubu.com/doc/1bKlzv2cCSK#m"})]))}});export{m as __pageData,n as default}; diff --git "a/assets/guide_css\347\233\270\345\205\263_\351\232\220\350\227\217\345\205\203\347\264\240\347\232\204\346\226\271\346\263\225.md.5d09b97a.js" "b/assets/guide_css\347\233\270\345\205\263_\351\232\220\350\227\217\345\205\203\347\264\240\347\232\204\346\226\271\346\263\225.md.c310eeb1.js" similarity index 94% rename from "assets/guide_css\347\233\270\345\205\263_\351\232\220\350\227\217\345\205\203\347\264\240\347\232\204\346\226\271\346\263\225.md.5d09b97a.js" rename to "assets/guide_css\347\233\270\345\205\263_\351\232\220\350\227\217\345\205\203\347\264\240\347\232\204\346\226\271\346\263\225.md.c310eeb1.js" index 7f8d0e20..75500e02 100644 --- "a/assets/guide_css\347\233\270\345\205\263_\351\232\220\350\227\217\345\205\203\347\264\240\347\232\204\346\226\271\346\263\225.md.5d09b97a.js" +++ "b/assets/guide_css\347\233\270\345\205\263_\351\232\220\350\227\217\345\205\203\347\264\240\347\232\204\346\226\271\346\263\225.md.c310eeb1.js" @@ -1 +1 @@ -import{_ as l,o as i,c as t,Q as e}from"./chunks/framework.b6910bb2.js";const m=JSON.parse('{"title":"隐藏元素的方法","description":"","frontmatter":{},"headers":[],"relativePath":"guide/css相关/隐藏元素的方法.md","filePath":"guide/css相关/隐藏元素的方法.md","lastUpdated":1718173557000}'),a={name:"guide/css相关/隐藏元素的方法.md"},o=e('

隐藏元素的方法

    1. display: none - 不会显示在渲染树上,不占据空间,无法监听事件
    1. visibility: hidden - 占据空间,无法监听事件
    1. opacity: 0 - 占据空间,可以监听事件
    1. transform: scale(0, 0)
    1. 绝对定位
    1. z-index 为负数
',2),s=[o];function _(r,c,n,d,p,h){return i(),t("div",null,s)}const f=l(a,[["render",_]]);export{m as __pageData,f as default}; +import{_ as l,o as i,c as t,Q as e}from"./chunks/framework.b6910bb2.js";const m=JSON.parse('{"title":"隐藏元素的方法","description":"","frontmatter":{},"headers":[],"relativePath":"guide/css相关/隐藏元素的方法.md","filePath":"guide/css相关/隐藏元素的方法.md","lastUpdated":1718174182000}'),a={name:"guide/css相关/隐藏元素的方法.md"},o=e('

隐藏元素的方法

    1. display: none - 不会显示在渲染树上,不占据空间,无法监听事件
    1. visibility: hidden - 占据空间,无法监听事件
    1. opacity: 0 - 占据空间,可以监听事件
    1. transform: scale(0, 0)
    1. 绝对定位
    1. z-index 为负数
',2),s=[o];function _(r,c,n,d,p,h){return i(),t("div",null,s)}const f=l(a,[["render",_]]);export{m as __pageData,f as default}; diff --git "a/assets/guide_css\347\233\270\345\205\263_\351\232\220\350\227\217\345\205\203\347\264\240\347\232\204\346\226\271\346\263\225.md.5d09b97a.lean.js" "b/assets/guide_css\347\233\270\345\205\263_\351\232\220\350\227\217\345\205\203\347\264\240\347\232\204\346\226\271\346\263\225.md.c310eeb1.lean.js" similarity index 87% rename from "assets/guide_css\347\233\270\345\205\263_\351\232\220\350\227\217\345\205\203\347\264\240\347\232\204\346\226\271\346\263\225.md.5d09b97a.lean.js" rename to "assets/guide_css\347\233\270\345\205\263_\351\232\220\350\227\217\345\205\203\347\264\240\347\232\204\346\226\271\346\263\225.md.c310eeb1.lean.js" index 65da413e..f58908d5 100644 --- "a/assets/guide_css\347\233\270\345\205\263_\351\232\220\350\227\217\345\205\203\347\264\240\347\232\204\346\226\271\346\263\225.md.5d09b97a.lean.js" +++ "b/assets/guide_css\347\233\270\345\205\263_\351\232\220\350\227\217\345\205\203\347\264\240\347\232\204\346\226\271\346\263\225.md.c310eeb1.lean.js" @@ -1 +1 @@ -import{_ as l,o as i,c as t,Q as e}from"./chunks/framework.b6910bb2.js";const m=JSON.parse('{"title":"隐藏元素的方法","description":"","frontmatter":{},"headers":[],"relativePath":"guide/css相关/隐藏元素的方法.md","filePath":"guide/css相关/隐藏元素的方法.md","lastUpdated":1718173557000}'),a={name:"guide/css相关/隐藏元素的方法.md"},o=e("",2),s=[o];function _(r,c,n,d,p,h){return i(),t("div",null,s)}const f=l(a,[["render",_]]);export{m as __pageData,f as default}; +import{_ as l,o as i,c as t,Q as e}from"./chunks/framework.b6910bb2.js";const m=JSON.parse('{"title":"隐藏元素的方法","description":"","frontmatter":{},"headers":[],"relativePath":"guide/css相关/隐藏元素的方法.md","filePath":"guide/css相关/隐藏元素的方法.md","lastUpdated":1718174182000}'),a={name:"guide/css相关/隐藏元素的方法.md"},o=e("",2),s=[o];function _(r,c,n,d,p,h){return i(),t("div",null,s)}const f=l(a,[["render",_]]);export{m as __pageData,f as default}; diff --git "a/assets/guide_javaScript\347\233\270\345\205\263_DOM\347\233\270\345\205\263.md.14095a02.js" "b/assets/guide_javaScript\347\233\270\345\205\263_DOM\347\233\270\345\205\263.md.b979d5d3.js" similarity index 99% rename from "assets/guide_javaScript\347\233\270\345\205\263_DOM\347\233\270\345\205\263.md.14095a02.js" rename to "assets/guide_javaScript\347\233\270\345\205\263_DOM\347\233\270\345\205\263.md.b979d5d3.js" index 4676e455..516e6943 100644 --- "a/assets/guide_javaScript\347\233\270\345\205\263_DOM\347\233\270\345\205\263.md.14095a02.js" +++ "b/assets/guide_javaScript\347\233\270\345\205\263_DOM\347\233\270\345\205\263.md.b979d5d3.js" @@ -1,4 +1,4 @@ -import{_ as s,o as a,c as l,Q as n}from"./chunks/framework.b6910bb2.js";const h=JSON.parse('{"title":"DOM 相关","description":"","frontmatter":{},"headers":[],"relativePath":"guide/javaScript相关/DOM相关.md","filePath":"guide/javaScript相关/DOM相关.md","lastUpdated":1718173557000}'),o={name:"guide/javaScript相关/DOM相关.md"},e=n(`

DOM 相关

如何阻止事件的冒泡和默认事件

js
event.stopPropagation(); // 阻止事件冒泡
+import{_ as s,o as a,c as l,Q as n}from"./chunks/framework.b6910bb2.js";const h=JSON.parse('{"title":"DOM 相关","description":"","frontmatter":{},"headers":[],"relativePath":"guide/javaScript相关/DOM相关.md","filePath":"guide/javaScript相关/DOM相关.md","lastUpdated":1718174182000}'),o={name:"guide/javaScript相关/DOM相关.md"},e=n(`

DOM 相关

如何阻止事件的冒泡和默认事件

js
event.stopPropagation(); // 阻止事件冒泡
 event.preventDefalut(); // 阻止默认事件
 event.stopImmediatePropagation(); // 阻止监听同一事件的其他事件监听器被调用
event.stopPropagation(); // 阻止事件冒泡
 event.preventDefalut(); // 阻止默认事件
diff --git "a/assets/guide_javaScript\347\233\270\345\205\263_DOM\347\233\270\345\205\263.md.14095a02.lean.js" "b/assets/guide_javaScript\347\233\270\345\205\263_DOM\347\233\270\345\205\263.md.b979d5d3.lean.js"
similarity index 86%
rename from "assets/guide_javaScript\347\233\270\345\205\263_DOM\347\233\270\345\205\263.md.14095a02.lean.js"
rename to "assets/guide_javaScript\347\233\270\345\205\263_DOM\347\233\270\345\205\263.md.b979d5d3.lean.js"
index d07cfb20..ee56ff15 100644
--- "a/assets/guide_javaScript\347\233\270\345\205\263_DOM\347\233\270\345\205\263.md.14095a02.lean.js"
+++ "b/assets/guide_javaScript\347\233\270\345\205\263_DOM\347\233\270\345\205\263.md.b979d5d3.lean.js"
@@ -1 +1 @@
-import{_ as s,o as a,c as l,Q as n}from"./chunks/framework.b6910bb2.js";const h=JSON.parse('{"title":"DOM 相关","description":"","frontmatter":{},"headers":[],"relativePath":"guide/javaScript相关/DOM相关.md","filePath":"guide/javaScript相关/DOM相关.md","lastUpdated":1718173557000}'),o={name:"guide/javaScript相关/DOM相关.md"},e=n("",16),p=[e];function t(c,r,i,y,E,d){return a(),l("div",null,p)}const u=s(o,[["render",t]]);export{h as __pageData,u as default};
+import{_ as s,o as a,c as l,Q as n}from"./chunks/framework.b6910bb2.js";const h=JSON.parse('{"title":"DOM 相关","description":"","frontmatter":{},"headers":[],"relativePath":"guide/javaScript相关/DOM相关.md","filePath":"guide/javaScript相关/DOM相关.md","lastUpdated":1718174182000}'),o={name:"guide/javaScript相关/DOM相关.md"},e=n("",16),p=[e];function t(c,r,i,y,E,d){return a(),l("div",null,p)}const u=s(o,[["render",t]]);export{h as __pageData,u as default};
diff --git "a/assets/guide_javaScript\347\233\270\345\205\263_ES6\347\233\270\345\205\263.md.349f4c13.js" "b/assets/guide_javaScript\347\233\270\345\205\263_ES6\347\233\270\345\205\263.md.d9bb55f1.js"
similarity index 99%
rename from "assets/guide_javaScript\347\233\270\345\205\263_ES6\347\233\270\345\205\263.md.349f4c13.js"
rename to "assets/guide_javaScript\347\233\270\345\205\263_ES6\347\233\270\345\205\263.md.d9bb55f1.js"
index 558fa509..6e214465 100644
--- "a/assets/guide_javaScript\347\233\270\345\205\263_ES6\347\233\270\345\205\263.md.349f4c13.js"
+++ "b/assets/guide_javaScript\347\233\270\345\205\263_ES6\347\233\270\345\205\263.md.d9bb55f1.js"
@@ -1,4 +1,4 @@
-import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.b6910bb2.js";const p="/vitePress-blob/assets/6.9b165bbb.png",b=JSON.parse('{"title":"ES6相关","description":"","frontmatter":{},"headers":[],"relativePath":"guide/javaScript相关/ES6相关.md","filePath":"guide/javaScript相关/ES6相关.md","lastUpdated":1718173557000}'),o={name:"guide/javaScript相关/ES6相关.md"},e=l('

ES6相关

var、let、const 的区别

1 作用域 let、const 存在块级作用域 var 不存在块级作用域

2 const 常量 定义时赋值

3 变量提升 let/const 声明的变量需要声明后使用 var 声明的变量可以声明前使用

4 重复声明 let/const 不能重复声明 var 可以重复声明

5 暂时性死区 let/const 声明的变量不能在声明前使用

暂时性死区

箭头函数和普通函数的区别

1 箭头函数没有 arguments

2 箭头函数没有自己的 this this 由定义的所在父级上下文决定

3 箭头函数继承来的 this 不会改变 call、apply、bind 方法不能改变箭头函数的 this 指向

js
var id = 'global';
+import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.b6910bb2.js";const p="/vitePress-blob/assets/6.9b165bbb.png",b=JSON.parse('{"title":"ES6相关","description":"","frontmatter":{},"headers":[],"relativePath":"guide/javaScript相关/ES6相关.md","filePath":"guide/javaScript相关/ES6相关.md","lastUpdated":1718174182000}'),o={name:"guide/javaScript相关/ES6相关.md"},e=l('

ES6相关

var、let、const 的区别

1 作用域 let、const 存在块级作用域 var 不存在块级作用域

2 const 常量 定义时赋值

3 变量提升 let/const 声明的变量需要声明后使用 var 声明的变量可以声明前使用

4 重复声明 let/const 不能重复声明 var 可以重复声明

5 暂时性死区 let/const 声明的变量不能在声明前使用

暂时性死区

箭头函数和普通函数的区别

1 箭头函数没有 arguments

2 箭头函数没有自己的 this this 由定义的所在父级上下文决定

3 箭头函数继承来的 this 不会改变 call、apply、bind 方法不能改变箭头函数的 this 指向

js
var id = 'global';
 var obj = {
     id: 'obj',
     a: function () {
diff --git "a/assets/guide_javaScript\347\233\270\345\205\263_ES6\347\233\270\345\205\263.md.349f4c13.lean.js" "b/assets/guide_javaScript\347\233\270\345\205\263_ES6\347\233\270\345\205\263.md.d9bb55f1.lean.js"
similarity index 87%
rename from "assets/guide_javaScript\347\233\270\345\205\263_ES6\347\233\270\345\205\263.md.349f4c13.lean.js"
rename to "assets/guide_javaScript\347\233\270\345\205\263_ES6\347\233\270\345\205\263.md.d9bb55f1.lean.js"
index 0c19fca4..dd0751ee 100644
--- "a/assets/guide_javaScript\347\233\270\345\205\263_ES6\347\233\270\345\205\263.md.349f4c13.lean.js"
+++ "b/assets/guide_javaScript\347\233\270\345\205\263_ES6\347\233\270\345\205\263.md.d9bb55f1.lean.js"
@@ -1 +1 @@
-import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.b6910bb2.js";const p="/vitePress-blob/assets/6.9b165bbb.png",b=JSON.parse('{"title":"ES6相关","description":"","frontmatter":{},"headers":[],"relativePath":"guide/javaScript相关/ES6相关.md","filePath":"guide/javaScript相关/ES6相关.md","lastUpdated":1718173557000}'),o={name:"guide/javaScript相关/ES6相关.md"},e=l("",19),t=[e];function c(r,E,y,i,F,d){return n(),a("div",null,t)}const A=s(o,[["render",c]]);export{b as __pageData,A as default};
+import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.b6910bb2.js";const p="/vitePress-blob/assets/6.9b165bbb.png",b=JSON.parse('{"title":"ES6相关","description":"","frontmatter":{},"headers":[],"relativePath":"guide/javaScript相关/ES6相关.md","filePath":"guide/javaScript相关/ES6相关.md","lastUpdated":1718174182000}'),o={name:"guide/javaScript相关/ES6相关.md"},e=l("",19),t=[e];function c(r,E,y,i,F,d){return n(),a("div",null,t)}const A=s(o,[["render",c]]);export{b as __pageData,A as default};
diff --git "a/assets/guide_javaScript\347\233\270\345\205\263_JS\345\274\202\345\270\270\346\215\225\350\216\267\346\234\272\345\210\266.md.7fd96143.js" "b/assets/guide_javaScript\347\233\270\345\205\263_JS\345\274\202\345\270\270\346\215\225\350\216\267\346\234\272\345\210\266.md.ce3f1203.js"
similarity index 86%
rename from "assets/guide_javaScript\347\233\270\345\205\263_JS\345\274\202\345\270\270\346\215\225\350\216\267\346\234\272\345\210\266.md.7fd96143.js"
rename to "assets/guide_javaScript\347\233\270\345\205\263_JS\345\274\202\345\270\270\346\215\225\350\216\267\346\234\272\345\210\266.md.ce3f1203.js"
index 2c3e9ca1..2b98d586 100644
--- "a/assets/guide_javaScript\347\233\270\345\205\263_JS\345\274\202\345\270\270\346\215\225\350\216\267\346\234\272\345\210\266.md.7fd96143.js"
+++ "b/assets/guide_javaScript\347\233\270\345\205\263_JS\345\274\202\345\270\270\346\215\225\350\216\267\346\234\272\345\210\266.md.ce3f1203.js"
@@ -1 +1 @@
-import{_ as e,o as t,c as a}from"./chunks/framework.b6910bb2.js";const m=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"guide/javaScript相关/JS异常捕获机制.md","filePath":"guide/javaScript相关/JS异常捕获机制.md","lastUpdated":1718173557000}'),r={name:"guide/javaScript相关/JS异常捕获机制.md"};function c(o,s,_,i,d,n){return t(),a("div")}const f=e(r,[["render",c]]);export{m as __pageData,f as default};
+import{_ as e,o as t,c as a}from"./chunks/framework.b6910bb2.js";const m=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"guide/javaScript相关/JS异常捕获机制.md","filePath":"guide/javaScript相关/JS异常捕获机制.md","lastUpdated":1718174182000}'),r={name:"guide/javaScript相关/JS异常捕获机制.md"};function c(o,s,_,i,d,n){return t(),a("div")}const f=e(r,[["render",c]]);export{m as __pageData,f as default};
diff --git "a/assets/guide_javaScript\347\233\270\345\205\263_JS\345\274\202\345\270\270\346\215\225\350\216\267\346\234\272\345\210\266.md.7fd96143.lean.js" "b/assets/guide_javaScript\347\233\270\345\205\263_JS\345\274\202\345\270\270\346\215\225\350\216\267\346\234\272\345\210\266.md.ce3f1203.lean.js"
similarity index 86%
rename from "assets/guide_javaScript\347\233\270\345\205\263_JS\345\274\202\345\270\270\346\215\225\350\216\267\346\234\272\345\210\266.md.7fd96143.lean.js"
rename to "assets/guide_javaScript\347\233\270\345\205\263_JS\345\274\202\345\270\270\346\215\225\350\216\267\346\234\272\345\210\266.md.ce3f1203.lean.js"
index 2c3e9ca1..2b98d586 100644
--- "a/assets/guide_javaScript\347\233\270\345\205\263_JS\345\274\202\345\270\270\346\215\225\350\216\267\346\234\272\345\210\266.md.7fd96143.lean.js"
+++ "b/assets/guide_javaScript\347\233\270\345\205\263_JS\345\274\202\345\270\270\346\215\225\350\216\267\346\234\272\345\210\266.md.ce3f1203.lean.js"
@@ -1 +1 @@
-import{_ as e,o as t,c as a}from"./chunks/framework.b6910bb2.js";const m=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"guide/javaScript相关/JS异常捕获机制.md","filePath":"guide/javaScript相关/JS异常捕获机制.md","lastUpdated":1718173557000}'),r={name:"guide/javaScript相关/JS异常捕获机制.md"};function c(o,s,_,i,d,n){return t(),a("div")}const f=e(r,[["render",c]]);export{m as __pageData,f as default};
+import{_ as e,o as t,c as a}from"./chunks/framework.b6910bb2.js";const m=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"guide/javaScript相关/JS异常捕获机制.md","filePath":"guide/javaScript相关/JS异常捕获机制.md","lastUpdated":1718174182000}'),r={name:"guide/javaScript相关/JS异常捕获机制.md"};function c(o,s,_,i,d,n){return t(),a("div")}const f=e(r,[["render",c]]);export{m as __pageData,f as default};
diff --git "a/assets/guide_javaScript\347\233\270\345\205\263_JavaScript\346\211\247\350\241\214\346\234\272\345\210\266.md.3cb02e76.js" "b/assets/guide_javaScript\347\233\270\345\205\263_JavaScript\346\211\247\350\241\214\346\234\272\345\210\266.md.9520882a.js"
similarity index 92%
rename from "assets/guide_javaScript\347\233\270\345\205\263_JavaScript\346\211\247\350\241\214\346\234\272\345\210\266.md.3cb02e76.js"
rename to "assets/guide_javaScript\347\233\270\345\205\263_JavaScript\346\211\247\350\241\214\346\234\272\345\210\266.md.9520882a.js"
index 4391626c..55cfdbc0 100644
--- "a/assets/guide_javaScript\347\233\270\345\205\263_JavaScript\346\211\247\350\241\214\346\234\272\345\210\266.md.3cb02e76.js"
+++ "b/assets/guide_javaScript\347\233\270\345\205\263_JavaScript\346\211\247\350\241\214\346\234\272\345\210\266.md.9520882a.js"
@@ -1 +1 @@
-import{_ as t,o as e,c as r,k as a,a as c}from"./chunks/framework.b6910bb2.js";const f=JSON.parse('{"title":"JavaScript 执行机制","description":"","frontmatter":{},"headers":[],"relativePath":"guide/javaScript相关/JavaScript执行机制.md","filePath":"guide/javaScript相关/JavaScript执行机制.md","lastUpdated":1718173557000}'),i={name:"guide/javaScript相关/JavaScript执行机制.md"},s=a("h1",{id:"javascript-执行机制",tabindex:"-1"},[c("JavaScript 执行机制 "),a("a",{class:"header-anchor",href:"#javascript-执行机制","aria-label":'Permalink to "JavaScript 执行机制"'},"​")],-1),o=a("p",null,"先编译后执行",-1),p=a("p",null,"编译 -> 创建上下文、创建变量环境、创建词法环境 -> 将上下文压入执行调用栈执行代码",-1),n=[s,o,p];function d(_,l,v,h,S,m){return e(),r("div",null,n)}const J=t(i,[["render",d]]);export{f as __pageData,J as default};
+import{_ as t,o as e,c as r,k as a,a as c}from"./chunks/framework.b6910bb2.js";const f=JSON.parse('{"title":"JavaScript 执行机制","description":"","frontmatter":{},"headers":[],"relativePath":"guide/javaScript相关/JavaScript执行机制.md","filePath":"guide/javaScript相关/JavaScript执行机制.md","lastUpdated":1718174182000}'),i={name:"guide/javaScript相关/JavaScript执行机制.md"},s=a("h1",{id:"javascript-执行机制",tabindex:"-1"},[c("JavaScript 执行机制 "),a("a",{class:"header-anchor",href:"#javascript-执行机制","aria-label":'Permalink to "JavaScript 执行机制"'},"​")],-1),o=a("p",null,"先编译后执行",-1),p=a("p",null,"编译 -> 创建上下文、创建变量环境、创建词法环境 -> 将上下文压入执行调用栈执行代码",-1),n=[s,o,p];function d(_,l,v,h,S,m){return e(),r("div",null,n)}const J=t(i,[["render",d]]);export{f as __pageData,J as default};
diff --git "a/assets/guide_javaScript\347\233\270\345\205\263_JavaScript\346\211\247\350\241\214\346\234\272\345\210\266.md.3cb02e76.lean.js" "b/assets/guide_javaScript\347\233\270\345\205\263_JavaScript\346\211\247\350\241\214\346\234\272\345\210\266.md.9520882a.lean.js"
similarity index 92%
rename from "assets/guide_javaScript\347\233\270\345\205\263_JavaScript\346\211\247\350\241\214\346\234\272\345\210\266.md.3cb02e76.lean.js"
rename to "assets/guide_javaScript\347\233\270\345\205\263_JavaScript\346\211\247\350\241\214\346\234\272\345\210\266.md.9520882a.lean.js"
index 4391626c..55cfdbc0 100644
--- "a/assets/guide_javaScript\347\233\270\345\205\263_JavaScript\346\211\247\350\241\214\346\234\272\345\210\266.md.3cb02e76.lean.js"
+++ "b/assets/guide_javaScript\347\233\270\345\205\263_JavaScript\346\211\247\350\241\214\346\234\272\345\210\266.md.9520882a.lean.js"
@@ -1 +1 @@
-import{_ as t,o as e,c as r,k as a,a as c}from"./chunks/framework.b6910bb2.js";const f=JSON.parse('{"title":"JavaScript 执行机制","description":"","frontmatter":{},"headers":[],"relativePath":"guide/javaScript相关/JavaScript执行机制.md","filePath":"guide/javaScript相关/JavaScript执行机制.md","lastUpdated":1718173557000}'),i={name:"guide/javaScript相关/JavaScript执行机制.md"},s=a("h1",{id:"javascript-执行机制",tabindex:"-1"},[c("JavaScript 执行机制 "),a("a",{class:"header-anchor",href:"#javascript-执行机制","aria-label":'Permalink to "JavaScript 执行机制"'},"​")],-1),o=a("p",null,"先编译后执行",-1),p=a("p",null,"编译 -> 创建上下文、创建变量环境、创建词法环境 -> 将上下文压入执行调用栈执行代码",-1),n=[s,o,p];function d(_,l,v,h,S,m){return e(),r("div",null,n)}const J=t(i,[["render",d]]);export{f as __pageData,J as default};
+import{_ as t,o as e,c as r,k as a,a as c}from"./chunks/framework.b6910bb2.js";const f=JSON.parse('{"title":"JavaScript 执行机制","description":"","frontmatter":{},"headers":[],"relativePath":"guide/javaScript相关/JavaScript执行机制.md","filePath":"guide/javaScript相关/JavaScript执行机制.md","lastUpdated":1718174182000}'),i={name:"guide/javaScript相关/JavaScript执行机制.md"},s=a("h1",{id:"javascript-执行机制",tabindex:"-1"},[c("JavaScript 执行机制 "),a("a",{class:"header-anchor",href:"#javascript-执行机制","aria-label":'Permalink to "JavaScript 执行机制"'},"​")],-1),o=a("p",null,"先编译后执行",-1),p=a("p",null,"编译 -> 创建上下文、创建变量环境、创建词法环境 -> 将上下文压入执行调用栈执行代码",-1),n=[s,o,p];function d(_,l,v,h,S,m){return e(),r("div",null,n)}const J=t(i,[["render",d]]);export{f as __pageData,J as default};
diff --git "a/assets/guide_javaScript\347\233\270\345\205\263_JavaScript\347\274\226\350\257\221\346\234\272\345\210\266.md.9d2ae649.lean.js" "b/assets/guide_javaScript\347\233\270\345\205\263_JavaScript\347\274\226\350\257\221\346\234\272\345\210\266.md.e5a2c4f7.js"
similarity index 92%
rename from "assets/guide_javaScript\347\233\270\345\205\263_JavaScript\347\274\226\350\257\221\346\234\272\345\210\266.md.9d2ae649.lean.js"
rename to "assets/guide_javaScript\347\233\270\345\205\263_JavaScript\347\274\226\350\257\221\346\234\272\345\210\266.md.e5a2c4f7.js"
index ddbcdbc8..7234072c 100644
--- "a/assets/guide_javaScript\347\233\270\345\205\263_JavaScript\347\274\226\350\257\221\346\234\272\345\210\266.md.9d2ae649.lean.js"
+++ "b/assets/guide_javaScript\347\233\270\345\205\263_JavaScript\347\274\226\350\257\221\346\234\272\345\210\266.md.e5a2c4f7.js"
@@ -1 +1 @@
-import{_ as t,o as e,c as r,k as a,a as c}from"./chunks/framework.b6910bb2.js";const f=JSON.parse('{"title":"JavaScript 编译机制","description":"","frontmatter":{},"headers":[],"relativePath":"guide/javaScript相关/JavaScript编译机制.md","filePath":"guide/javaScript相关/JavaScript编译机制.md","lastUpdated":1718173557000}'),i={name:"guide/javaScript相关/JavaScript编译机制.md"},s=a("h1",{id:"javascript-编译机制",tabindex:"-1"},[c("JavaScript 编译机制 "),a("a",{class:"header-anchor",href:"#javascript-编译机制","aria-label":'Permalink to "JavaScript 编译机制"'},"​")],-1),o=a("p",null,"code -> 词法分析、语法分析 -> AST -> 生成字节码 -> 解释执行",-1),p=[s,o];function d(n,_,l,v,S,h){return e(),r("div",null,p)}const u=t(i,[["render",d]]);export{f as __pageData,u as default};
+import{_ as t,o as e,c as r,k as a,a as c}from"./chunks/framework.b6910bb2.js";const f=JSON.parse('{"title":"JavaScript 编译机制","description":"","frontmatter":{},"headers":[],"relativePath":"guide/javaScript相关/JavaScript编译机制.md","filePath":"guide/javaScript相关/JavaScript编译机制.md","lastUpdated":1718174182000}'),i={name:"guide/javaScript相关/JavaScript编译机制.md"},s=a("h1",{id:"javascript-编译机制",tabindex:"-1"},[c("JavaScript 编译机制 "),a("a",{class:"header-anchor",href:"#javascript-编译机制","aria-label":'Permalink to "JavaScript 编译机制"'},"​")],-1),o=a("p",null,"code -> 词法分析、语法分析 -> AST -> 生成字节码 -> 解释执行",-1),p=[s,o];function d(n,_,l,v,S,h){return e(),r("div",null,p)}const u=t(i,[["render",d]]);export{f as __pageData,u as default};
diff --git "a/assets/guide_javaScript\347\233\270\345\205\263_JavaScript\347\274\226\350\257\221\346\234\272\345\210\266.md.9d2ae649.js" "b/assets/guide_javaScript\347\233\270\345\205\263_JavaScript\347\274\226\350\257\221\346\234\272\345\210\266.md.e5a2c4f7.lean.js"
similarity index 92%
rename from "assets/guide_javaScript\347\233\270\345\205\263_JavaScript\347\274\226\350\257\221\346\234\272\345\210\266.md.9d2ae649.js"
rename to "assets/guide_javaScript\347\233\270\345\205\263_JavaScript\347\274\226\350\257\221\346\234\272\345\210\266.md.e5a2c4f7.lean.js"
index ddbcdbc8..7234072c 100644
--- "a/assets/guide_javaScript\347\233\270\345\205\263_JavaScript\347\274\226\350\257\221\346\234\272\345\210\266.md.9d2ae649.js"
+++ "b/assets/guide_javaScript\347\233\270\345\205\263_JavaScript\347\274\226\350\257\221\346\234\272\345\210\266.md.e5a2c4f7.lean.js"
@@ -1 +1 @@
-import{_ as t,o as e,c as r,k as a,a as c}from"./chunks/framework.b6910bb2.js";const f=JSON.parse('{"title":"JavaScript 编译机制","description":"","frontmatter":{},"headers":[],"relativePath":"guide/javaScript相关/JavaScript编译机制.md","filePath":"guide/javaScript相关/JavaScript编译机制.md","lastUpdated":1718173557000}'),i={name:"guide/javaScript相关/JavaScript编译机制.md"},s=a("h1",{id:"javascript-编译机制",tabindex:"-1"},[c("JavaScript 编译机制 "),a("a",{class:"header-anchor",href:"#javascript-编译机制","aria-label":'Permalink to "JavaScript 编译机制"'},"​")],-1),o=a("p",null,"code -> 词法分析、语法分析 -> AST -> 生成字节码 -> 解释执行",-1),p=[s,o];function d(n,_,l,v,S,h){return e(),r("div",null,p)}const u=t(i,[["render",d]]);export{f as __pageData,u as default};
+import{_ as t,o as e,c as r,k as a,a as c}from"./chunks/framework.b6910bb2.js";const f=JSON.parse('{"title":"JavaScript 编译机制","description":"","frontmatter":{},"headers":[],"relativePath":"guide/javaScript相关/JavaScript编译机制.md","filePath":"guide/javaScript相关/JavaScript编译机制.md","lastUpdated":1718174182000}'),i={name:"guide/javaScript相关/JavaScript编译机制.md"},s=a("h1",{id:"javascript-编译机制",tabindex:"-1"},[c("JavaScript 编译机制 "),a("a",{class:"header-anchor",href:"#javascript-编译机制","aria-label":'Permalink to "JavaScript 编译机制"'},"​")],-1),o=a("p",null,"code -> 词法分析、语法分析 -> AST -> 生成字节码 -> 解释执行",-1),p=[s,o];function d(n,_,l,v,S,h){return e(),r("div",null,p)}const u=t(i,[["render",d]]);export{f as __pageData,u as default};
diff --git "a/assets/guide_javaScript\347\233\270\345\205\263_Promise.md.5354a1f7.js" "b/assets/guide_javaScript\347\233\270\345\205\263_Promise.md.f290aa02.js"
similarity index 99%
rename from "assets/guide_javaScript\347\233\270\345\205\263_Promise.md.5354a1f7.js"
rename to "assets/guide_javaScript\347\233\270\345\205\263_Promise.md.f290aa02.js"
index 02f17abc..519e8d51 100644
--- "a/assets/guide_javaScript\347\233\270\345\205\263_Promise.md.5354a1f7.js"
+++ "b/assets/guide_javaScript\347\233\270\345\205\263_Promise.md.f290aa02.js"
@@ -1,4 +1,4 @@
-import{_ as s,o as a,c as n,Q as l}from"./chunks/framework.b6910bb2.js";const p="/vitePress-blob/assets/10.5cd5f050.png",o="/vitePress-blob/assets/7.6a576ff8.png",e="/vitePress-blob/assets/8.56c35364.png",r="/vitePress-blob/assets/9.bf057657.png",v=JSON.parse('{"title":"Promise 相关","description":"","frontmatter":{},"headers":[],"relativePath":"guide/javaScript相关/Promise.md","filePath":"guide/javaScript相关/Promise.md","lastUpdated":1718173557000}'),t={name:"guide/javaScript相关/Promise.md"},c=l(`

Promise 相关

定义

Promise 有 3 种状态:

  • 等待状态 pending
  • 成功状态 resolved
  • 失败状态 rejected

当 Promise 状态是 Pending 时,可以转换为 Resolved 或者 Rejected 状态,一旦状态转换,就不会再改变。

resolved、rejected 是异步函数

then 默认返回一个 Promise 对象,第一个参数是 resolved 的回调函数,第二个参数是 rejected 的回调函数 catch 会返回一个 Promise 对象,catch 正常返回 resolved 状态,里面报错返回 rejected 状态

Promise.resolve

Promise.resolve(value) 返回一个成功状态的 promise 对象

js
/*
+import{_ as s,o as a,c as n,Q as l}from"./chunks/framework.b6910bb2.js";const p="/vitePress-blob/assets/10.5cd5f050.png",o="/vitePress-blob/assets/7.6a576ff8.png",e="/vitePress-blob/assets/8.56c35364.png",r="/vitePress-blob/assets/9.bf057657.png",v=JSON.parse('{"title":"Promise 相关","description":"","frontmatter":{},"headers":[],"relativePath":"guide/javaScript相关/Promise.md","filePath":"guide/javaScript相关/Promise.md","lastUpdated":1718174182000}'),t={name:"guide/javaScript相关/Promise.md"},c=l(`

Promise 相关

定义

Promise 有 3 种状态:

  • 等待状态 pending
  • 成功状态 resolved
  • 失败状态 rejected

当 Promise 状态是 Pending 时,可以转换为 Resolved 或者 Rejected 状态,一旦状态转换,就不会再改变。

resolved、rejected 是异步函数

then 默认返回一个 Promise 对象,第一个参数是 resolved 的回调函数,第二个参数是 rejected 的回调函数 catch 会返回一个 Promise 对象,catch 正常返回 resolved 状态,里面报错返回 rejected 状态

Promise.resolve

Promise.resolve(value) 返回一个成功状态的 promise 对象

js
/*
   如果 .then 函数参数不是一个函数,那么会将其封装成 v => v 函数, 这里的 v 是上一个 resolve 的返回值
 */
 
diff --git "a/assets/guide_javaScript\347\233\270\345\205\263_Promise.md.5354a1f7.lean.js" "b/assets/guide_javaScript\347\233\270\345\205\263_Promise.md.f290aa02.lean.js"
similarity index 90%
rename from "assets/guide_javaScript\347\233\270\345\205\263_Promise.md.5354a1f7.lean.js"
rename to "assets/guide_javaScript\347\233\270\345\205\263_Promise.md.f290aa02.lean.js"
index 88d32a61..dbde8a6a 100644
--- "a/assets/guide_javaScript\347\233\270\345\205\263_Promise.md.5354a1f7.lean.js"
+++ "b/assets/guide_javaScript\347\233\270\345\205\263_Promise.md.f290aa02.lean.js"
@@ -1 +1 @@
-import{_ as s,o as a,c as n,Q as l}from"./chunks/framework.b6910bb2.js";const p="/vitePress-blob/assets/10.5cd5f050.png",o="/vitePress-blob/assets/7.6a576ff8.png",e="/vitePress-blob/assets/8.56c35364.png",r="/vitePress-blob/assets/9.bf057657.png",v=JSON.parse('{"title":"Promise 相关","description":"","frontmatter":{},"headers":[],"relativePath":"guide/javaScript相关/Promise.md","filePath":"guide/javaScript相关/Promise.md","lastUpdated":1718173557000}'),t={name:"guide/javaScript相关/Promise.md"},c=l("",34),E=[c];function y(i,d,F,h,m,P){return a(),n("div",null,E)}const A=s(t,[["render",y]]);export{v as __pageData,A as default};
+import{_ as s,o as a,c as n,Q as l}from"./chunks/framework.b6910bb2.js";const p="/vitePress-blob/assets/10.5cd5f050.png",o="/vitePress-blob/assets/7.6a576ff8.png",e="/vitePress-blob/assets/8.56c35364.png",r="/vitePress-blob/assets/9.bf057657.png",v=JSON.parse('{"title":"Promise 相关","description":"","frontmatter":{},"headers":[],"relativePath":"guide/javaScript相关/Promise.md","filePath":"guide/javaScript相关/Promise.md","lastUpdated":1718174182000}'),t={name:"guide/javaScript相关/Promise.md"},c=l("",34),E=[c];function y(i,d,F,h,m,P){return a(),n("div",null,E)}const A=s(t,[["render",y]]);export{v as __pageData,A as default};
diff --git "a/assets/guide_javaScript\347\233\270\345\205\263_index.md.acb75e78.js" "b/assets/guide_javaScript\347\233\270\345\205\263_index.md.071c7151.js"
similarity index 88%
rename from "assets/guide_javaScript\347\233\270\345\205\263_index.md.acb75e78.js"
rename to "assets/guide_javaScript\347\233\270\345\205\263_index.md.071c7151.js"
index a418e8e3..cebdecf5 100644
--- "a/assets/guide_javaScript\347\233\270\345\205\263_index.md.acb75e78.js"
+++ "b/assets/guide_javaScript\347\233\270\345\205\263_index.md.071c7151.js"
@@ -1 +1 @@
-import{_ as e}from"./chunks/container.fad5294e.js";import{o as a,c as t,H as i}from"./chunks/framework.b6910bb2.js";const l=JSON.parse('{"title":"","description":"","frontmatter":{"aside":false,"outline":false},"headers":[],"relativePath":"guide/javaScript相关/index.md","filePath":"guide/javaScript相关/index.md","lastUpdated":1718173557000}'),r={name:"guide/javaScript相关/index.md"},m=Object.assign(r,{setup(s){return(c,d)=>(a(),t("div",null,[i(e,{url:"https://www.mubu.com/doc/2GzwQWqBS-K#m"})]))}});export{l as __pageData,m as default};
+import{_ as e}from"./chunks/container.fad5294e.js";import{o as a,c as t,H as i}from"./chunks/framework.b6910bb2.js";const l=JSON.parse('{"title":"","description":"","frontmatter":{"aside":false,"outline":false},"headers":[],"relativePath":"guide/javaScript相关/index.md","filePath":"guide/javaScript相关/index.md","lastUpdated":1718174182000}'),r={name:"guide/javaScript相关/index.md"},m=Object.assign(r,{setup(s){return(c,d)=>(a(),t("div",null,[i(e,{url:"https://www.mubu.com/doc/2GzwQWqBS-K#m"})]))}});export{l as __pageData,m as default};
diff --git "a/assets/guide_javaScript\347\233\270\345\205\263_index.md.acb75e78.lean.js" "b/assets/guide_javaScript\347\233\270\345\205\263_index.md.071c7151.lean.js"
similarity index 88%
rename from "assets/guide_javaScript\347\233\270\345\205\263_index.md.acb75e78.lean.js"
rename to "assets/guide_javaScript\347\233\270\345\205\263_index.md.071c7151.lean.js"
index a418e8e3..cebdecf5 100644
--- "a/assets/guide_javaScript\347\233\270\345\205\263_index.md.acb75e78.lean.js"
+++ "b/assets/guide_javaScript\347\233\270\345\205\263_index.md.071c7151.lean.js"
@@ -1 +1 @@
-import{_ as e}from"./chunks/container.fad5294e.js";import{o as a,c as t,H as i}from"./chunks/framework.b6910bb2.js";const l=JSON.parse('{"title":"","description":"","frontmatter":{"aside":false,"outline":false},"headers":[],"relativePath":"guide/javaScript相关/index.md","filePath":"guide/javaScript相关/index.md","lastUpdated":1718173557000}'),r={name:"guide/javaScript相关/index.md"},m=Object.assign(r,{setup(s){return(c,d)=>(a(),t("div",null,[i(e,{url:"https://www.mubu.com/doc/2GzwQWqBS-K#m"})]))}});export{l as __pageData,m as default};
+import{_ as e}from"./chunks/container.fad5294e.js";import{o as a,c as t,H as i}from"./chunks/framework.b6910bb2.js";const l=JSON.parse('{"title":"","description":"","frontmatter":{"aside":false,"outline":false},"headers":[],"relativePath":"guide/javaScript相关/index.md","filePath":"guide/javaScript相关/index.md","lastUpdated":1718174182000}'),r={name:"guide/javaScript相关/index.md"},m=Object.assign(r,{setup(s){return(c,d)=>(a(),t("div",null,[i(e,{url:"https://www.mubu.com/doc/2GzwQWqBS-K#m"})]))}});export{l as __pageData,m as default};
diff --git "a/assets/guide_javaScript\347\233\270\345\205\263_\344\272\213\344\273\266\345\276\252\347\216\257\346\234\272\345\210\266.md.075e7fe9.js" "b/assets/guide_javaScript\347\233\270\345\205\263_\344\272\213\344\273\266\345\276\252\347\216\257\346\234\272\345\210\266.md.6b5cbf0d.js"
similarity index 93%
rename from "assets/guide_javaScript\347\233\270\345\205\263_\344\272\213\344\273\266\345\276\252\347\216\257\346\234\272\345\210\266.md.075e7fe9.js"
rename to "assets/guide_javaScript\347\233\270\345\205\263_\344\272\213\344\273\266\345\276\252\347\216\257\346\234\272\345\210\266.md.6b5cbf0d.js"
index c9f0b518..f37404cb 100644
--- "a/assets/guide_javaScript\347\233\270\345\205\263_\344\272\213\344\273\266\345\276\252\347\216\257\346\234\272\345\210\266.md.075e7fe9.js"
+++ "b/assets/guide_javaScript\347\233\270\345\205\263_\344\272\213\344\273\266\345\276\252\347\216\257\346\234\272\345\210\266.md.6b5cbf0d.js"
@@ -1 +1 @@
-import{_ as a,o as t,c as s,k as e,a as r}from"./chunks/framework.b6910bb2.js";const v=JSON.parse('{"title":"事件循环机制","description":"","frontmatter":{},"headers":[],"relativePath":"guide/javaScript相关/事件循环机制.md","filePath":"guide/javaScript相关/事件循环机制.md","lastUpdated":1718173557000}'),o={name:"guide/javaScript相关/事件循环机制.md"},c=e("h1",{id:"事件循环机制",tabindex:"-1"},[r("事件循环机制 "),e("a",{class:"header-anchor",href:"#事件循环机制","aria-label":'Permalink to "事件循环机制"'},"​")],-1),d=e("p",null,"执行 js 代码时,会将代码分成同步代码和异步代码, 同步任务会进入主线程执行,异步任务又分成宏任务和微任务 宏任务会进入宏任务队列,微任务会进入微任务队列 当主线程的代码执行完后,会查看是否有微任务队列,有则执行,无则进入下一个宏任务",-1),i=[c,d];function n(_,l,p,h,m,f){return t(),s("div",null,i)}const x=a(o,[["render",n]]);export{v as __pageData,x as default};
+import{_ as a,o as t,c as s,k as e,a as r}from"./chunks/framework.b6910bb2.js";const v=JSON.parse('{"title":"事件循环机制","description":"","frontmatter":{},"headers":[],"relativePath":"guide/javaScript相关/事件循环机制.md","filePath":"guide/javaScript相关/事件循环机制.md","lastUpdated":1718174182000}'),o={name:"guide/javaScript相关/事件循环机制.md"},c=e("h1",{id:"事件循环机制",tabindex:"-1"},[r("事件循环机制 "),e("a",{class:"header-anchor",href:"#事件循环机制","aria-label":'Permalink to "事件循环机制"'},"​")],-1),d=e("p",null,"执行 js 代码时,会将代码分成同步代码和异步代码, 同步任务会进入主线程执行,异步任务又分成宏任务和微任务 宏任务会进入宏任务队列,微任务会进入微任务队列 当主线程的代码执行完后,会查看是否有微任务队列,有则执行,无则进入下一个宏任务",-1),i=[c,d];function n(_,l,p,h,m,f){return t(),s("div",null,i)}const x=a(o,[["render",n]]);export{v as __pageData,x as default};
diff --git "a/assets/guide_javaScript\347\233\270\345\205\263_\344\272\213\344\273\266\345\276\252\347\216\257\346\234\272\345\210\266.md.075e7fe9.lean.js" "b/assets/guide_javaScript\347\233\270\345\205\263_\344\272\213\344\273\266\345\276\252\347\216\257\346\234\272\345\210\266.md.6b5cbf0d.lean.js"
similarity index 93%
rename from "assets/guide_javaScript\347\233\270\345\205\263_\344\272\213\344\273\266\345\276\252\347\216\257\346\234\272\345\210\266.md.075e7fe9.lean.js"
rename to "assets/guide_javaScript\347\233\270\345\205\263_\344\272\213\344\273\266\345\276\252\347\216\257\346\234\272\345\210\266.md.6b5cbf0d.lean.js"
index c9f0b518..f37404cb 100644
--- "a/assets/guide_javaScript\347\233\270\345\205\263_\344\272\213\344\273\266\345\276\252\347\216\257\346\234\272\345\210\266.md.075e7fe9.lean.js"
+++ "b/assets/guide_javaScript\347\233\270\345\205\263_\344\272\213\344\273\266\345\276\252\347\216\257\346\234\272\345\210\266.md.6b5cbf0d.lean.js"
@@ -1 +1 @@
-import{_ as a,o as t,c as s,k as e,a as r}from"./chunks/framework.b6910bb2.js";const v=JSON.parse('{"title":"事件循环机制","description":"","frontmatter":{},"headers":[],"relativePath":"guide/javaScript相关/事件循环机制.md","filePath":"guide/javaScript相关/事件循环机制.md","lastUpdated":1718173557000}'),o={name:"guide/javaScript相关/事件循环机制.md"},c=e("h1",{id:"事件循环机制",tabindex:"-1"},[r("事件循环机制 "),e("a",{class:"header-anchor",href:"#事件循环机制","aria-label":'Permalink to "事件循环机制"'},"​")],-1),d=e("p",null,"执行 js 代码时,会将代码分成同步代码和异步代码, 同步任务会进入主线程执行,异步任务又分成宏任务和微任务 宏任务会进入宏任务队列,微任务会进入微任务队列 当主线程的代码执行完后,会查看是否有微任务队列,有则执行,无则进入下一个宏任务",-1),i=[c,d];function n(_,l,p,h,m,f){return t(),s("div",null,i)}const x=a(o,[["render",n]]);export{v as __pageData,x as default};
+import{_ as a,o as t,c as s,k as e,a as r}from"./chunks/framework.b6910bb2.js";const v=JSON.parse('{"title":"事件循环机制","description":"","frontmatter":{},"headers":[],"relativePath":"guide/javaScript相关/事件循环机制.md","filePath":"guide/javaScript相关/事件循环机制.md","lastUpdated":1718174182000}'),o={name:"guide/javaScript相关/事件循环机制.md"},c=e("h1",{id:"事件循环机制",tabindex:"-1"},[r("事件循环机制 "),e("a",{class:"header-anchor",href:"#事件循环机制","aria-label":'Permalink to "事件循环机制"'},"​")],-1),d=e("p",null,"执行 js 代码时,会将代码分成同步代码和异步代码, 同步任务会进入主线程执行,异步任务又分成宏任务和微任务 宏任务会进入宏任务队列,微任务会进入微任务队列 当主线程的代码执行完后,会查看是否有微任务队列,有则执行,无则进入下一个宏任务",-1),i=[c,d];function n(_,l,p,h,m,f){return t(),s("div",null,i)}const x=a(o,[["render",n]]);export{v as __pageData,x as default};
diff --git "a/assets/guide_javaScript\347\233\270\345\205\263_\345\236\203\345\234\276\345\233\236\346\224\266\346\234\272\345\210\266.md.0fcbd9c4.js" "b/assets/guide_javaScript\347\233\270\345\205\263_\345\236\203\345\234\276\345\233\236\346\224\266\346\234\272\345\210\266.md.e4fa0356.js"
similarity index 95%
rename from "assets/guide_javaScript\347\233\270\345\205\263_\345\236\203\345\234\276\345\233\236\346\224\266\346\234\272\345\210\266.md.0fcbd9c4.js"
rename to "assets/guide_javaScript\347\233\270\345\205\263_\345\236\203\345\234\276\345\233\236\346\224\266\346\234\272\345\210\266.md.e4fa0356.js"
index 2615f052..57fafb4f 100644
--- "a/assets/guide_javaScript\347\233\270\345\205\263_\345\236\203\345\234\276\345\233\236\346\224\266\346\234\272\345\210\266.md.0fcbd9c4.js"
+++ "b/assets/guide_javaScript\347\233\270\345\205\263_\345\236\203\345\234\276\345\233\236\346\224\266\346\234\272\345\210\266.md.e4fa0356.js"
@@ -1 +1 @@
-import{_ as t,o as a,c as s,k as e,a as o}from"./chunks/framework.b6910bb2.js";const S=JSON.parse('{"title":"垃圾回收机制","description":"","frontmatter":{},"headers":[],"relativePath":"guide/javaScript相关/垃圾回收机制.md","filePath":"guide/javaScript相关/垃圾回收机制.md","lastUpdated":1718173557000}'),r={name:"guide/javaScript相关/垃圾回收机制.md"},c=e("h1",{id:"垃圾回收机制",tabindex:"-1"},[o("垃圾回收机制 "),e("a",{class:"header-anchor",href:"#垃圾回收机制","aria-label":'Permalink to "垃圾回收机制"'},"​")],-1),n=e("p",null,"在 JS 的垃圾回收机制中,分成新生代和老生代 新生代采用的是 GC 算法,将新生代划分成活动对象区域和空闲区域,例如声明的对象会被放入活动对象区域,当活动对象区域填满时, 会进行一次垃圾回收,将存活的对象移入空闲区域并进行碎片空间整理,完成后再将空闲区域和活动对象区域进行翻转,依次循环回收。",-1),_=e("p",null,"当进行 2次 垃圾回收后,存活的对象会被放入老生代中,",-1),d=e("p",null,"老生代采用的是标记清除和标记整理算法,递归遍历堆内存的变量,将不需要使用的变量标记为垃圾数据,将需要使用的变量标记成活动变量,清除掉垃圾,然后进行标记整理碎片空间。",-1),i=[c,n,_,d];function l(p,h,u,m,f,v){return a(),s("div",null,i)}const g=t(r,[["render",l]]);export{S as __pageData,g as default};
+import{_ as t,o as a,c as s,k as e,a as o}from"./chunks/framework.b6910bb2.js";const S=JSON.parse('{"title":"垃圾回收机制","description":"","frontmatter":{},"headers":[],"relativePath":"guide/javaScript相关/垃圾回收机制.md","filePath":"guide/javaScript相关/垃圾回收机制.md","lastUpdated":1718174182000}'),r={name:"guide/javaScript相关/垃圾回收机制.md"},c=e("h1",{id:"垃圾回收机制",tabindex:"-1"},[o("垃圾回收机制 "),e("a",{class:"header-anchor",href:"#垃圾回收机制","aria-label":'Permalink to "垃圾回收机制"'},"​")],-1),n=e("p",null,"在 JS 的垃圾回收机制中,分成新生代和老生代 新生代采用的是 GC 算法,将新生代划分成活动对象区域和空闲区域,例如声明的对象会被放入活动对象区域,当活动对象区域填满时, 会进行一次垃圾回收,将存活的对象移入空闲区域并进行碎片空间整理,完成后再将空闲区域和活动对象区域进行翻转,依次循环回收。",-1),_=e("p",null,"当进行 2次 垃圾回收后,存活的对象会被放入老生代中,",-1),d=e("p",null,"老生代采用的是标记清除和标记整理算法,递归遍历堆内存的变量,将不需要使用的变量标记为垃圾数据,将需要使用的变量标记成活动变量,清除掉垃圾,然后进行标记整理碎片空间。",-1),i=[c,n,_,d];function l(p,h,u,m,f,v){return a(),s("div",null,i)}const g=t(r,[["render",l]]);export{S as __pageData,g as default};
diff --git "a/assets/guide_javaScript\347\233\270\345\205\263_\345\236\203\345\234\276\345\233\236\346\224\266\346\234\272\345\210\266.md.0fcbd9c4.lean.js" "b/assets/guide_javaScript\347\233\270\345\205\263_\345\236\203\345\234\276\345\233\236\346\224\266\346\234\272\345\210\266.md.e4fa0356.lean.js"
similarity index 95%
rename from "assets/guide_javaScript\347\233\270\345\205\263_\345\236\203\345\234\276\345\233\236\346\224\266\346\234\272\345\210\266.md.0fcbd9c4.lean.js"
rename to "assets/guide_javaScript\347\233\270\345\205\263_\345\236\203\345\234\276\345\233\236\346\224\266\346\234\272\345\210\266.md.e4fa0356.lean.js"
index 2615f052..57fafb4f 100644
--- "a/assets/guide_javaScript\347\233\270\345\205\263_\345\236\203\345\234\276\345\233\236\346\224\266\346\234\272\345\210\266.md.0fcbd9c4.lean.js"
+++ "b/assets/guide_javaScript\347\233\270\345\205\263_\345\236\203\345\234\276\345\233\236\346\224\266\346\234\272\345\210\266.md.e4fa0356.lean.js"
@@ -1 +1 @@
-import{_ as t,o as a,c as s,k as e,a as o}from"./chunks/framework.b6910bb2.js";const S=JSON.parse('{"title":"垃圾回收机制","description":"","frontmatter":{},"headers":[],"relativePath":"guide/javaScript相关/垃圾回收机制.md","filePath":"guide/javaScript相关/垃圾回收机制.md","lastUpdated":1718173557000}'),r={name:"guide/javaScript相关/垃圾回收机制.md"},c=e("h1",{id:"垃圾回收机制",tabindex:"-1"},[o("垃圾回收机制 "),e("a",{class:"header-anchor",href:"#垃圾回收机制","aria-label":'Permalink to "垃圾回收机制"'},"​")],-1),n=e("p",null,"在 JS 的垃圾回收机制中,分成新生代和老生代 新生代采用的是 GC 算法,将新生代划分成活动对象区域和空闲区域,例如声明的对象会被放入活动对象区域,当活动对象区域填满时, 会进行一次垃圾回收,将存活的对象移入空闲区域并进行碎片空间整理,完成后再将空闲区域和活动对象区域进行翻转,依次循环回收。",-1),_=e("p",null,"当进行 2次 垃圾回收后,存活的对象会被放入老生代中,",-1),d=e("p",null,"老生代采用的是标记清除和标记整理算法,递归遍历堆内存的变量,将不需要使用的变量标记为垃圾数据,将需要使用的变量标记成活动变量,清除掉垃圾,然后进行标记整理碎片空间。",-1),i=[c,n,_,d];function l(p,h,u,m,f,v){return a(),s("div",null,i)}const g=t(r,[["render",l]]);export{S as __pageData,g as default};
+import{_ as t,o as a,c as s,k as e,a as o}from"./chunks/framework.b6910bb2.js";const S=JSON.parse('{"title":"垃圾回收机制","description":"","frontmatter":{},"headers":[],"relativePath":"guide/javaScript相关/垃圾回收机制.md","filePath":"guide/javaScript相关/垃圾回收机制.md","lastUpdated":1718174182000}'),r={name:"guide/javaScript相关/垃圾回收机制.md"},c=e("h1",{id:"垃圾回收机制",tabindex:"-1"},[o("垃圾回收机制 "),e("a",{class:"header-anchor",href:"#垃圾回收机制","aria-label":'Permalink to "垃圾回收机制"'},"​")],-1),n=e("p",null,"在 JS 的垃圾回收机制中,分成新生代和老生代 新生代采用的是 GC 算法,将新生代划分成活动对象区域和空闲区域,例如声明的对象会被放入活动对象区域,当活动对象区域填满时, 会进行一次垃圾回收,将存活的对象移入空闲区域并进行碎片空间整理,完成后再将空闲区域和活动对象区域进行翻转,依次循环回收。",-1),_=e("p",null,"当进行 2次 垃圾回收后,存活的对象会被放入老生代中,",-1),d=e("p",null,"老生代采用的是标记清除和标记整理算法,递归遍历堆内存的变量,将不需要使用的变量标记为垃圾数据,将需要使用的变量标记成活动变量,清除掉垃圾,然后进行标记整理碎片空间。",-1),i=[c,n,_,d];function l(p,h,u,m,f,v){return a(),s("div",null,i)}const g=t(r,[["render",l]]);export{S as __pageData,g as default};
diff --git "a/assets/guide_javaScript\347\233\270\345\205\263_\345\237\272\347\241\200\346\246\202\345\277\265.md.dc3d2e30.js" "b/assets/guide_javaScript\347\233\270\345\205\263_\345\237\272\347\241\200\346\246\202\345\277\265.md.64290002.js"
similarity index 99%
rename from "assets/guide_javaScript\347\233\270\345\205\263_\345\237\272\347\241\200\346\246\202\345\277\265.md.dc3d2e30.js"
rename to "assets/guide_javaScript\347\233\270\345\205\263_\345\237\272\347\241\200\346\246\202\345\277\265.md.64290002.js"
index 13775aeb..902eaa6a 100644
--- "a/assets/guide_javaScript\347\233\270\345\205\263_\345\237\272\347\241\200\346\246\202\345\277\265.md.dc3d2e30.js"
+++ "b/assets/guide_javaScript\347\233\270\345\205\263_\345\237\272\347\241\200\346\246\202\345\277\265.md.64290002.js"
@@ -1,4 +1,4 @@
-import{_ as a,o as s,c as l,Q as n}from"./chunks/framework.b6910bb2.js";const p="/vitePress-blob/assets/4.8663f597.png",o="/vitePress-blob/assets/5.83f69d4f.png",_=JSON.parse('{"title":"3 基础概念","description":"","frontmatter":{},"headers":[],"relativePath":"guide/javaScript相关/基础概念.md","filePath":"guide/javaScript相关/基础概念.md","lastUpdated":1718173557000}'),e={name:"guide/javaScript相关/基础概念.md"},t=n('

3 基础概念

3.1 闭包

执行外部函数返回内部函数后,虽然外部函数已经弹出调用栈了,但是内部函数对外部函数变量的引用依然保存在内存中,那么内部函数和这些变量的集合就叫做闭包。

闭包的好处: 1. 私有变量在内存中持久化

闭包的坏处: 1. 使用不当会造成内存泄漏

3.2 原型

在 js 中对象是由构造函数创建的,构造函数中会有一个 prototype 属性,指向一个对象,这个对象包含了由该构造函数创建的实例所共享的属性和方法, 由该构造函数创建的实例可以通过 proto 属性指向这个对象,这个对象就是我们所说的原型。

当想要访问对象的某个属性时,如果在当前对象查找不到,就会往该对象的原型查找,对象的原型也会有属于他的原型对象,如此循环,直到 null 停止,这就是我们所说的原型链

隐式原型: proto 显示原型: prototype

相关方法: 1. hasOwnProperty() 判断属性是否是实例自身的属性 2. Object.getPrototypeOf() 获取实例的原型

3.3 作用域

作用域分成全局作用域函数作用域块级作用域,它标识着一个变量是否合法 (编译过程中就已经确认了)

当查询一个变量时,如果当前作用域查询不到,会往上一级作用域查找,如此循环,直到全局作用域,这就是我们所说的作用域链

3.4 执行上下文

从类型上看

  1. 全局执行上下文
  2. 函数执行上下文
  3. eval 执行上下文

从生命周期上看

  1. 创建阶段
    • this 绑定
    • 创建词法环境 (let、const会被提升到词法环境)
    • 创建变量环境 (var 声明的变量会被提升到变量环境)
  2. 执行阶段
    • 对变量进行赋值,执行代码
  3. 回收阶段
    • 当执行上下文弹出调用站后,会对上下文进行回收

执行上下文栈: 当 JS 执行代码时,首先遇到全局代码,会创建一个全局执行上下文并压入执行栈中,当遇到函数调用时,就会为该函数创建一个新的函数执行上下文压入栈中, 引擎会执行位于执行上下文栈顶的函数,当函数执行完后,执行上下文会从栈中弹出,继续执行下一个上下文,当所有代码都执行完毕后,从栈中弹出全局执行上下文

执行上下文

3.5 类数组对象

一个拥有 length 属性和若干索引属性的对象就是类数组对象。

将类数组对象转化成数组的方法:

1 Array.from(arrayLike)
+import{_ as a,o as s,c as l,Q as n}from"./chunks/framework.b6910bb2.js";const p="/vitePress-blob/assets/4.8663f597.png",o="/vitePress-blob/assets/5.83f69d4f.png",_=JSON.parse('{"title":"3 基础概念","description":"","frontmatter":{},"headers":[],"relativePath":"guide/javaScript相关/基础概念.md","filePath":"guide/javaScript相关/基础概念.md","lastUpdated":1718174182000}'),e={name:"guide/javaScript相关/基础概念.md"},t=n('

3 基础概念

3.1 闭包

执行外部函数返回内部函数后,虽然外部函数已经弹出调用栈了,但是内部函数对外部函数变量的引用依然保存在内存中,那么内部函数和这些变量的集合就叫做闭包。

闭包的好处: 1. 私有变量在内存中持久化

闭包的坏处: 1. 使用不当会造成内存泄漏

3.2 原型

在 js 中对象是由构造函数创建的,构造函数中会有一个 prototype 属性,指向一个对象,这个对象包含了由该构造函数创建的实例所共享的属性和方法, 由该构造函数创建的实例可以通过 proto 属性指向这个对象,这个对象就是我们所说的原型。

当想要访问对象的某个属性时,如果在当前对象查找不到,就会往该对象的原型查找,对象的原型也会有属于他的原型对象,如此循环,直到 null 停止,这就是我们所说的原型链

隐式原型: proto 显示原型: prototype

相关方法: 1. hasOwnProperty() 判断属性是否是实例自身的属性 2. Object.getPrototypeOf() 获取实例的原型

3.3 作用域

作用域分成全局作用域函数作用域块级作用域,它标识着一个变量是否合法 (编译过程中就已经确认了)

当查询一个变量时,如果当前作用域查询不到,会往上一级作用域查找,如此循环,直到全局作用域,这就是我们所说的作用域链

3.4 执行上下文

从类型上看

  1. 全局执行上下文
  2. 函数执行上下文
  3. eval 执行上下文

从生命周期上看

  1. 创建阶段
    • this 绑定
    • 创建词法环境 (let、const会被提升到词法环境)
    • 创建变量环境 (var 声明的变量会被提升到变量环境)
  2. 执行阶段
    • 对变量进行赋值,执行代码
  3. 回收阶段
    • 当执行上下文弹出调用站后,会对上下文进行回收

执行上下文栈: 当 JS 执行代码时,首先遇到全局代码,会创建一个全局执行上下文并压入执行栈中,当遇到函数调用时,就会为该函数创建一个新的函数执行上下文压入栈中, 引擎会执行位于执行上下文栈顶的函数,当函数执行完后,执行上下文会从栈中弹出,继续执行下一个上下文,当所有代码都执行完毕后,从栈中弹出全局执行上下文

执行上下文

3.5 类数组对象

一个拥有 length 属性和若干索引属性的对象就是类数组对象。

将类数组对象转化成数组的方法:

1 Array.from(arrayLike)
 
 2 Array.prototype.slice.call(arrayLike)
 
diff --git "a/assets/guide_javaScript\347\233\270\345\205\263_\345\237\272\347\241\200\346\246\202\345\277\265.md.dc3d2e30.lean.js" "b/assets/guide_javaScript\347\233\270\345\205\263_\345\237\272\347\241\200\346\246\202\345\277\265.md.64290002.lean.js"
similarity index 88%
rename from "assets/guide_javaScript\347\233\270\345\205\263_\345\237\272\347\241\200\346\246\202\345\277\265.md.dc3d2e30.lean.js"
rename to "assets/guide_javaScript\347\233\270\345\205\263_\345\237\272\347\241\200\346\246\202\345\277\265.md.64290002.lean.js"
index 22bdf2af..d6a3a1a7 100644
--- "a/assets/guide_javaScript\347\233\270\345\205\263_\345\237\272\347\241\200\346\246\202\345\277\265.md.dc3d2e30.lean.js"
+++ "b/assets/guide_javaScript\347\233\270\345\205\263_\345\237\272\347\241\200\346\246\202\345\277\265.md.64290002.lean.js"
@@ -1 +1 @@
-import{_ as a,o as s,c as l,Q as n}from"./chunks/framework.b6910bb2.js";const p="/vitePress-blob/assets/4.8663f597.png",o="/vitePress-blob/assets/5.83f69d4f.png",_=JSON.parse('{"title":"3 基础概念","description":"","frontmatter":{},"headers":[],"relativePath":"guide/javaScript相关/基础概念.md","filePath":"guide/javaScript相关/基础概念.md","lastUpdated":1718173557000}'),e={name:"guide/javaScript相关/基础概念.md"},t=n("",63),r=[t];function c(i,y,E,h,d,u){return s(),l("div",null,r)}const b=a(e,[["render",c]]);export{_ as __pageData,b as default};
+import{_ as a,o as s,c as l,Q as n}from"./chunks/framework.b6910bb2.js";const p="/vitePress-blob/assets/4.8663f597.png",o="/vitePress-blob/assets/5.83f69d4f.png",_=JSON.parse('{"title":"3 基础概念","description":"","frontmatter":{},"headers":[],"relativePath":"guide/javaScript相关/基础概念.md","filePath":"guide/javaScript相关/基础概念.md","lastUpdated":1718174182000}'),e={name:"guide/javaScript相关/基础概念.md"},t=n("",63),r=[t];function c(i,y,E,h,d,u){return s(),l("div",null,r)}const b=a(e,[["render",c]]);export{_ as __pageData,b as default};
diff --git "a/assets/guide_javaScript\347\233\270\345\205\263_\345\255\227\347\254\246\344\270\262\345\270\270\350\247\201\347\232\204API.md.43fdbea0.js" "b/assets/guide_javaScript\347\233\270\345\205\263_\345\255\227\347\254\246\344\270\262\345\270\270\350\247\201\347\232\204API.md.17b4927c.js"
similarity index 86%
rename from "assets/guide_javaScript\347\233\270\345\205\263_\345\255\227\347\254\246\344\270\262\345\270\270\350\247\201\347\232\204API.md.43fdbea0.js"
rename to "assets/guide_javaScript\347\233\270\345\205\263_\345\255\227\347\254\246\344\270\262\345\270\270\350\247\201\347\232\204API.md.17b4927c.js"
index 0cbf0fe9..bd875894 100644
--- "a/assets/guide_javaScript\347\233\270\345\205\263_\345\255\227\347\254\246\344\270\262\345\270\270\350\247\201\347\232\204API.md.43fdbea0.js"
+++ "b/assets/guide_javaScript\347\233\270\345\205\263_\345\255\227\347\254\246\344\270\262\345\270\270\350\247\201\347\232\204API.md.17b4927c.js"
@@ -1 +1 @@
-import{_ as e,o as t,c as a}from"./chunks/framework.b6910bb2.js";const m=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"guide/javaScript相关/字符串常见的API.md","filePath":"guide/javaScript相关/字符串常见的API.md","lastUpdated":1718173557000}'),r={name:"guide/javaScript相关/字符串常见的API.md"};function c(o,s,_,i,d,n){return t(),a("div")}const f=e(r,[["render",c]]);export{m as __pageData,f as default};
+import{_ as e,o as t,c as a}from"./chunks/framework.b6910bb2.js";const m=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"guide/javaScript相关/字符串常见的API.md","filePath":"guide/javaScript相关/字符串常见的API.md","lastUpdated":1718174182000}'),r={name:"guide/javaScript相关/字符串常见的API.md"};function c(o,s,_,i,d,n){return t(),a("div")}const f=e(r,[["render",c]]);export{m as __pageData,f as default};
diff --git "a/assets/guide_javaScript\347\233\270\345\205\263_\345\255\227\347\254\246\344\270\262\345\270\270\350\247\201\347\232\204API.md.43fdbea0.lean.js" "b/assets/guide_javaScript\347\233\270\345\205\263_\345\255\227\347\254\246\344\270\262\345\270\270\350\247\201\347\232\204API.md.17b4927c.lean.js"
similarity index 86%
rename from "assets/guide_javaScript\347\233\270\345\205\263_\345\255\227\347\254\246\344\270\262\345\270\270\350\247\201\347\232\204API.md.43fdbea0.lean.js"
rename to "assets/guide_javaScript\347\233\270\345\205\263_\345\255\227\347\254\246\344\270\262\345\270\270\350\247\201\347\232\204API.md.17b4927c.lean.js"
index 0cbf0fe9..bd875894 100644
--- "a/assets/guide_javaScript\347\233\270\345\205\263_\345\255\227\347\254\246\344\270\262\345\270\270\350\247\201\347\232\204API.md.43fdbea0.lean.js"
+++ "b/assets/guide_javaScript\347\233\270\345\205\263_\345\255\227\347\254\246\344\270\262\345\270\270\350\247\201\347\232\204API.md.17b4927c.lean.js"
@@ -1 +1 @@
-import{_ as e,o as t,c as a}from"./chunks/framework.b6910bb2.js";const m=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"guide/javaScript相关/字符串常见的API.md","filePath":"guide/javaScript相关/字符串常见的API.md","lastUpdated":1718173557000}'),r={name:"guide/javaScript相关/字符串常见的API.md"};function c(o,s,_,i,d,n){return t(),a("div")}const f=e(r,[["render",c]]);export{m as __pageData,f as default};
+import{_ as e,o as t,c as a}from"./chunks/framework.b6910bb2.js";const m=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"guide/javaScript相关/字符串常见的API.md","filePath":"guide/javaScript相关/字符串常见的API.md","lastUpdated":1718174182000}'),r={name:"guide/javaScript相关/字符串常见的API.md"};function c(o,s,_,i,d,n){return t(),a("div")}const f=e(r,[["render",c]]);export{m as __pageData,f as default};
diff --git "a/assets/guide_javaScript\347\233\270\345\205\263_\345\256\232\344\271\211.md.ef2262a8.js" "b/assets/guide_javaScript\347\233\270\345\205\263_\345\256\232\344\271\211.md.dcb774c1.js"
similarity index 94%
rename from "assets/guide_javaScript\347\233\270\345\205\263_\345\256\232\344\271\211.md.ef2262a8.js"
rename to "assets/guide_javaScript\347\233\270\345\205\263_\345\256\232\344\271\211.md.dcb774c1.js"
index 950b3983..880f7135 100644
--- "a/assets/guide_javaScript\347\233\270\345\205\263_\345\256\232\344\271\211.md.ef2262a8.js"
+++ "b/assets/guide_javaScript\347\233\270\345\205\263_\345\256\232\344\271\211.md.dcb774c1.js"
@@ -1 +1 @@
-import{_ as a,o as s,c as o,k as t,a as e}from"./chunks/framework.b6910bb2.js";const c="/vitePress-blob/assets/2.192658da.png",k=JSON.parse('{"title":"1 定义","description":"","frontmatter":{},"headers":[],"relativePath":"guide/javaScript相关/定义.md","filePath":"guide/javaScript相关/定义.md","lastUpdated":1718173557000}'),r={name:"guide/javaScript相关/定义.md"},i=t("h1",{id:"_1-定义",tabindex:"-1"},[e("1 定义 "),t("a",{class:"header-anchor",href:"#_1-定义","aria-label":'Permalink to "1 定义"'},"​")],-1),n=t("p",null,"JavaScript 是一门动态语言,可以不需要定义变量类型",-1),_=t("p",null,"JavaScript 是一门弱类型语言,存在隐式类型转化",-1),d=t("p",null,"JavaScript 是一门解释型语言,在运行程序时动态编译",-1),l=t("p",null,"解释型语言特点: 1 每次运行都需要将源代码转化成机器码并执行,效率低 2 只要平台提供相应的解析器,就可以运行源代码,跨平台",-1),p=t("p",null,[e("V8 执行一段代码的流程图 "),t("img",{src:c,alt:"流程"})],-1),h=[i,n,_,d,l,p];function u(m,f,v,S,g,x){return s(),o("div",null,h)}const J=a(r,[["render",u]]);export{k as __pageData,J as default};
+import{_ as a,o as s,c as o,k as t,a as e}from"./chunks/framework.b6910bb2.js";const c="/vitePress-blob/assets/2.192658da.png",k=JSON.parse('{"title":"1 定义","description":"","frontmatter":{},"headers":[],"relativePath":"guide/javaScript相关/定义.md","filePath":"guide/javaScript相关/定义.md","lastUpdated":1718174182000}'),r={name:"guide/javaScript相关/定义.md"},i=t("h1",{id:"_1-定义",tabindex:"-1"},[e("1 定义 "),t("a",{class:"header-anchor",href:"#_1-定义","aria-label":'Permalink to "1 定义"'},"​")],-1),n=t("p",null,"JavaScript 是一门动态语言,可以不需要定义变量类型",-1),_=t("p",null,"JavaScript 是一门弱类型语言,存在隐式类型转化",-1),d=t("p",null,"JavaScript 是一门解释型语言,在运行程序时动态编译",-1),l=t("p",null,"解释型语言特点: 1 每次运行都需要将源代码转化成机器码并执行,效率低 2 只要平台提供相应的解析器,就可以运行源代码,跨平台",-1),p=t("p",null,[e("V8 执行一段代码的流程图 "),t("img",{src:c,alt:"流程"})],-1),h=[i,n,_,d,l,p];function u(m,f,v,S,g,x){return s(),o("div",null,h)}const J=a(r,[["render",u]]);export{k as __pageData,J as default};
diff --git "a/assets/guide_javaScript\347\233\270\345\205\263_\345\256\232\344\271\211.md.ef2262a8.lean.js" "b/assets/guide_javaScript\347\233\270\345\205\263_\345\256\232\344\271\211.md.dcb774c1.lean.js"
similarity index 94%
rename from "assets/guide_javaScript\347\233\270\345\205\263_\345\256\232\344\271\211.md.ef2262a8.lean.js"
rename to "assets/guide_javaScript\347\233\270\345\205\263_\345\256\232\344\271\211.md.dcb774c1.lean.js"
index 950b3983..880f7135 100644
--- "a/assets/guide_javaScript\347\233\270\345\205\263_\345\256\232\344\271\211.md.ef2262a8.lean.js"
+++ "b/assets/guide_javaScript\347\233\270\345\205\263_\345\256\232\344\271\211.md.dcb774c1.lean.js"
@@ -1 +1 @@
-import{_ as a,o as s,c as o,k as t,a as e}from"./chunks/framework.b6910bb2.js";const c="/vitePress-blob/assets/2.192658da.png",k=JSON.parse('{"title":"1 定义","description":"","frontmatter":{},"headers":[],"relativePath":"guide/javaScript相关/定义.md","filePath":"guide/javaScript相关/定义.md","lastUpdated":1718173557000}'),r={name:"guide/javaScript相关/定义.md"},i=t("h1",{id:"_1-定义",tabindex:"-1"},[e("1 定义 "),t("a",{class:"header-anchor",href:"#_1-定义","aria-label":'Permalink to "1 定义"'},"​")],-1),n=t("p",null,"JavaScript 是一门动态语言,可以不需要定义变量类型",-1),_=t("p",null,"JavaScript 是一门弱类型语言,存在隐式类型转化",-1),d=t("p",null,"JavaScript 是一门解释型语言,在运行程序时动态编译",-1),l=t("p",null,"解释型语言特点: 1 每次运行都需要将源代码转化成机器码并执行,效率低 2 只要平台提供相应的解析器,就可以运行源代码,跨平台",-1),p=t("p",null,[e("V8 执行一段代码的流程图 "),t("img",{src:c,alt:"流程"})],-1),h=[i,n,_,d,l,p];function u(m,f,v,S,g,x){return s(),o("div",null,h)}const J=a(r,[["render",u]]);export{k as __pageData,J as default};
+import{_ as a,o as s,c as o,k as t,a as e}from"./chunks/framework.b6910bb2.js";const c="/vitePress-blob/assets/2.192658da.png",k=JSON.parse('{"title":"1 定义","description":"","frontmatter":{},"headers":[],"relativePath":"guide/javaScript相关/定义.md","filePath":"guide/javaScript相关/定义.md","lastUpdated":1718174182000}'),r={name:"guide/javaScript相关/定义.md"},i=t("h1",{id:"_1-定义",tabindex:"-1"},[e("1 定义 "),t("a",{class:"header-anchor",href:"#_1-定义","aria-label":'Permalink to "1 定义"'},"​")],-1),n=t("p",null,"JavaScript 是一门动态语言,可以不需要定义变量类型",-1),_=t("p",null,"JavaScript 是一门弱类型语言,存在隐式类型转化",-1),d=t("p",null,"JavaScript 是一门解释型语言,在运行程序时动态编译",-1),l=t("p",null,"解释型语言特点: 1 每次运行都需要将源代码转化成机器码并执行,效率低 2 只要平台提供相应的解析器,就可以运行源代码,跨平台",-1),p=t("p",null,[e("V8 执行一段代码的流程图 "),t("img",{src:c,alt:"流程"})],-1),h=[i,n,_,d,l,p];function u(m,f,v,S,g,x){return s(),o("div",null,h)}const J=a(r,[["render",u]]);export{k as __pageData,J as default};
diff --git "a/assets/guide_javaScript\347\233\270\345\205\263_\345\257\271\350\261\241\345\270\270\350\247\201\347\232\204API.md.1305a407.js" "b/assets/guide_javaScript\347\233\270\345\205\263_\345\257\271\350\261\241\345\270\270\350\247\201\347\232\204API.md.4f48158b.js"
similarity index 86%
rename from "assets/guide_javaScript\347\233\270\345\205\263_\345\257\271\350\261\241\345\270\270\350\247\201\347\232\204API.md.1305a407.js"
rename to "assets/guide_javaScript\347\233\270\345\205\263_\345\257\271\350\261\241\345\270\270\350\247\201\347\232\204API.md.4f48158b.js"
index 9b5230e6..0909e7f9 100644
--- "a/assets/guide_javaScript\347\233\270\345\205\263_\345\257\271\350\261\241\345\270\270\350\247\201\347\232\204API.md.1305a407.js"
+++ "b/assets/guide_javaScript\347\233\270\345\205\263_\345\257\271\350\261\241\345\270\270\350\247\201\347\232\204API.md.4f48158b.js"
@@ -1 +1 @@
-import{_ as e,o as t,c as a}from"./chunks/framework.b6910bb2.js";const m=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"guide/javaScript相关/对象常见的API.md","filePath":"guide/javaScript相关/对象常见的API.md","lastUpdated":1718173557000}'),r={name:"guide/javaScript相关/对象常见的API.md"};function c(o,s,i,_,d,n){return t(),a("div")}const f=e(r,[["render",c]]);export{m as __pageData,f as default};
+import{_ as e,o as t,c as a}from"./chunks/framework.b6910bb2.js";const m=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"guide/javaScript相关/对象常见的API.md","filePath":"guide/javaScript相关/对象常见的API.md","lastUpdated":1718174182000}'),r={name:"guide/javaScript相关/对象常见的API.md"};function c(o,s,i,_,d,n){return t(),a("div")}const f=e(r,[["render",c]]);export{m as __pageData,f as default};
diff --git "a/assets/guide_javaScript\347\233\270\345\205\263_\345\257\271\350\261\241\345\270\270\350\247\201\347\232\204API.md.1305a407.lean.js" "b/assets/guide_javaScript\347\233\270\345\205\263_\345\257\271\350\261\241\345\270\270\350\247\201\347\232\204API.md.4f48158b.lean.js"
similarity index 86%
rename from "assets/guide_javaScript\347\233\270\345\205\263_\345\257\271\350\261\241\345\270\270\350\247\201\347\232\204API.md.1305a407.lean.js"
rename to "assets/guide_javaScript\347\233\270\345\205\263_\345\257\271\350\261\241\345\270\270\350\247\201\347\232\204API.md.4f48158b.lean.js"
index 9b5230e6..0909e7f9 100644
--- "a/assets/guide_javaScript\347\233\270\345\205\263_\345\257\271\350\261\241\345\270\270\350\247\201\347\232\204API.md.1305a407.lean.js"
+++ "b/assets/guide_javaScript\347\233\270\345\205\263_\345\257\271\350\261\241\345\270\270\350\247\201\347\232\204API.md.4f48158b.lean.js"
@@ -1 +1 @@
-import{_ as e,o as t,c as a}from"./chunks/framework.b6910bb2.js";const m=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"guide/javaScript相关/对象常见的API.md","filePath":"guide/javaScript相关/对象常见的API.md","lastUpdated":1718173557000}'),r={name:"guide/javaScript相关/对象常见的API.md"};function c(o,s,i,_,d,n){return t(),a("div")}const f=e(r,[["render",c]]);export{m as __pageData,f as default};
+import{_ as e,o as t,c as a}from"./chunks/framework.b6910bb2.js";const m=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"guide/javaScript相关/对象常见的API.md","filePath":"guide/javaScript相关/对象常见的API.md","lastUpdated":1718174182000}'),r={name:"guide/javaScript相关/对象常见的API.md"};function c(o,s,i,_,d,n){return t(),a("div")}const f=e(r,[["render",c]]);export{m as __pageData,f as default};
diff --git "a/assets/guide_javaScript\347\233\270\345\205\263_\346\225\260\346\215\256\347\261\273\345\236\213.md.bf71558a.js" "b/assets/guide_javaScript\347\233\270\345\205\263_\346\225\260\346\215\256\347\261\273\345\236\213.md.9fd8813a.js"
similarity index 99%
rename from "assets/guide_javaScript\347\233\270\345\205\263_\346\225\260\346\215\256\347\261\273\345\236\213.md.bf71558a.js"
rename to "assets/guide_javaScript\347\233\270\345\205\263_\346\225\260\346\215\256\347\261\273\345\236\213.md.9fd8813a.js"
index 50d9c553..3a7414a8 100644
--- "a/assets/guide_javaScript\347\233\270\345\205\263_\346\225\260\346\215\256\347\261\273\345\236\213.md.bf71558a.js"
+++ "b/assets/guide_javaScript\347\233\270\345\205\263_\346\225\260\346\215\256\347\261\273\345\236\213.md.9fd8813a.js"
@@ -1,4 +1,4 @@
-import{_ as s,o as a,c as n,Q as l}from"./chunks/framework.b6910bb2.js";const p="/vitePress-blob/assets/3.d5809f49.png",b=JSON.parse('{"title":"2 数据类型","description":"","frontmatter":{},"headers":[],"relativePath":"guide/javaScript相关/数据类型.md","filePath":"guide/javaScript相关/数据类型.md","lastUpdated":1718173557000}'),o={name:"guide/javaScript相关/数据类型.md"},e=l(`

2 数据类型

2.1 数据类型

一共有 7 种基本数据类型

  • 1 Number - 基于 IEEE 754 标准实现,采用双精度 64 位二进制格式, -(2 ^ 63 - 1) ~ 2 ^ 63 - 1
  • 2 Boolean - 只有 true 和 false
  • 3 Undefined - 没有定义的值
  • 4 Null - 空值
  • 5 String - 字符串
  • 6 Symbol - 唯一不可修改的值
  • 7 BigInt - 大整数类型

一种引用类型

  • Object - 引用类型,存储在堆中

2.2 类型检测

2.2.1 typeof

判断基础数据类型,除了 null 也可以判断 function

js
typeof (function() {}) // function
+import{_ as s,o as a,c as n,Q as l}from"./chunks/framework.b6910bb2.js";const p="/vitePress-blob/assets/3.d5809f49.png",b=JSON.parse('{"title":"2 数据类型","description":"","frontmatter":{},"headers":[],"relativePath":"guide/javaScript相关/数据类型.md","filePath":"guide/javaScript相关/数据类型.md","lastUpdated":1718174182000}'),o={name:"guide/javaScript相关/数据类型.md"},e=l(`

2 数据类型

2.1 数据类型

一共有 7 种基本数据类型

  • 1 Number - 基于 IEEE 754 标准实现,采用双精度 64 位二进制格式, -(2 ^ 63 - 1) ~ 2 ^ 63 - 1
  • 2 Boolean - 只有 true 和 false
  • 3 Undefined - 没有定义的值
  • 4 Null - 空值
  • 5 String - 字符串
  • 6 Symbol - 唯一不可修改的值
  • 7 BigInt - 大整数类型

一种引用类型

  • Object - 引用类型,存储在堆中

2.2 类型检测

2.2.1 typeof

判断基础数据类型,除了 null 也可以判断 function

js
typeof (function() {}) // function
 typeof (() => {}) // function
typeof (function() {}) // function
 typeof (() => {}) // function

但数组、对象、null 都会返回 object

js
typeof [] // object
 typeof {} // object
diff --git "a/assets/guide_javaScript\347\233\270\345\205\263_\346\225\260\346\215\256\347\261\273\345\236\213.md.bf71558a.lean.js" "b/assets/guide_javaScript\347\233\270\345\205\263_\346\225\260\346\215\256\347\261\273\345\236\213.md.9fd8813a.lean.js"
similarity index 87%
rename from "assets/guide_javaScript\347\233\270\345\205\263_\346\225\260\346\215\256\347\261\273\345\236\213.md.bf71558a.lean.js"
rename to "assets/guide_javaScript\347\233\270\345\205\263_\346\225\260\346\215\256\347\261\273\345\236\213.md.9fd8813a.lean.js"
index 26093597..8c613aeb 100644
--- "a/assets/guide_javaScript\347\233\270\345\205\263_\346\225\260\346\215\256\347\261\273\345\236\213.md.bf71558a.lean.js"
+++ "b/assets/guide_javaScript\347\233\270\345\205\263_\346\225\260\346\215\256\347\261\273\345\236\213.md.9fd8813a.lean.js"
@@ -1 +1 @@
-import{_ as s,o as a,c as n,Q as l}from"./chunks/framework.b6910bb2.js";const p="/vitePress-blob/assets/3.d5809f49.png",b=JSON.parse('{"title":"2 数据类型","description":"","frontmatter":{},"headers":[],"relativePath":"guide/javaScript相关/数据类型.md","filePath":"guide/javaScript相关/数据类型.md","lastUpdated":1718173557000}'),o={name:"guide/javaScript相关/数据类型.md"},e=l("",59),t=[e];function c(r,y,E,i,d,u){return a(),n("div",null,t)}const g=s(o,[["render",c]]);export{b as __pageData,g as default};
+import{_ as s,o as a,c as n,Q as l}from"./chunks/framework.b6910bb2.js";const p="/vitePress-blob/assets/3.d5809f49.png",b=JSON.parse('{"title":"2 数据类型","description":"","frontmatter":{},"headers":[],"relativePath":"guide/javaScript相关/数据类型.md","filePath":"guide/javaScript相关/数据类型.md","lastUpdated":1718174182000}'),o={name:"guide/javaScript相关/数据类型.md"},e=l("",59),t=[e];function c(r,y,E,i,d,u){return a(),n("div",null,t)}const g=s(o,[["render",c]]);export{b as __pageData,g as default};
diff --git "a/assets/guide_javaScript\347\233\270\345\205\263_\346\225\260\347\273\204\345\270\270\350\247\201\347\232\204API.md.bbc62074.js" "b/assets/guide_javaScript\347\233\270\345\205\263_\346\225\260\347\273\204\345\270\270\350\247\201\347\232\204API.md.e4d7ce17.js"
similarity index 86%
rename from "assets/guide_javaScript\347\233\270\345\205\263_\346\225\260\347\273\204\345\270\270\350\247\201\347\232\204API.md.bbc62074.js"
rename to "assets/guide_javaScript\347\233\270\345\205\263_\346\225\260\347\273\204\345\270\270\350\247\201\347\232\204API.md.e4d7ce17.js"
index 94fc399e..d5e4cb0e 100644
--- "a/assets/guide_javaScript\347\233\270\345\205\263_\346\225\260\347\273\204\345\270\270\350\247\201\347\232\204API.md.bbc62074.js"
+++ "b/assets/guide_javaScript\347\233\270\345\205\263_\346\225\260\347\273\204\345\270\270\350\247\201\347\232\204API.md.e4d7ce17.js"
@@ -1 +1 @@
-import{_ as e,o as t,c as a}from"./chunks/framework.b6910bb2.js";const m=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"guide/javaScript相关/数组常见的API.md","filePath":"guide/javaScript相关/数组常见的API.md","lastUpdated":1718173557000}'),r={name:"guide/javaScript相关/数组常见的API.md"};function c(o,s,i,_,d,n){return t(),a("div")}const f=e(r,[["render",c]]);export{m as __pageData,f as default};
+import{_ as e,o as t,c as a}from"./chunks/framework.b6910bb2.js";const m=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"guide/javaScript相关/数组常见的API.md","filePath":"guide/javaScript相关/数组常见的API.md","lastUpdated":1718174182000}'),r={name:"guide/javaScript相关/数组常见的API.md"};function c(o,s,i,_,d,n){return t(),a("div")}const f=e(r,[["render",c]]);export{m as __pageData,f as default};
diff --git "a/assets/guide_javaScript\347\233\270\345\205\263_\346\225\260\347\273\204\345\270\270\350\247\201\347\232\204API.md.bbc62074.lean.js" "b/assets/guide_javaScript\347\233\270\345\205\263_\346\225\260\347\273\204\345\270\270\350\247\201\347\232\204API.md.e4d7ce17.lean.js"
similarity index 86%
rename from "assets/guide_javaScript\347\233\270\345\205\263_\346\225\260\347\273\204\345\270\270\350\247\201\347\232\204API.md.bbc62074.lean.js"
rename to "assets/guide_javaScript\347\233\270\345\205\263_\346\225\260\347\273\204\345\270\270\350\247\201\347\232\204API.md.e4d7ce17.lean.js"
index 94fc399e..d5e4cb0e 100644
--- "a/assets/guide_javaScript\347\233\270\345\205\263_\346\225\260\347\273\204\345\270\270\350\247\201\347\232\204API.md.bbc62074.lean.js"
+++ "b/assets/guide_javaScript\347\233\270\345\205\263_\346\225\260\347\273\204\345\270\270\350\247\201\347\232\204API.md.e4d7ce17.lean.js"
@@ -1 +1 @@
-import{_ as e,o as t,c as a}from"./chunks/framework.b6910bb2.js";const m=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"guide/javaScript相关/数组常见的API.md","filePath":"guide/javaScript相关/数组常见的API.md","lastUpdated":1718173557000}'),r={name:"guide/javaScript相关/数组常见的API.md"};function c(o,s,i,_,d,n){return t(),a("div")}const f=e(r,[["render",c]]);export{m as __pageData,f as default};
+import{_ as e,o as t,c as a}from"./chunks/framework.b6910bb2.js";const m=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"guide/javaScript相关/数组常见的API.md","filePath":"guide/javaScript相关/数组常见的API.md","lastUpdated":1718174182000}'),r={name:"guide/javaScript相关/数组常见的API.md"};function c(o,s,i,_,d,n){return t(),a("div")}const f=e(r,[["render",c]]);export{m as __pageData,f as default};
diff --git "a/assets/guide_javaScript\347\233\270\345\205\263_\346\226\260\347\232\204\350\277\220\347\256\227\347\254\246.md.254d85e1.js" "b/assets/guide_javaScript\347\233\270\345\205\263_\346\226\260\347\232\204\350\277\220\347\256\227\347\254\246.md.ebbfecce.js"
similarity index 85%
rename from "assets/guide_javaScript\347\233\270\345\205\263_\346\226\260\347\232\204\350\277\220\347\256\227\347\254\246.md.254d85e1.js"
rename to "assets/guide_javaScript\347\233\270\345\205\263_\346\226\260\347\232\204\350\277\220\347\256\227\347\254\246.md.ebbfecce.js"
index 3e155cc6..4f0e7be2 100644
--- "a/assets/guide_javaScript\347\233\270\345\205\263_\346\226\260\347\232\204\350\277\220\347\256\227\347\254\246.md.254d85e1.js"
+++ "b/assets/guide_javaScript\347\233\270\345\205\263_\346\226\260\347\232\204\350\277\220\347\256\227\347\254\246.md.ebbfecce.js"
@@ -1 +1 @@
-import{_ as e,o as t,c as a}from"./chunks/framework.b6910bb2.js";const m=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"guide/javaScript相关/新的运算符.md","filePath":"guide/javaScript相关/新的运算符.md","lastUpdated":1718173557000}'),r={name:"guide/javaScript相关/新的运算符.md"};function c(o,s,i,_,d,n){return t(),a("div")}const f=e(r,[["render",c]]);export{m as __pageData,f as default};
+import{_ as e,o as t,c as a}from"./chunks/framework.b6910bb2.js";const m=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"guide/javaScript相关/新的运算符.md","filePath":"guide/javaScript相关/新的运算符.md","lastUpdated":1718174182000}'),r={name:"guide/javaScript相关/新的运算符.md"};function c(o,s,i,_,d,n){return t(),a("div")}const f=e(r,[["render",c]]);export{m as __pageData,f as default};
diff --git "a/assets/guide_javaScript\347\233\270\345\205\263_\346\226\260\347\232\204\350\277\220\347\256\227\347\254\246.md.254d85e1.lean.js" "b/assets/guide_javaScript\347\233\270\345\205\263_\346\226\260\347\232\204\350\277\220\347\256\227\347\254\246.md.ebbfecce.lean.js"
similarity index 85%
rename from "assets/guide_javaScript\347\233\270\345\205\263_\346\226\260\347\232\204\350\277\220\347\256\227\347\254\246.md.254d85e1.lean.js"
rename to "assets/guide_javaScript\347\233\270\345\205\263_\346\226\260\347\232\204\350\277\220\347\256\227\347\254\246.md.ebbfecce.lean.js"
index 3e155cc6..4f0e7be2 100644
--- "a/assets/guide_javaScript\347\233\270\345\205\263_\346\226\260\347\232\204\350\277\220\347\256\227\347\254\246.md.254d85e1.lean.js"
+++ "b/assets/guide_javaScript\347\233\270\345\205\263_\346\226\260\347\232\204\350\277\220\347\256\227\347\254\246.md.ebbfecce.lean.js"
@@ -1 +1 @@
-import{_ as e,o as t,c as a}from"./chunks/framework.b6910bb2.js";const m=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"guide/javaScript相关/新的运算符.md","filePath":"guide/javaScript相关/新的运算符.md","lastUpdated":1718173557000}'),r={name:"guide/javaScript相关/新的运算符.md"};function c(o,s,i,_,d,n){return t(),a("div")}const f=e(r,[["render",c]]);export{m as __pageData,f as default};
+import{_ as e,o as t,c as a}from"./chunks/framework.b6910bb2.js";const m=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"guide/javaScript相关/新的运算符.md","filePath":"guide/javaScript相关/新的运算符.md","lastUpdated":1718174182000}'),r={name:"guide/javaScript相关/新的运算符.md"};function c(o,s,i,_,d,n){return t(),a("div")}const f=e(r,[["render",c]]);export{m as __pageData,f as default};
diff --git "a/assets/guide_javaScript\347\233\270\345\205\263_\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217.md.9d16e29a.js" "b/assets/guide_javaScript\347\233\270\345\205\263_\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217.md.acb1905e.js"
similarity index 85%
rename from "assets/guide_javaScript\347\233\270\345\205\263_\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217.md.9d16e29a.js"
rename to "assets/guide_javaScript\347\233\270\345\205\263_\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217.md.acb1905e.js"
index 0d22af86..1e68070a 100644
--- "a/assets/guide_javaScript\347\233\270\345\205\263_\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217.md.9d16e29a.js"
+++ "b/assets/guide_javaScript\347\233\270\345\205\263_\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217.md.acb1905e.js"
@@ -1 +1 @@
-import{_ as e,o as t,c as a}from"./chunks/framework.b6910bb2.js";const m=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"guide/javaScript相关/正则表达式.md","filePath":"guide/javaScript相关/正则表达式.md","lastUpdated":1718173557000}'),r={name:"guide/javaScript相关/正则表达式.md"};function c(o,s,i,_,d,n){return t(),a("div")}const f=e(r,[["render",c]]);export{m as __pageData,f as default};
+import{_ as e,o as t,c as a}from"./chunks/framework.b6910bb2.js";const m=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"guide/javaScript相关/正则表达式.md","filePath":"guide/javaScript相关/正则表达式.md","lastUpdated":1718174182000}'),r={name:"guide/javaScript相关/正则表达式.md"};function c(o,s,i,_,d,n){return t(),a("div")}const f=e(r,[["render",c]]);export{m as __pageData,f as default};
diff --git "a/assets/guide_javaScript\347\233\270\345\205\263_\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217.md.9d16e29a.lean.js" "b/assets/guide_javaScript\347\233\270\345\205\263_\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217.md.acb1905e.lean.js"
similarity index 85%
rename from "assets/guide_javaScript\347\233\270\345\205\263_\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217.md.9d16e29a.lean.js"
rename to "assets/guide_javaScript\347\233\270\345\205\263_\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217.md.acb1905e.lean.js"
index 0d22af86..1e68070a 100644
--- "a/assets/guide_javaScript\347\233\270\345\205\263_\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217.md.9d16e29a.lean.js"
+++ "b/assets/guide_javaScript\347\233\270\345\205\263_\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217.md.acb1905e.lean.js"
@@ -1 +1 @@
-import{_ as e,o as t,c as a}from"./chunks/framework.b6910bb2.js";const m=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"guide/javaScript相关/正则表达式.md","filePath":"guide/javaScript相关/正则表达式.md","lastUpdated":1718173557000}'),r={name:"guide/javaScript相关/正则表达式.md"};function c(o,s,i,_,d,n){return t(),a("div")}const f=e(r,[["render",c]]);export{m as __pageData,f as default};
+import{_ as e,o as t,c as a}from"./chunks/framework.b6910bb2.js";const m=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"guide/javaScript相关/正则表达式.md","filePath":"guide/javaScript相关/正则表达式.md","lastUpdated":1718174182000}'),r={name:"guide/javaScript相关/正则表达式.md"};function c(o,s,i,_,d,n){return t(),a("div")}const f=e(r,[["render",c]]);export{m as __pageData,f as default};
diff --git "a/assets/guide_javaScript\347\233\270\345\205\263_\347\273\247\346\211\277\347\233\270\345\205\263.md.00da001d.js" "b/assets/guide_javaScript\347\233\270\345\205\263_\347\273\247\346\211\277\347\233\270\345\205\263.md.d7ab4f95.js"
similarity index 99%
rename from "assets/guide_javaScript\347\233\270\345\205\263_\347\273\247\346\211\277\347\233\270\345\205\263.md.00da001d.js"
rename to "assets/guide_javaScript\347\233\270\345\205\263_\347\273\247\346\211\277\347\233\270\345\205\263.md.d7ab4f95.js"
index 346b6c04..d8cd3dbe 100644
--- "a/assets/guide_javaScript\347\233\270\345\205\263_\347\273\247\346\211\277\347\233\270\345\205\263.md.00da001d.js"
+++ "b/assets/guide_javaScript\347\233\270\345\205\263_\347\273\247\346\211\277\347\233\270\345\205\263.md.d7ab4f95.js"
@@ -1,4 +1,4 @@
-import{_ as s,o as n,c as a,Q as p}from"./chunks/framework.b6910bb2.js";const d=JSON.parse('{"title":"继承","description":"","frontmatter":{},"headers":[],"relativePath":"guide/javaScript相关/继承相关.md","filePath":"guide/javaScript相关/继承相关.md","lastUpdated":1718173557000}'),l={name:"guide/javaScript相关/继承相关.md"},o=p(`

继承

原型链继承

子类的原型对象是父类的实例对象

优点:

  • 简单易懂 缺点:
  • 1 实例化子类时,没办法向父类的构造函数传值
  • 2 所有子类实例共享一个父类,当某个子类修改了父类的属性时,其他子类也会受到影响
js
function Parent() {
+import{_ as s,o as n,c as a,Q as p}from"./chunks/framework.b6910bb2.js";const d=JSON.parse('{"title":"继承","description":"","frontmatter":{},"headers":[],"relativePath":"guide/javaScript相关/继承相关.md","filePath":"guide/javaScript相关/继承相关.md","lastUpdated":1718174182000}'),l={name:"guide/javaScript相关/继承相关.md"},o=p(`

继承

原型链继承

子类的原型对象是父类的实例对象

优点:

  • 简单易懂 缺点:
  • 1 实例化子类时,没办法向父类的构造函数传值
  • 2 所有子类实例共享一个父类,当某个子类修改了父类的属性时,其他子类也会受到影响
js
function Parent() {
     this.name = 'parent';
 }
 
diff --git "a/assets/guide_javaScript\347\233\270\345\205\263_\347\273\247\346\211\277\347\233\270\345\205\263.md.00da001d.lean.js" "b/assets/guide_javaScript\347\233\270\345\205\263_\347\273\247\346\211\277\347\233\270\345\205\263.md.d7ab4f95.lean.js"
similarity index 86%
rename from "assets/guide_javaScript\347\233\270\345\205\263_\347\273\247\346\211\277\347\233\270\345\205\263.md.00da001d.lean.js"
rename to "assets/guide_javaScript\347\233\270\345\205\263_\347\273\247\346\211\277\347\233\270\345\205\263.md.d7ab4f95.lean.js"
index 0ff9358c..b5cf651c 100644
--- "a/assets/guide_javaScript\347\233\270\345\205\263_\347\273\247\346\211\277\347\233\270\345\205\263.md.00da001d.lean.js"
+++ "b/assets/guide_javaScript\347\233\270\345\205\263_\347\273\247\346\211\277\347\233\270\345\205\263.md.d7ab4f95.lean.js"
@@ -1 +1 @@
-import{_ as s,o as n,c as a,Q as p}from"./chunks/framework.b6910bb2.js";const d=JSON.parse('{"title":"继承","description":"","frontmatter":{},"headers":[],"relativePath":"guide/javaScript相关/继承相关.md","filePath":"guide/javaScript相关/继承相关.md","lastUpdated":1718173557000}'),l={name:"guide/javaScript相关/继承相关.md"},o=p("",31),e=[o];function t(c,r,E,y,i,F){return n(),a("div",null,e)}const h=s(l,[["render",t]]);export{d as __pageData,h as default};
+import{_ as s,o as n,c as a,Q as p}from"./chunks/framework.b6910bb2.js";const d=JSON.parse('{"title":"继承","description":"","frontmatter":{},"headers":[],"relativePath":"guide/javaScript相关/继承相关.md","filePath":"guide/javaScript相关/继承相关.md","lastUpdated":1718174182000}'),l={name:"guide/javaScript相关/继承相关.md"},o=p("",31),e=[o];function t(c,r,E,y,i,F){return n(),a("div",null,e)}const h=s(l,[["render",t]]);export{d as __pageData,h as default};
diff --git a/assets/guide_webpack_Loader.md.65e3268d.js b/assets/guide_webpack_Loader.md.efb3dbc7.js
similarity index 99%
rename from assets/guide_webpack_Loader.md.65e3268d.js
rename to assets/guide_webpack_Loader.md.efb3dbc7.js
index 6ab46366..644fafec 100644
--- a/assets/guide_webpack_Loader.md.65e3268d.js
+++ b/assets/guide_webpack_Loader.md.efb3dbc7.js
@@ -1,4 +1,4 @@
-import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.b6910bb2.js";const o="/vitePress-blob/assets/1.f8d8fb4d.png",p="/vitePress-blob/assets/2.ca1be426.png",g=JSON.parse('{"title":"Loader","description":"","frontmatter":{},"headers":[],"relativePath":"guide/webpack/Loader.md","filePath":"guide/webpack/Loader.md","lastUpdated":1718173557000}'),e={name:"guide/webpack/Loader.md"},c=l(`

Loader

loader 是一个加载器,让 webpack 拥有加载和解析非 JavaScript 文件的能力

类型

  1. pre - 前置
  2. normal - 普通
  3. inline - 行内
  4. post - 后置
js
// 定义在 require 请求内部的叫做行内 loader
+import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.b6910bb2.js";const o="/vitePress-blob/assets/1.f8d8fb4d.png",p="/vitePress-blob/assets/2.ca1be426.png",g=JSON.parse('{"title":"Loader","description":"","frontmatter":{},"headers":[],"relativePath":"guide/webpack/Loader.md","filePath":"guide/webpack/Loader.md","lastUpdated":1718174182000}'),e={name:"guide/webpack/Loader.md"},c=l(`

Loader

loader 是一个加载器,让 webpack 拥有加载和解析非 JavaScript 文件的能力

类型

  1. pre - 前置
  2. normal - 普通
  3. inline - 行内
  4. post - 后置
js
// 定义在 require 请求内部的叫做行内 loader
 const a = require('inline1-loader!inline2-loader!a.js');
// 定义在 require 请求内部的叫做行内 loader
 const a = require('inline1-loader!inline2-loader!a.js');
  • 如果是 ! 作为前缀,将禁用 normal loader,例如 !inline1-loader!inline2-loader!a.js
  • 如果是 !! 作为前缀,将禁用所有 loader,例如 !!inline1-loader!inline2-loader!a.js
  • 如果是 -! 作为前缀,将禁用所有 loader 但不包含 post loader,例如 -!inline1-loader!inline2-loader!a.js

pitch

一个 loader 中存在 normal (必须) 和 pitch (可选)

先从左往右执行 loader 的 pitch 方法,在从右往左执行 loader 的默认方法

js
function preLoader(source) {
   console.log("pre1");
diff --git a/assets/guide_webpack_Loader.md.65e3268d.lean.js b/assets/guide_webpack_Loader.md.efb3dbc7.lean.js
similarity index 87%
rename from assets/guide_webpack_Loader.md.65e3268d.lean.js
rename to assets/guide_webpack_Loader.md.efb3dbc7.lean.js
index bbc4a2e0..942d6a9f 100644
--- a/assets/guide_webpack_Loader.md.65e3268d.lean.js
+++ b/assets/guide_webpack_Loader.md.efb3dbc7.lean.js
@@ -1 +1 @@
-import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.b6910bb2.js";const o="/vitePress-blob/assets/1.f8d8fb4d.png",p="/vitePress-blob/assets/2.ca1be426.png",g=JSON.parse('{"title":"Loader","description":"","frontmatter":{},"headers":[],"relativePath":"guide/webpack/Loader.md","filePath":"guide/webpack/Loader.md","lastUpdated":1718173557000}'),e={name:"guide/webpack/Loader.md"},c=l("",13),t=[c];function r(E,y,i,d,F,u){return n(),a("div",null,t)}const q=s(e,[["render",r]]);export{g as __pageData,q as default};
+import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.b6910bb2.js";const o="/vitePress-blob/assets/1.f8d8fb4d.png",p="/vitePress-blob/assets/2.ca1be426.png",g=JSON.parse('{"title":"Loader","description":"","frontmatter":{},"headers":[],"relativePath":"guide/webpack/Loader.md","filePath":"guide/webpack/Loader.md","lastUpdated":1718174182000}'),e={name:"guide/webpack/Loader.md"},c=l("",13),t=[c];function r(E,y,i,d,F,u){return n(),a("div",null,t)}const q=s(e,[["render",r]]);export{g as __pageData,q as default};
diff --git a/assets/guide_webpack_index.md.db3bb590.js b/assets/guide_webpack_index.md.5f5b84e7.js
similarity index 94%
rename from assets/guide_webpack_index.md.db3bb590.js
rename to assets/guide_webpack_index.md.5f5b84e7.js
index 7520b532..622a208f 100644
--- a/assets/guide_webpack_index.md.db3bb590.js
+++ b/assets/guide_webpack_index.md.5f5b84e7.js
@@ -1 +1 @@
-import{_ as t,o as a,c as r,k as e,a as o}from"./chunks/framework.b6910bb2.js";const f=JSON.parse('{"title":"参考文章","description":"","frontmatter":{},"headers":[],"relativePath":"guide/webpack/index.md","filePath":"guide/webpack/index.md","lastUpdated":1718173557000}'),i={name:"guide/webpack/index.md"},n=e("h1",{id:"参考文章",tabindex:"-1"},[o("参考文章 "),e("a",{class:"header-anchor",href:"#参考文章","aria-label":'Permalink to "参考文章"'},"​")],-1),s=e("ul",null,[e("li",null,[e("a",{href:"https://www.youtube.com/watch?v=Gc9-7PBqOC8&list=LLHK1mTHpwrUeYgF5gu-Kd4g",target:"_blank",rel:"noreferrer"},"https://www.youtube.com/watch?v=Gc9-7PBqOC8&list=LLHK1mTHpwrUeYgF5gu-Kd4g")]),e("li",null,[e("a",{href:"https://tsejx.github.io/webpack-guidebook/infra/implementation-principle/workflow",target:"_blank",rel:"noreferrer"},"https://tsejx.github.io/webpack-guidebook/infra/implementation-principle/workflow")])],-1),c=[n,s];function l(d,p,u,h,w,_){return a(),r("div",null,c)}const g=t(i,[["render",l]]);export{f as __pageData,g as default};
+import{_ as t,o as a,c as r,k as e,a as o}from"./chunks/framework.b6910bb2.js";const f=JSON.parse('{"title":"参考文章","description":"","frontmatter":{},"headers":[],"relativePath":"guide/webpack/index.md","filePath":"guide/webpack/index.md","lastUpdated":1718174182000}'),i={name:"guide/webpack/index.md"},n=e("h1",{id:"参考文章",tabindex:"-1"},[o("参考文章 "),e("a",{class:"header-anchor",href:"#参考文章","aria-label":'Permalink to "参考文章"'},"​")],-1),s=e("ul",null,[e("li",null,[e("a",{href:"https://www.youtube.com/watch?v=Gc9-7PBqOC8&list=LLHK1mTHpwrUeYgF5gu-Kd4g",target:"_blank",rel:"noreferrer"},"https://www.youtube.com/watch?v=Gc9-7PBqOC8&list=LLHK1mTHpwrUeYgF5gu-Kd4g")]),e("li",null,[e("a",{href:"https://tsejx.github.io/webpack-guidebook/infra/implementation-principle/workflow",target:"_blank",rel:"noreferrer"},"https://tsejx.github.io/webpack-guidebook/infra/implementation-principle/workflow")])],-1),c=[n,s];function l(d,p,u,h,w,_){return a(),r("div",null,c)}const g=t(i,[["render",l]]);export{f as __pageData,g as default};
diff --git a/assets/guide_webpack_index.md.db3bb590.lean.js b/assets/guide_webpack_index.md.5f5b84e7.lean.js
similarity index 94%
rename from assets/guide_webpack_index.md.db3bb590.lean.js
rename to assets/guide_webpack_index.md.5f5b84e7.lean.js
index 7520b532..622a208f 100644
--- a/assets/guide_webpack_index.md.db3bb590.lean.js
+++ b/assets/guide_webpack_index.md.5f5b84e7.lean.js
@@ -1 +1 @@
-import{_ as t,o as a,c as r,k as e,a as o}from"./chunks/framework.b6910bb2.js";const f=JSON.parse('{"title":"参考文章","description":"","frontmatter":{},"headers":[],"relativePath":"guide/webpack/index.md","filePath":"guide/webpack/index.md","lastUpdated":1718173557000}'),i={name:"guide/webpack/index.md"},n=e("h1",{id:"参考文章",tabindex:"-1"},[o("参考文章 "),e("a",{class:"header-anchor",href:"#参考文章","aria-label":'Permalink to "参考文章"'},"​")],-1),s=e("ul",null,[e("li",null,[e("a",{href:"https://www.youtube.com/watch?v=Gc9-7PBqOC8&list=LLHK1mTHpwrUeYgF5gu-Kd4g",target:"_blank",rel:"noreferrer"},"https://www.youtube.com/watch?v=Gc9-7PBqOC8&list=LLHK1mTHpwrUeYgF5gu-Kd4g")]),e("li",null,[e("a",{href:"https://tsejx.github.io/webpack-guidebook/infra/implementation-principle/workflow",target:"_blank",rel:"noreferrer"},"https://tsejx.github.io/webpack-guidebook/infra/implementation-principle/workflow")])],-1),c=[n,s];function l(d,p,u,h,w,_){return a(),r("div",null,c)}const g=t(i,[["render",l]]);export{f as __pageData,g as default};
+import{_ as t,o as a,c as r,k as e,a as o}from"./chunks/framework.b6910bb2.js";const f=JSON.parse('{"title":"参考文章","description":"","frontmatter":{},"headers":[],"relativePath":"guide/webpack/index.md","filePath":"guide/webpack/index.md","lastUpdated":1718174182000}'),i={name:"guide/webpack/index.md"},n=e("h1",{id:"参考文章",tabindex:"-1"},[o("参考文章 "),e("a",{class:"header-anchor",href:"#参考文章","aria-label":'Permalink to "参考文章"'},"​")],-1),s=e("ul",null,[e("li",null,[e("a",{href:"https://www.youtube.com/watch?v=Gc9-7PBqOC8&list=LLHK1mTHpwrUeYgF5gu-Kd4g",target:"_blank",rel:"noreferrer"},"https://www.youtube.com/watch?v=Gc9-7PBqOC8&list=LLHK1mTHpwrUeYgF5gu-Kd4g")]),e("li",null,[e("a",{href:"https://tsejx.github.io/webpack-guidebook/infra/implementation-principle/workflow",target:"_blank",rel:"noreferrer"},"https://tsejx.github.io/webpack-guidebook/infra/implementation-principle/workflow")])],-1),c=[n,s];function l(d,p,u,h,w,_){return a(),r("div",null,c)}const g=t(i,[["render",l]]);export{f as __pageData,g as default};
diff --git a/assets/guide_webpack_mini-webpack.md.f3f154f9.js b/assets/guide_webpack_mini-webpack.md.408bd203.js
similarity index 91%
rename from assets/guide_webpack_mini-webpack.md.f3f154f9.js
rename to assets/guide_webpack_mini-webpack.md.408bd203.js
index 051a6e74..695da32f 100644
--- a/assets/guide_webpack_mini-webpack.md.f3f154f9.js
+++ b/assets/guide_webpack_mini-webpack.md.408bd203.js
@@ -1 +1 @@
-import{_ as a,o as i,c as t,k as e,a as n}from"./chunks/framework.b6910bb2.js";const w=JSON.parse('{"title":"mini-webpack","description":"","frontmatter":{},"headers":[],"relativePath":"guide/webpack/mini-webpack.md","filePath":"guide/webpack/mini-webpack.md","lastUpdated":1718173557000}'),c={name:"guide/webpack/mini-webpack.md"},r=e("h1",{id:"mini-webpack",tabindex:"-1"},[n("mini-webpack "),e("a",{class:"header-anchor",href:"#mini-webpack","aria-label":'Permalink to "mini-webpack"'},"​")],-1),o=e("p",null,[e("a",{href:"https://github.com/enson0131/mini-webpack",target:"_blank",rel:"noreferrer"},"mini-webpack 仓库")],-1),s=[r,o];function p(d,m,k,b,l,_){return i(),t("div",null,s)}const f=a(c,[["render",p]]);export{w as __pageData,f as default};
+import{_ as a,o as i,c as t,k as e,a as n}from"./chunks/framework.b6910bb2.js";const w=JSON.parse('{"title":"mini-webpack","description":"","frontmatter":{},"headers":[],"relativePath":"guide/webpack/mini-webpack.md","filePath":"guide/webpack/mini-webpack.md","lastUpdated":1718174182000}'),c={name:"guide/webpack/mini-webpack.md"},r=e("h1",{id:"mini-webpack",tabindex:"-1"},[n("mini-webpack "),e("a",{class:"header-anchor",href:"#mini-webpack","aria-label":'Permalink to "mini-webpack"'},"​")],-1),o=e("p",null,[e("a",{href:"https://github.com/enson0131/mini-webpack",target:"_blank",rel:"noreferrer"},"mini-webpack 仓库")],-1),s=[r,o];function p(d,m,k,b,l,_){return i(),t("div",null,s)}const f=a(c,[["render",p]]);export{w as __pageData,f as default};
diff --git a/assets/guide_webpack_mini-webpack.md.f3f154f9.lean.js b/assets/guide_webpack_mini-webpack.md.408bd203.lean.js
similarity index 91%
rename from assets/guide_webpack_mini-webpack.md.f3f154f9.lean.js
rename to assets/guide_webpack_mini-webpack.md.408bd203.lean.js
index 051a6e74..695da32f 100644
--- a/assets/guide_webpack_mini-webpack.md.f3f154f9.lean.js
+++ b/assets/guide_webpack_mini-webpack.md.408bd203.lean.js
@@ -1 +1 @@
-import{_ as a,o as i,c as t,k as e,a as n}from"./chunks/framework.b6910bb2.js";const w=JSON.parse('{"title":"mini-webpack","description":"","frontmatter":{},"headers":[],"relativePath":"guide/webpack/mini-webpack.md","filePath":"guide/webpack/mini-webpack.md","lastUpdated":1718173557000}'),c={name:"guide/webpack/mini-webpack.md"},r=e("h1",{id:"mini-webpack",tabindex:"-1"},[n("mini-webpack "),e("a",{class:"header-anchor",href:"#mini-webpack","aria-label":'Permalink to "mini-webpack"'},"​")],-1),o=e("p",null,[e("a",{href:"https://github.com/enson0131/mini-webpack",target:"_blank",rel:"noreferrer"},"mini-webpack 仓库")],-1),s=[r,o];function p(d,m,k,b,l,_){return i(),t("div",null,s)}const f=a(c,[["render",p]]);export{w as __pageData,f as default};
+import{_ as a,o as i,c as t,k as e,a as n}from"./chunks/framework.b6910bb2.js";const w=JSON.parse('{"title":"mini-webpack","description":"","frontmatter":{},"headers":[],"relativePath":"guide/webpack/mini-webpack.md","filePath":"guide/webpack/mini-webpack.md","lastUpdated":1718174182000}'),c={name:"guide/webpack/mini-webpack.md"},r=e("h1",{id:"mini-webpack",tabindex:"-1"},[n("mini-webpack "),e("a",{class:"header-anchor",href:"#mini-webpack","aria-label":'Permalink to "mini-webpack"'},"​")],-1),o=e("p",null,[e("a",{href:"https://github.com/enson0131/mini-webpack",target:"_blank",rel:"noreferrer"},"mini-webpack 仓库")],-1),s=[r,o];function p(d,m,k,b,l,_){return i(),t("div",null,s)}const f=a(c,[["render",p]]);export{w as __pageData,f as default};
diff --git "a/assets/guide_webpack_\346\236\204\345\273\272\346\265\201\347\250\213.md.18bf89d5.js" "b/assets/guide_webpack_\346\236\204\345\273\272\346\265\201\347\250\213.md.75ec3b17.js"
similarity index 99%
rename from "assets/guide_webpack_\346\236\204\345\273\272\346\265\201\347\250\213.md.18bf89d5.js"
rename to "assets/guide_webpack_\346\236\204\345\273\272\346\265\201\347\250\213.md.75ec3b17.js"
index f1524133..8079e701 100644
--- "a/assets/guide_webpack_\346\236\204\345\273\272\346\265\201\347\250\213.md.18bf89d5.js"
+++ "b/assets/guide_webpack_\346\236\204\345\273\272\346\265\201\347\250\213.md.75ec3b17.js"
@@ -1,4 +1,4 @@
-import{_ as a,o as s,c as l,Q as n}from"./chunks/framework.b6910bb2.js";const y=JSON.parse('{"title":"构建流程","description":"","frontmatter":{},"headers":[],"relativePath":"guide/webpack/构建流程.md","filePath":"guide/webpack/构建流程.md","lastUpdated":1718173557000}'),e={name:"guide/webpack/构建流程.md"},p=n(`

构建流程

工作流程

webpack 的工作流程是一个串行的过程,从启动到结束会依次执行以下流程:

  1. 初始化参数:从配置文件和 Shell 语句中读取与合并参数,得出最终的参数;
  2. 开始编译:用上一步得到的参数初始化 Compiler 对象,加载所有配置的插件,执行对象的 run 方法开始执行编译;
  3. 确定入口:根据配置中的 entry 确定入口文件;
  4. 编译模块:从入口文件出发,调用所有配置的 Loader 对模块进行编译,再找出该模块依赖的模块,得到了每个模块被编译后的 最终内容 以及他们之间的 依赖关系图
  5. 输出资源:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的 Chunk,再把每个 Chunk 转换成一个单独的文件加入到输出列表,这步是可以修改输出内容的最后机会;
  6. 输出完成:在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统。

常见的问题

Module、Chunk、Bundle 的区别

module: 模块,一个模块就是一个文件

chunk: 代码块,一个 chunk 可以由多个模块组合而成

bundle: webpack 打包出来的文件

Loader 和 Plugin

loader 是一个加载器,让 webpack 拥有加载和解析非 JavaScript 文件的能力

Plugin 是一个插件,是对 webpack 功能的扩展,让 webpack 具有更高的灵活性

Compiler 和 Compilation 的区别

Compiler 对象在 webpack 启动时候被实例化,可以访问当前运行的 webpack 配置,包括 entry、output、loader 等配置,它是全局唯一的。

Plugin 的 apply 方法会传入一个 Compiler 对象,通过这个 Compiler 对象可以注册各种钩子函数,执行插件任务,也可以通过该对象获取配置信息。

js
Compiler.plugin('emit', function(compilation, callback) {
+import{_ as a,o as s,c as l,Q as n}from"./chunks/framework.b6910bb2.js";const y=JSON.parse('{"title":"构建流程","description":"","frontmatter":{},"headers":[],"relativePath":"guide/webpack/构建流程.md","filePath":"guide/webpack/构建流程.md","lastUpdated":1718174182000}'),e={name:"guide/webpack/构建流程.md"},p=n(`

构建流程

工作流程

webpack 的工作流程是一个串行的过程,从启动到结束会依次执行以下流程:

  1. 初始化参数:从配置文件和 Shell 语句中读取与合并参数,得出最终的参数;
  2. 开始编译:用上一步得到的参数初始化 Compiler 对象,加载所有配置的插件,执行对象的 run 方法开始执行编译;
  3. 确定入口:根据配置中的 entry 确定入口文件;
  4. 编译模块:从入口文件出发,调用所有配置的 Loader 对模块进行编译,再找出该模块依赖的模块,得到了每个模块被编译后的 最终内容 以及他们之间的 依赖关系图
  5. 输出资源:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的 Chunk,再把每个 Chunk 转换成一个单独的文件加入到输出列表,这步是可以修改输出内容的最后机会;
  6. 输出完成:在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统。

常见的问题

Module、Chunk、Bundle 的区别

module: 模块,一个模块就是一个文件

chunk: 代码块,一个 chunk 可以由多个模块组合而成

bundle: webpack 打包出来的文件

Loader 和 Plugin

loader 是一个加载器,让 webpack 拥有加载和解析非 JavaScript 文件的能力

Plugin 是一个插件,是对 webpack 功能的扩展,让 webpack 具有更高的灵活性

Compiler 和 Compilation 的区别

Compiler 对象在 webpack 启动时候被实例化,可以访问当前运行的 webpack 配置,包括 entry、output、loader 等配置,它是全局唯一的。

Plugin 的 apply 方法会传入一个 Compiler 对象,通过这个 Compiler 对象可以注册各种钩子函数,执行插件任务,也可以通过该对象获取配置信息。

js
Compiler.plugin('emit', function(compilation, callback) {
     // emit 是异步 hook, 在生成之前输出到目录之前调用
  });
Compiler.plugin('emit', function(compilation, callback) {
     // emit 是异步 hook, 在生成之前输出到目录之前调用
diff --git "a/assets/guide_webpack_\346\236\204\345\273\272\346\265\201\347\250\213.md.18bf89d5.lean.js" "b/assets/guide_webpack_\346\236\204\345\273\272\346\265\201\347\250\213.md.75ec3b17.lean.js"
similarity index 86%
rename from "assets/guide_webpack_\346\236\204\345\273\272\346\265\201\347\250\213.md.18bf89d5.lean.js"
rename to "assets/guide_webpack_\346\236\204\345\273\272\346\265\201\347\250\213.md.75ec3b17.lean.js"
index 13346c9e..e0de64ac 100644
--- "a/assets/guide_webpack_\346\236\204\345\273\272\346\265\201\347\250\213.md.18bf89d5.lean.js"
+++ "b/assets/guide_webpack_\346\236\204\345\273\272\346\265\201\347\250\213.md.75ec3b17.lean.js"
@@ -1 +1 @@
-import{_ as a,o as s,c as l,Q as n}from"./chunks/framework.b6910bb2.js";const y=JSON.parse('{"title":"构建流程","description":"","frontmatter":{},"headers":[],"relativePath":"guide/webpack/构建流程.md","filePath":"guide/webpack/构建流程.md","lastUpdated":1718173557000}'),e={name:"guide/webpack/构建流程.md"},p=n("",34),o=[p];function c(t,i,r,d,E,u){return s(),l("div",null,o)}const k=a(e,[["render",c]]);export{y as __pageData,k as default};
+import{_ as a,o as s,c as l,Q as n}from"./chunks/framework.b6910bb2.js";const y=JSON.parse('{"title":"构建流程","description":"","frontmatter":{},"headers":[],"relativePath":"guide/webpack/构建流程.md","filePath":"guide/webpack/构建流程.md","lastUpdated":1718174182000}'),e={name:"guide/webpack/构建流程.md"},p=n("",34),o=[p];function c(t,i,r,d,E,u){return s(),l("div",null,o)}const k=a(e,[["render",c]]);export{y as __pageData,k as default};
diff --git "a/assets/guide_webpack_\346\250\241\345\235\227\350\201\224\351\202\246.md.55fd1b70.js" "b/assets/guide_webpack_\346\250\241\345\235\227\350\201\224\351\202\246.md.74341cda.js"
similarity index 99%
rename from "assets/guide_webpack_\346\250\241\345\235\227\350\201\224\351\202\246.md.55fd1b70.js"
rename to "assets/guide_webpack_\346\250\241\345\235\227\350\201\224\351\202\246.md.74341cda.js"
index 01b1be3c..8bb6f89f 100644
--- "a/assets/guide_webpack_\346\250\241\345\235\227\350\201\224\351\202\246.md.55fd1b70.js"
+++ "b/assets/guide_webpack_\346\250\241\345\235\227\350\201\224\351\202\246.md.74341cda.js"
@@ -1,4 +1,4 @@
-import{_ as a,o as l,c as p,Q as n,k as s}from"./chunks/framework.b6910bb2.js";const o="/vitePress-blob/assets/3.6834884f.png",e="/vitePress-blob/assets/4.ca1b5ab5.png",t="/vitePress-blob/assets/5.ccaac5d9.png",B=JSON.parse('{"title":"模块联邦","description":"","frontmatter":{},"headers":[],"relativePath":"guide/webpack/模块联邦.md","filePath":"guide/webpack/模块联邦.md","lastUpdated":1718173557000}'),c={name:"guide/webpack/模块联邦.md"},r=n('

模块联邦

目的

更好的复用应用块或者库

每个应用块都是独立构建,被称之为容器

Module Federation

一个被引用的容器被称之为 remote

引用者被称之为 host

配置参数

',8),E=s("table",null,[s("thead",null,[s("tr",null,[s("th",null,"字段"),s("th",null,"类型"),s("th",null,"含义")])]),s("tbody",null,[s("tr",{expose:""},[s("td",null,"name"),s("td",null,"string"),s("td",null,"必传值,即输出的模块名,被远程引用时的路径为 ${name}/$")]),s("tr",null,[s("td",null,"library"),s("td",null,"object"),s("td",null,"声明全局变量的方式,name为 umd 的name")]),s("tr",null,[s("td",null,"filename"),s("td",null,"string"),s("td",null,"构建输出的文件名称")]),s("tr",null,[s("td",null,"remotes"),s("td",null,"object"),s("td",null,"(host 使用)远程引用的应用名及其别名的映射,使用时以 key 值作为 name")]),s("tr",null,[s("td",null,"exposes"),s("td",null,"object"),s("td",null,"(remote 使用)被引用时可暴露的资源路径以其别名")]),s("tr",null,[s("td",null,"shared"),s("td",null,"object"),s("td",null,"与其他应用之间可以共享的第三方依赖,使你的代码中不用重复加载同一份依赖")])])],-1),y=n(`

remote 配置

js
// webpack.config.js
+import{_ as a,o as l,c as p,Q as n,k as s}from"./chunks/framework.b6910bb2.js";const o="/vitePress-blob/assets/3.6834884f.png",e="/vitePress-blob/assets/4.ca1b5ab5.png",t="/vitePress-blob/assets/5.ccaac5d9.png",B=JSON.parse('{"title":"模块联邦","description":"","frontmatter":{},"headers":[],"relativePath":"guide/webpack/模块联邦.md","filePath":"guide/webpack/模块联邦.md","lastUpdated":1718174182000}'),c={name:"guide/webpack/模块联邦.md"},r=n('

模块联邦

目的

更好的复用应用块或者库

每个应用块都是独立构建,被称之为容器

Module Federation

一个被引用的容器被称之为 remote

引用者被称之为 host

配置参数

',8),E=s("table",null,[s("thead",null,[s("tr",null,[s("th",null,"字段"),s("th",null,"类型"),s("th",null,"含义")])]),s("tbody",null,[s("tr",{expose:""},[s("td",null,"name"),s("td",null,"string"),s("td",null,"必传值,即输出的模块名,被远程引用时的路径为 ${name}/$")]),s("tr",null,[s("td",null,"library"),s("td",null,"object"),s("td",null,"声明全局变量的方式,name为 umd 的name")]),s("tr",null,[s("td",null,"filename"),s("td",null,"string"),s("td",null,"构建输出的文件名称")]),s("tr",null,[s("td",null,"remotes"),s("td",null,"object"),s("td",null,"(host 使用)远程引用的应用名及其别名的映射,使用时以 key 值作为 name")]),s("tr",null,[s("td",null,"exposes"),s("td",null,"object"),s("td",null,"(remote 使用)被引用时可暴露的资源路径以其别名")]),s("tr",null,[s("td",null,"shared"),s("td",null,"object"),s("td",null,"与其他应用之间可以共享的第三方依赖,使你的代码中不用重复加载同一份依赖")])])],-1),y=n(`

remote 配置

js
// webpack.config.js
 const path = require("path");
 const webpack = require("webpack");
 const HtmlWebpackPlugin = require("html-webpack-plugin");
diff --git "a/assets/guide_webpack_\346\250\241\345\235\227\350\201\224\351\202\246.md.55fd1b70.lean.js" "b/assets/guide_webpack_\346\250\241\345\235\227\350\201\224\351\202\246.md.74341cda.lean.js"
similarity index 96%
rename from "assets/guide_webpack_\346\250\241\345\235\227\350\201\224\351\202\246.md.55fd1b70.lean.js"
rename to "assets/guide_webpack_\346\250\241\345\235\227\350\201\224\351\202\246.md.74341cda.lean.js"
index c22a6d9a..bdc468e5 100644
--- "a/assets/guide_webpack_\346\250\241\345\235\227\350\201\224\351\202\246.md.55fd1b70.lean.js"
+++ "b/assets/guide_webpack_\346\250\241\345\235\227\350\201\224\351\202\246.md.74341cda.lean.js"
@@ -1 +1 @@
-import{_ as a,o as l,c as p,Q as n,k as s}from"./chunks/framework.b6910bb2.js";const o="/vitePress-blob/assets/3.6834884f.png",e="/vitePress-blob/assets/4.ca1b5ab5.png",t="/vitePress-blob/assets/5.ccaac5d9.png",B=JSON.parse('{"title":"模块联邦","description":"","frontmatter":{},"headers":[],"relativePath":"guide/webpack/模块联邦.md","filePath":"guide/webpack/模块联邦.md","lastUpdated":1718173557000}'),c={name:"guide/webpack/模块联邦.md"},r=n("",8),E=s("table",null,[s("thead",null,[s("tr",null,[s("th",null,"字段"),s("th",null,"类型"),s("th",null,"含义")])]),s("tbody",null,[s("tr",{expose:""},[s("td",null,"name"),s("td",null,"string"),s("td",null,"必传值,即输出的模块名,被远程引用时的路径为 ${name}/$")]),s("tr",null,[s("td",null,"library"),s("td",null,"object"),s("td",null,"声明全局变量的方式,name为 umd 的name")]),s("tr",null,[s("td",null,"filename"),s("td",null,"string"),s("td",null,"构建输出的文件名称")]),s("tr",null,[s("td",null,"remotes"),s("td",null,"object"),s("td",null,"(host 使用)远程引用的应用名及其别名的映射,使用时以 key 值作为 name")]),s("tr",null,[s("td",null,"exposes"),s("td",null,"object"),s("td",null,"(remote 使用)被引用时可暴露的资源路径以其别名")]),s("tr",null,[s("td",null,"shared"),s("td",null,"object"),s("td",null,"与其他应用之间可以共享的第三方依赖,使你的代码中不用重复加载同一份依赖")])])],-1),y=n("",15),i=[r,E,y];function u(F,d,q,h,m,b){return l(),p("div",null,i)}const g=a(c,[["render",u]]);export{B as __pageData,g as default};
+import{_ as a,o as l,c as p,Q as n,k as s}from"./chunks/framework.b6910bb2.js";const o="/vitePress-blob/assets/3.6834884f.png",e="/vitePress-blob/assets/4.ca1b5ab5.png",t="/vitePress-blob/assets/5.ccaac5d9.png",B=JSON.parse('{"title":"模块联邦","description":"","frontmatter":{},"headers":[],"relativePath":"guide/webpack/模块联邦.md","filePath":"guide/webpack/模块联邦.md","lastUpdated":1718174182000}'),c={name:"guide/webpack/模块联邦.md"},r=n("",8),E=s("table",null,[s("thead",null,[s("tr",null,[s("th",null,"字段"),s("th",null,"类型"),s("th",null,"含义")])]),s("tbody",null,[s("tr",{expose:""},[s("td",null,"name"),s("td",null,"string"),s("td",null,"必传值,即输出的模块名,被远程引用时的路径为 ${name}/$")]),s("tr",null,[s("td",null,"library"),s("td",null,"object"),s("td",null,"声明全局变量的方式,name为 umd 的name")]),s("tr",null,[s("td",null,"filename"),s("td",null,"string"),s("td",null,"构建输出的文件名称")]),s("tr",null,[s("td",null,"remotes"),s("td",null,"object"),s("td",null,"(host 使用)远程引用的应用名及其别名的映射,使用时以 key 值作为 name")]),s("tr",null,[s("td",null,"exposes"),s("td",null,"object"),s("td",null,"(remote 使用)被引用时可暴露的资源路径以其别名")]),s("tr",null,[s("td",null,"shared"),s("td",null,"object"),s("td",null,"与其他应用之间可以共享的第三方依赖,使你的代码中不用重复加载同一份依赖")])])],-1),y=n("",15),i=[r,E,y];function u(F,d,q,h,m,b){return l(),p("div",null,i)}const g=a(c,[["render",u]]);export{B as __pageData,g as default};
diff --git "a/assets/guide_webpack_\347\203\255\346\233\264\346\226\260\345\216\237\347\220\206.md.081bcae8.js" "b/assets/guide_webpack_\347\203\255\346\233\264\346\226\260\345\216\237\347\220\206.md.fa9979a3.js"
similarity index 90%
rename from "assets/guide_webpack_\347\203\255\346\233\264\346\226\260\345\216\237\347\220\206.md.081bcae8.js"
rename to "assets/guide_webpack_\347\203\255\346\233\264\346\226\260\345\216\237\347\220\206.md.fa9979a3.js"
index 7948d4d4..34ab5701 100644
--- "a/assets/guide_webpack_\347\203\255\346\233\264\346\226\260\345\216\237\347\220\206.md.081bcae8.js"
+++ "b/assets/guide_webpack_\347\203\255\346\233\264\346\226\260\345\216\237\347\220\206.md.fa9979a3.js"
@@ -1 +1 @@
-import{_ as a,o as t,c as s,k as e,a as o}from"./chunks/framework.b6910bb2.js";const u=JSON.parse('{"title":"热更新原理","description":"","frontmatter":{},"headers":[],"relativePath":"guide/webpack/热更新原理.md","filePath":"guide/webpack/热更新原理.md","lastUpdated":1718173557000}'),r={name:"guide/webpack/热更新原理.md"},c=e("h1",{id:"热更新原理",tabindex:"-1"},[o("热更新原理 "),e("a",{class:"header-anchor",href:"#热更新原理","aria-label":'Permalink to "热更新原理"'},"​")],-1),d=[c];function n(_,i,p,l,h,m){return t(),s("div",null,d)}const k=a(r,[["render",n]]);export{u as __pageData,k as default};
+import{_ as a,o as t,c as s,k as e,a as o}from"./chunks/framework.b6910bb2.js";const u=JSON.parse('{"title":"热更新原理","description":"","frontmatter":{},"headers":[],"relativePath":"guide/webpack/热更新原理.md","filePath":"guide/webpack/热更新原理.md","lastUpdated":1718174182000}'),r={name:"guide/webpack/热更新原理.md"},c=e("h1",{id:"热更新原理",tabindex:"-1"},[o("热更新原理 "),e("a",{class:"header-anchor",href:"#热更新原理","aria-label":'Permalink to "热更新原理"'},"​")],-1),d=[c];function n(_,i,p,l,h,m){return t(),s("div",null,d)}const k=a(r,[["render",n]]);export{u as __pageData,k as default};
diff --git "a/assets/guide_webpack_\347\203\255\346\233\264\346\226\260\345\216\237\347\220\206.md.081bcae8.lean.js" "b/assets/guide_webpack_\347\203\255\346\233\264\346\226\260\345\216\237\347\220\206.md.fa9979a3.lean.js"
similarity index 90%
rename from "assets/guide_webpack_\347\203\255\346\233\264\346\226\260\345\216\237\347\220\206.md.081bcae8.lean.js"
rename to "assets/guide_webpack_\347\203\255\346\233\264\346\226\260\345\216\237\347\220\206.md.fa9979a3.lean.js"
index 7948d4d4..34ab5701 100644
--- "a/assets/guide_webpack_\347\203\255\346\233\264\346\226\260\345\216\237\347\220\206.md.081bcae8.lean.js"
+++ "b/assets/guide_webpack_\347\203\255\346\233\264\346\226\260\345\216\237\347\220\206.md.fa9979a3.lean.js"
@@ -1 +1 @@
-import{_ as a,o as t,c as s,k as e,a as o}from"./chunks/framework.b6910bb2.js";const u=JSON.parse('{"title":"热更新原理","description":"","frontmatter":{},"headers":[],"relativePath":"guide/webpack/热更新原理.md","filePath":"guide/webpack/热更新原理.md","lastUpdated":1718173557000}'),r={name:"guide/webpack/热更新原理.md"},c=e("h1",{id:"热更新原理",tabindex:"-1"},[o("热更新原理 "),e("a",{class:"header-anchor",href:"#热更新原理","aria-label":'Permalink to "热更新原理"'},"​")],-1),d=[c];function n(_,i,p,l,h,m){return t(),s("div",null,d)}const k=a(r,[["render",n]]);export{u as __pageData,k as default};
+import{_ as a,o as t,c as s,k as e,a as o}from"./chunks/framework.b6910bb2.js";const u=JSON.parse('{"title":"热更新原理","description":"","frontmatter":{},"headers":[],"relativePath":"guide/webpack/热更新原理.md","filePath":"guide/webpack/热更新原理.md","lastUpdated":1718174182000}'),r={name:"guide/webpack/热更新原理.md"},c=e("h1",{id:"热更新原理",tabindex:"-1"},[o("热更新原理 "),e("a",{class:"header-anchor",href:"#热更新原理","aria-label":'Permalink to "热更新原理"'},"​")],-1),d=[c];function n(_,i,p,l,h,m){return t(),s("div",null,d)}const k=a(r,[["render",n]]);export{u as __pageData,k as default};
diff --git "a/assets/guide_\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263_\346\246\202\350\246\201.md.4c97d5fd.js" "b/assets/guide_\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263_\346\246\202\350\246\201.md.02c9983a.js"
similarity index 88%
rename from "assets/guide_\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263_\346\246\202\350\246\201.md.4c97d5fd.js"
rename to "assets/guide_\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263_\346\246\202\350\246\201.md.02c9983a.js"
index 03e5f90f..68ce769a 100644
--- "a/assets/guide_\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263_\346\246\202\350\246\201.md.4c97d5fd.js"
+++ "b/assets/guide_\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263_\346\246\202\350\246\201.md.02c9983a.js"
@@ -1 +1 @@
-import{_ as e}from"./chunks/container.fad5294e.js";import{o as t,c as a,H as s}from"./chunks/framework.b6910bb2.js";const m=JSON.parse('{"title":"","description":"","frontmatter":{"aside":false,"outline":false},"headers":[],"relativePath":"guide/浏览器相关/概要.md","filePath":"guide/浏览器相关/概要.md","lastUpdated":1718173557000}'),o={name:"guide/浏览器相关/概要.md"},n=Object.assign(o,{setup(r){return(c,d)=>(t(),a("div",null,[s(e,{url:"https://www.mubu.com/doc/-ip51T7dbe#m"})]))}});export{m as __pageData,n as default};
+import{_ as e}from"./chunks/container.fad5294e.js";import{o as t,c as a,H as s}from"./chunks/framework.b6910bb2.js";const m=JSON.parse('{"title":"","description":"","frontmatter":{"aside":false,"outline":false},"headers":[],"relativePath":"guide/浏览器相关/概要.md","filePath":"guide/浏览器相关/概要.md","lastUpdated":1718174182000}'),o={name:"guide/浏览器相关/概要.md"},n=Object.assign(o,{setup(r){return(c,d)=>(t(),a("div",null,[s(e,{url:"https://www.mubu.com/doc/-ip51T7dbe#m"})]))}});export{m as __pageData,n as default};
diff --git "a/assets/guide_\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263_\346\246\202\350\246\201.md.4c97d5fd.lean.js" "b/assets/guide_\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263_\346\246\202\350\246\201.md.02c9983a.lean.js"
similarity index 88%
rename from "assets/guide_\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263_\346\246\202\350\246\201.md.4c97d5fd.lean.js"
rename to "assets/guide_\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263_\346\246\202\350\246\201.md.02c9983a.lean.js"
index 03e5f90f..68ce769a 100644
--- "a/assets/guide_\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263_\346\246\202\350\246\201.md.4c97d5fd.lean.js"
+++ "b/assets/guide_\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263_\346\246\202\350\246\201.md.02c9983a.lean.js"
@@ -1 +1 @@
-import{_ as e}from"./chunks/container.fad5294e.js";import{o as t,c as a,H as s}from"./chunks/framework.b6910bb2.js";const m=JSON.parse('{"title":"","description":"","frontmatter":{"aside":false,"outline":false},"headers":[],"relativePath":"guide/浏览器相关/概要.md","filePath":"guide/浏览器相关/概要.md","lastUpdated":1718173557000}'),o={name:"guide/浏览器相关/概要.md"},n=Object.assign(o,{setup(r){return(c,d)=>(t(),a("div",null,[s(e,{url:"https://www.mubu.com/doc/-ip51T7dbe#m"})]))}});export{m as __pageData,n as default};
+import{_ as e}from"./chunks/container.fad5294e.js";import{o as t,c as a,H as s}from"./chunks/framework.b6910bb2.js";const m=JSON.parse('{"title":"","description":"","frontmatter":{"aside":false,"outline":false},"headers":[],"relativePath":"guide/浏览器相关/概要.md","filePath":"guide/浏览器相关/概要.md","lastUpdated":1718174182000}'),o={name:"guide/浏览器相关/概要.md"},n=Object.assign(o,{setup(r){return(c,d)=>(t(),a("div",null,[s(e,{url:"https://www.mubu.com/doc/-ip51T7dbe#m"})]))}});export{m as __pageData,n as default};
diff --git "a/assets/guide_\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263_\346\265\217\350\247\210\345\231\250\345\206\205\346\240\270.md.a4aefbe3.js" "b/assets/guide_\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263_\346\265\217\350\247\210\345\231\250\345\206\205\346\240\270.md.68b358b7.js"
similarity index 92%
rename from "assets/guide_\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263_\346\265\217\350\247\210\345\231\250\345\206\205\346\240\270.md.a4aefbe3.js"
rename to "assets/guide_\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263_\346\265\217\350\247\210\345\231\250\345\206\205\346\240\270.md.68b358b7.js"
index b8840ac1..4580845c 100644
--- "a/assets/guide_\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263_\346\265\217\350\247\210\345\231\250\345\206\205\346\240\270.md.a4aefbe3.js"
+++ "b/assets/guide_\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263_\346\265\217\350\247\210\345\231\250\345\206\205\346\240\270.md.68b358b7.js"
@@ -1 +1 @@
-import{_ as t,o as a,c as i,k as e,a as l}from"./chunks/framework.b6910bb2.js";const k=JSON.parse('{"title":"浏览器内核","description":"","frontmatter":{},"headers":[],"relativePath":"guide/浏览器相关/浏览器内核.md","filePath":"guide/浏览器相关/浏览器内核.md","lastUpdated":1718173557000}'),n={name:"guide/浏览器相关/浏览器内核.md"},o=e("h1",{id:"浏览器内核",tabindex:"-1"},[l("浏览器内核 "),e("a",{class:"header-anchor",href:"#浏览器内核","aria-label":'Permalink to "浏览器内核"'},"​")],-1),r=e("ul",null,[e("li",null,"Trident (IE)"),e("li",null,"Gecko (Firefox)"),e("li",null,"Webkit (Safari)"),e("li",null,"Blink (Chrome、Opera) Blink 是 Webkit 的一个分支")],-1),s=[o,r];function d(c,_,u,p,h,f){return a(),i("div",null,s)}const x=t(n,[["render",d]]);export{k as __pageData,x as default};
+import{_ as t,o as a,c as i,k as e,a as l}from"./chunks/framework.b6910bb2.js";const k=JSON.parse('{"title":"浏览器内核","description":"","frontmatter":{},"headers":[],"relativePath":"guide/浏览器相关/浏览器内核.md","filePath":"guide/浏览器相关/浏览器内核.md","lastUpdated":1718174182000}'),n={name:"guide/浏览器相关/浏览器内核.md"},o=e("h1",{id:"浏览器内核",tabindex:"-1"},[l("浏览器内核 "),e("a",{class:"header-anchor",href:"#浏览器内核","aria-label":'Permalink to "浏览器内核"'},"​")],-1),r=e("ul",null,[e("li",null,"Trident (IE)"),e("li",null,"Gecko (Firefox)"),e("li",null,"Webkit (Safari)"),e("li",null,"Blink (Chrome、Opera) Blink 是 Webkit 的一个分支")],-1),s=[o,r];function d(c,_,u,p,h,f){return a(),i("div",null,s)}const x=t(n,[["render",d]]);export{k as __pageData,x as default};
diff --git "a/assets/guide_\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263_\346\265\217\350\247\210\345\231\250\345\206\205\346\240\270.md.a4aefbe3.lean.js" "b/assets/guide_\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263_\346\265\217\350\247\210\345\231\250\345\206\205\346\240\270.md.68b358b7.lean.js"
similarity index 92%
rename from "assets/guide_\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263_\346\265\217\350\247\210\345\231\250\345\206\205\346\240\270.md.a4aefbe3.lean.js"
rename to "assets/guide_\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263_\346\265\217\350\247\210\345\231\250\345\206\205\346\240\270.md.68b358b7.lean.js"
index b8840ac1..4580845c 100644
--- "a/assets/guide_\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263_\346\265\217\350\247\210\345\231\250\345\206\205\346\240\270.md.a4aefbe3.lean.js"
+++ "b/assets/guide_\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263_\346\265\217\350\247\210\345\231\250\345\206\205\346\240\270.md.68b358b7.lean.js"
@@ -1 +1 @@
-import{_ as t,o as a,c as i,k as e,a as l}from"./chunks/framework.b6910bb2.js";const k=JSON.parse('{"title":"浏览器内核","description":"","frontmatter":{},"headers":[],"relativePath":"guide/浏览器相关/浏览器内核.md","filePath":"guide/浏览器相关/浏览器内核.md","lastUpdated":1718173557000}'),n={name:"guide/浏览器相关/浏览器内核.md"},o=e("h1",{id:"浏览器内核",tabindex:"-1"},[l("浏览器内核 "),e("a",{class:"header-anchor",href:"#浏览器内核","aria-label":'Permalink to "浏览器内核"'},"​")],-1),r=e("ul",null,[e("li",null,"Trident (IE)"),e("li",null,"Gecko (Firefox)"),e("li",null,"Webkit (Safari)"),e("li",null,"Blink (Chrome、Opera) Blink 是 Webkit 的一个分支")],-1),s=[o,r];function d(c,_,u,p,h,f){return a(),i("div",null,s)}const x=t(n,[["render",d]]);export{k as __pageData,x as default};
+import{_ as t,o as a,c as i,k as e,a as l}from"./chunks/framework.b6910bb2.js";const k=JSON.parse('{"title":"浏览器内核","description":"","frontmatter":{},"headers":[],"relativePath":"guide/浏览器相关/浏览器内核.md","filePath":"guide/浏览器相关/浏览器内核.md","lastUpdated":1718174182000}'),n={name:"guide/浏览器相关/浏览器内核.md"},o=e("h1",{id:"浏览器内核",tabindex:"-1"},[l("浏览器内核 "),e("a",{class:"header-anchor",href:"#浏览器内核","aria-label":'Permalink to "浏览器内核"'},"​")],-1),r=e("ul",null,[e("li",null,"Trident (IE)"),e("li",null,"Gecko (Firefox)"),e("li",null,"Webkit (Safari)"),e("li",null,"Blink (Chrome、Opera) Blink 是 Webkit 的一个分支")],-1),s=[o,r];function d(c,_,u,p,h,f){return a(),i("div",null,s)}const x=t(n,[["render",d]]);export{k as __pageData,x as default};
diff --git "a/assets/guide_\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263_\346\265\217\350\247\210\345\231\250\345\256\211\345\205\250.md.25196afe.js" "b/assets/guide_\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263_\346\265\217\350\247\210\345\231\250\345\256\211\345\205\250.md.377392a3.js"
similarity index 99%
rename from "assets/guide_\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263_\346\265\217\350\247\210\345\231\250\345\256\211\345\205\250.md.25196afe.js"
rename to "assets/guide_\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263_\346\265\217\350\247\210\345\231\250\345\256\211\345\205\250.md.377392a3.js"
index 0c05558e..5840d6b8 100644
--- "a/assets/guide_\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263_\346\265\217\350\247\210\345\231\250\345\256\211\345\205\250.md.25196afe.js"
+++ "b/assets/guide_\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263_\346\265\217\350\247\210\345\231\250\345\256\211\345\205\250.md.377392a3.js"
@@ -1 +1 @@
-import{_ as l,o as i,c as e,Q as a}from"./chunks/framework.b6910bb2.js";const o="/vitePress-blob/assets/6.36673f2f.jpg",t="/vitePress-blob/assets/7.d0aefc74.jpg",r="/vitePress-blob/assets/8.28d1dcd9.jpg",s="/vitePress-blob/assets/9.b32cc031.jpg",P=JSON.parse('{"title":"浏览器安全","description":"","frontmatter":{},"headers":[],"relativePath":"guide/浏览器相关/浏览器安全.md","filePath":"guide/浏览器相关/浏览器安全.md","lastUpdated":1718173557000}'),n={name:"guide/浏览器相关/浏览器安全.md"},c=a('

浏览器安全

页面安全

同源策略

协议、域名、端口号都相同,才是同源。

限制

  1. 无法进行 DOM 操作
  2. 无法获取 Cookie、LocalStorage 等数据
  3. 无法向不同源发请求

开放

  1. 默认页面中可以引用任意第三方资源

    引入 CSP (内容安全策略)

    渲染流程图

  2. 只能请求同源的接口

    引入 CORS (跨域资源共享)

    • 简单请求 (HEAD/POST/GET请求)

      1. 浏览器在请求头上添加 Oirgin 字段,该字段用来说明请求来自那个源,服务器可以根据这个值决定是否同意这次请求
      2. 当服务器收到请求后,根据 Origin 判断是否在许可范围内
      3. 如果不在范围内,服务器会返回一个正常的 HTTP 响应,浏览器发现该响应头没有包含 Access-Control-Allow-Origin 字段,就会抛出一个错误,被 XMLHttpRequest 的 onerror 回调函数捕获 (由于正常响应,其状态码是 200,所以该错误不能通过状态码识别)
      4. 如果 Origin 在指定范围内,服务器返回的响应会多几个头信息字段
        • Access-Control-Allow-Origin(必须) 判断源是否可以跨域,该值要么是请求的 Origin,要么是 *

        • Access-Control-Allow-Credentials 是否允许发送 Cookie,默认为 false 如果 Access-Control-Allow-Origin 的值为 *,则无法发送 Cookie

        • Access-Control-Expose-Headers 制定其他的头信息字段可以暴露给客户端 因为默认情况下,只有 6 个字段可以被暴露,其他的都会被过滤掉

          简单请求

    • 非简单请求 (PUT/DELETE 或者 Content-type字段类型是 application/json)

      1. 浏览器发起 Option 预检请求
      2. 服务器收到预检请求后,检查
        • Origin 发起请求的源信息
        • Access-Control-Request-Method 浏览器会发起请求的方法
        • Access-Control-Request-Headers 请求额外发送的头信息字段
      3. 如果服务器否定预检请求,会返回一个正常的 HTTP 响应,但是没有任何的 CORS 相关的头信息字段,这是浏览器会认定服务器不同意预检,触发错误
      4. 如果服务器同意预检请求,会返回一个正常的 HTTP 响应,但是会多几个 CORS 相关的头信息字段
        • Access-Control-Allow-Origin (必须)
        • Access-Control-Allow-Methods (必须)
        • Access-Control-Allow-Credentials
        • Access-Control-Expose-Headers
        • Access-Control-Max-Age - 预检请求的有效期, 单位秒
        • Access-Control-Allow-Headers

      非简单请求

  3. 只能操作同源的DOM

    引入了跨文档消息机制 postMessage

XSS 攻击

跨域脚本攻击。

类型

  1. 存储型

    脚本存储在服务器,用户访问时,脚本从服务器返回,浏览器执行脚本

  2. 反射型

    在文章链接参数上存放了一段恶意脚本,用户访问时,脚本从参数中取出,浏览器执行脚本

  3. DOM 型

    比如在搜索的时候,添加了一段脚本, 如果网站的搜索功能没有对用户输入进行适当的过滤和转义,搜索结果页面可能会将恶意的脚本代码直接插入到 HTML 中,并在用户浏览器中执行

    web 资源在传输或者用户在使用的过程中修改了 Web 页面的数据

预防

  1. 对输入的内容进行截取或者转义(encode)
  2. 限制输入的长度和类型
  3. 引入内容安全策略 (CSP)
  4. 对 Cookie 设置 HttpOnly 属性

CSRF 攻击

跨站请求伪造。

比如诱导用户点击链接,访问网址后,网址通过用户的登录信息伪造请求

必要条件

  1. 站点有 CSRF 漏洞
  2. 用户登录了
  3. 用户点击了诱导链接

预防

  1. 给 Cookie 新增 SameSite 属性
    • Strict: 第三方站点无法发送 Cookie
    • Lax (默认): 第三方站点如果是 GET 请求可以发送 Cookie
    • None 不做限制 Cookie的书写
  2. 通过请求的 Origin or Referer 字段判断请求合法性
  3. 在请求地址中添加 token 并验证

浏览器安全

将渲染进程放在沙箱中

  • 无法持久存储
  • 无法访问网络
  • 无法监听用户交互
  • 需要通过 IPC 与浏览器主进程通信,由浏览器进程处理后,再将结果传递给渲染进程

网络安全

HTTPS、重放攻击、验签

  • 基本属性:

    • name
    • value
  • 访问性:

    • expire
    • path
    • domain
  • 安全性:

    • secure
    • httpOnly
    • sameSite
',28),p=[c];function h(d,u,_,b,C,m){return i(),e("div",null,p)}const f=l(n,[["render",h]]);export{P as __pageData,f as default}; +import{_ as l,o as i,c as e,Q as a}from"./chunks/framework.b6910bb2.js";const o="/vitePress-blob/assets/6.36673f2f.jpg",t="/vitePress-blob/assets/7.d0aefc74.jpg",r="/vitePress-blob/assets/8.28d1dcd9.jpg",s="/vitePress-blob/assets/9.b32cc031.jpg",P=JSON.parse('{"title":"浏览器安全","description":"","frontmatter":{},"headers":[],"relativePath":"guide/浏览器相关/浏览器安全.md","filePath":"guide/浏览器相关/浏览器安全.md","lastUpdated":1718174182000}'),n={name:"guide/浏览器相关/浏览器安全.md"},c=a('

浏览器安全

页面安全

同源策略

协议、域名、端口号都相同,才是同源。

限制

  1. 无法进行 DOM 操作
  2. 无法获取 Cookie、LocalStorage 等数据
  3. 无法向不同源发请求

开放

  1. 默认页面中可以引用任意第三方资源

    引入 CSP (内容安全策略)

    渲染流程图

  2. 只能请求同源的接口

    引入 CORS (跨域资源共享)

    • 简单请求 (HEAD/POST/GET请求)

      1. 浏览器在请求头上添加 Oirgin 字段,该字段用来说明请求来自那个源,服务器可以根据这个值决定是否同意这次请求
      2. 当服务器收到请求后,根据 Origin 判断是否在许可范围内
      3. 如果不在范围内,服务器会返回一个正常的 HTTP 响应,浏览器发现该响应头没有包含 Access-Control-Allow-Origin 字段,就会抛出一个错误,被 XMLHttpRequest 的 onerror 回调函数捕获 (由于正常响应,其状态码是 200,所以该错误不能通过状态码识别)
      4. 如果 Origin 在指定范围内,服务器返回的响应会多几个头信息字段
        • Access-Control-Allow-Origin(必须) 判断源是否可以跨域,该值要么是请求的 Origin,要么是 *

        • Access-Control-Allow-Credentials 是否允许发送 Cookie,默认为 false 如果 Access-Control-Allow-Origin 的值为 *,则无法发送 Cookie

        • Access-Control-Expose-Headers 制定其他的头信息字段可以暴露给客户端 因为默认情况下,只有 6 个字段可以被暴露,其他的都会被过滤掉

          简单请求

    • 非简单请求 (PUT/DELETE 或者 Content-type字段类型是 application/json)

      1. 浏览器发起 Option 预检请求
      2. 服务器收到预检请求后,检查
        • Origin 发起请求的源信息
        • Access-Control-Request-Method 浏览器会发起请求的方法
        • Access-Control-Request-Headers 请求额外发送的头信息字段
      3. 如果服务器否定预检请求,会返回一个正常的 HTTP 响应,但是没有任何的 CORS 相关的头信息字段,这是浏览器会认定服务器不同意预检,触发错误
      4. 如果服务器同意预检请求,会返回一个正常的 HTTP 响应,但是会多几个 CORS 相关的头信息字段
        • Access-Control-Allow-Origin (必须)
        • Access-Control-Allow-Methods (必须)
        • Access-Control-Allow-Credentials
        • Access-Control-Expose-Headers
        • Access-Control-Max-Age - 预检请求的有效期, 单位秒
        • Access-Control-Allow-Headers

      非简单请求

  3. 只能操作同源的DOM

    引入了跨文档消息机制 postMessage

XSS 攻击

跨域脚本攻击。

类型

  1. 存储型

    脚本存储在服务器,用户访问时,脚本从服务器返回,浏览器执行脚本

  2. 反射型

    在文章链接参数上存放了一段恶意脚本,用户访问时,脚本从参数中取出,浏览器执行脚本

  3. DOM 型

    比如在搜索的时候,添加了一段脚本, 如果网站的搜索功能没有对用户输入进行适当的过滤和转义,搜索结果页面可能会将恶意的脚本代码直接插入到 HTML 中,并在用户浏览器中执行

    web 资源在传输或者用户在使用的过程中修改了 Web 页面的数据

预防

  1. 对输入的内容进行截取或者转义(encode)
  2. 限制输入的长度和类型
  3. 引入内容安全策略 (CSP)
  4. 对 Cookie 设置 HttpOnly 属性

CSRF 攻击

跨站请求伪造。

比如诱导用户点击链接,访问网址后,网址通过用户的登录信息伪造请求

必要条件

  1. 站点有 CSRF 漏洞
  2. 用户登录了
  3. 用户点击了诱导链接

预防

  1. 给 Cookie 新增 SameSite 属性
    • Strict: 第三方站点无法发送 Cookie
    • Lax (默认): 第三方站点如果是 GET 请求可以发送 Cookie
    • None 不做限制 Cookie的书写
  2. 通过请求的 Origin or Referer 字段判断请求合法性
  3. 在请求地址中添加 token 并验证

浏览器安全

将渲染进程放在沙箱中

  • 无法持久存储
  • 无法访问网络
  • 无法监听用户交互
  • 需要通过 IPC 与浏览器主进程通信,由浏览器进程处理后,再将结果传递给渲染进程

网络安全

HTTPS、重放攻击、验签

  • 基本属性:

    • name
    • value
  • 访问性:

    • expire
    • path
    • domain
  • 安全性:

    • secure
    • httpOnly
    • sameSite
',28),p=[c];function h(d,u,_,b,C,m){return i(),e("div",null,p)}const f=l(n,[["render",h]]);export{P as __pageData,f as default}; diff --git "a/assets/guide_\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263_\346\265\217\350\247\210\345\231\250\345\256\211\345\205\250.md.25196afe.lean.js" "b/assets/guide_\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263_\346\265\217\350\247\210\345\231\250\345\256\211\345\205\250.md.377392a3.lean.js" similarity index 90% rename from "assets/guide_\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263_\346\265\217\350\247\210\345\231\250\345\256\211\345\205\250.md.25196afe.lean.js" rename to "assets/guide_\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263_\346\265\217\350\247\210\345\231\250\345\256\211\345\205\250.md.377392a3.lean.js" index 189a7c40..c9703b35 100644 --- "a/assets/guide_\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263_\346\265\217\350\247\210\345\231\250\345\256\211\345\205\250.md.25196afe.lean.js" +++ "b/assets/guide_\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263_\346\265\217\350\247\210\345\231\250\345\256\211\345\205\250.md.377392a3.lean.js" @@ -1 +1 @@ -import{_ as l,o as i,c as e,Q as a}from"./chunks/framework.b6910bb2.js";const o="/vitePress-blob/assets/6.36673f2f.jpg",t="/vitePress-blob/assets/7.d0aefc74.jpg",r="/vitePress-blob/assets/8.28d1dcd9.jpg",s="/vitePress-blob/assets/9.b32cc031.jpg",P=JSON.parse('{"title":"浏览器安全","description":"","frontmatter":{},"headers":[],"relativePath":"guide/浏览器相关/浏览器安全.md","filePath":"guide/浏览器相关/浏览器安全.md","lastUpdated":1718173557000}'),n={name:"guide/浏览器相关/浏览器安全.md"},c=a("",28),p=[c];function h(d,u,_,b,C,m){return i(),e("div",null,p)}const f=l(n,[["render",h]]);export{P as __pageData,f as default}; +import{_ as l,o as i,c as e,Q as a}from"./chunks/framework.b6910bb2.js";const o="/vitePress-blob/assets/6.36673f2f.jpg",t="/vitePress-blob/assets/7.d0aefc74.jpg",r="/vitePress-blob/assets/8.28d1dcd9.jpg",s="/vitePress-blob/assets/9.b32cc031.jpg",P=JSON.parse('{"title":"浏览器安全","description":"","frontmatter":{},"headers":[],"relativePath":"guide/浏览器相关/浏览器安全.md","filePath":"guide/浏览器相关/浏览器安全.md","lastUpdated":1718174182000}'),n={name:"guide/浏览器相关/浏览器安全.md"},c=a("",28),p=[c];function h(d,u,_,b,C,m){return i(),e("div",null,p)}const f=l(n,[["render",h]]);export{P as __pageData,f as default}; diff --git "a/assets/guide_\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263_\346\265\217\350\247\210\345\231\250\346\270\262\346\237\223\346\265\201\347\250\213.md.144e6f8e.js" "b/assets/guide_\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263_\346\265\217\350\247\210\345\231\250\346\270\262\346\237\223\346\265\201\347\250\213.md.12bb6e51.js" similarity index 99% rename from "assets/guide_\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263_\346\265\217\350\247\210\345\231\250\346\270\262\346\237\223\346\265\201\347\250\213.md.144e6f8e.js" rename to "assets/guide_\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263_\346\265\217\350\247\210\345\231\250\346\270\262\346\237\223\346\265\201\347\250\213.md.12bb6e51.js" index 06031caa..3a2b5277 100644 --- "a/assets/guide_\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263_\346\265\217\350\247\210\345\231\250\346\270\262\346\237\223\346\265\201\347\250\213.md.144e6f8e.js" +++ "b/assets/guide_\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263_\346\265\217\350\247\210\345\231\250\346\270\262\346\237\223\346\265\201\347\250\213.md.12bb6e51.js" @@ -1 +1 @@ -import{_ as l,o as i,c as e,Q as a}from"./chunks/framework.b6910bb2.js";const o="/vitePress-blob/assets/3.8bc85ddd.png",t="/vitePress-blob/assets/4.9caf6b36.png",s="/vitePress-blob/assets/5.bbea4579.jpg",m=JSON.parse('{"title":"浏览器渲染流程","description":"","frontmatter":{},"headers":[],"relativePath":"guide/浏览器相关/浏览器渲染流程.md","filePath":"guide/浏览器相关/浏览器渲染流程.md","lastUpdated":1718173557000}'),r={name:"guide/浏览器相关/浏览器渲染流程.md"},p=a('

浏览器渲染流程

浏览器渲染流程

  1. 发出请求到页面首次绘制

    • 第一阶段: 页面提交请求到服务器响应,这时候页面还是之前的页面
    • 第二阶段: 获取到响应数据提交到渲染进程,进行 HTML 解析、CSS 加载、JS 加载、JS 执行、CSSOM 解析、布局树生成、页面绘制
    • 第三阶段: 等首次加载完成后,页面一点点被渲染
  2. HTML 解析

  3. 生成 CSSOM 树

    CSS 不会阻塞 HTML 解析,但是会阻塞页面渲染,因为要生成渲染树

  4. 生成布局树

    去除不显示的节点,计算样式

  5. 分层和合成机制

    • 分层: 分层树在布局树之后,分层树的每一个节点都是图层,如没有,则和父节点同一个图层

    • 绘制阶段: 根据图层在绘制阶段生成绘制指令

    • 光栅化: 根据绘制指令,将每个图层都绘制成一张图片

    • 合成: 合成线程将多张图片合成一张图片,然后显示在屏幕上 (由合成线程完成,不影响主线程)

      • 优化操作1: 合成线程内会维护一个光栅化线程池,将绘制指令列表提交到 GPU 进行光栅化,生成位图,放在内存中
      • 优化操作2: 分块,合成线程将图层分块,优先渲染离屏幕最近的图块
      • 合成线程
  6. 页面显示

常见的问题

1 从输入 URL 到页面渲染完成,发生了什么?

  1. 浏览器会根据用户输入的内容判断是关键字还是URL
  2. 如果是关键字,会将其组成成带有搜索关键字的URL,通过IPC进程通信发送给网络进程
  3. 网络进程发起请求前,会判断是否命中强缓存,如命中直接返回存储资源
  4. 否则发起请求,根据 DNS 解析获取域名对应的 IP 地址,进行 TCP、HTTP 连接
  5. 服务端收到请求后,会判断是否命中协商缓存,如命中则返回304状态码
  6. 如返回的是301、302状态码,浏览器会根据响应头返回的location字段,进行重定向
  7. 如是正常返回资源类型,浏览器会根据 content-type 对资源做相对应的操作,如果是下载类型则进行下载,如果是html类型则会提交到渲染进程进行解析
  8. 解析 HTML,转换成浏览器能识别的 DOM 树
  9. 解析 CSS,转化成浏览器能识别的 CSS 样式树
  10. 根据 DOM 和 CSS 样式树,通过 布局计算生成 布局树
  11. 根据布局树上的分层属性(z-index),生成分层树
  12. 根据分层树,生成绘制指令列表
  13. 渲染主线程会将绘制指令列表提交给合成线程
  14. 合成线程会维护一个光栅化线程池,将绘制指令列表提交到 GPU 进行光栅化,生成位图,放在内存中
  15. 合成线程通信浏览器进程,浏览器进程将内存中的数据输出到显卡的后缓存区,在下一帧绘制之前,显卡的后缓冲区与前缓冲区对换,显示屏读取前缓冲区数据,显示到屏幕上

整体流程

2 回流和重绘有什么区别

回流:元素尺寸、定位改变,可能会影响到其他元素的位置

重绘:元素外观改变,如背景色、颜色,元素尺寸位置不改变且不影响其他元素

减少回流的方法:

  1. 集中修改
    • 修改样式,使用 class
    • 修改前将 DOM 改成 display: none,修改后再显示
    • 使用 DocumentFragment
    • resize、scroll 事件,使用防抖
  2. 使用 BFC
    • 隔离内部元素对外部元素的影响
  3. 脱离文档流
    • position: absolute、fixed
    • float
  4. 提升合成图层
    • CSS3 属性: will-change、transform: translate3d(0);
  5. 不是用 offsetHeight、getBoundingClientRect
    • 使用 intersectionObserver API - 判断元素是否在可视区域内

BFC: 块级格式化上下文 特点: BFC 内部元素不会影响到外部元素 形成条件:

  1. HTML 元素
  2. overflow: hidden、auto、scroll
  3. position: absolute、fixed
  4. float 元素
  5. display: inline-block、flex、inline-flex等

3 渲染流程图

渲染流程图

JS 会阻塞 HTML 的解析和渲染

CSS 不会阻塞 HTML 解析,但会阻塞 DOM 渲染,还会阻塞 JS 的执行

为什么 CSS 会阻塞 JS 的执行?

因为 JS 可能会操作 DOM 节点和 CSS 样式,因此浏览器为了获取到最新的 CSS 样式,样式表会在后面的 JS 执行前先加载执行完毕,所以 CSS 会阻塞 JS 的执行

',20),c=[p];function d(n,_,u,h,S,b){return i(),e("div",null,c)}const C=l(r,[["render",d]]);export{m as __pageData,C as default}; +import{_ as l,o as i,c as e,Q as a}from"./chunks/framework.b6910bb2.js";const o="/vitePress-blob/assets/3.8bc85ddd.png",t="/vitePress-blob/assets/4.9caf6b36.png",s="/vitePress-blob/assets/5.bbea4579.jpg",m=JSON.parse('{"title":"浏览器渲染流程","description":"","frontmatter":{},"headers":[],"relativePath":"guide/浏览器相关/浏览器渲染流程.md","filePath":"guide/浏览器相关/浏览器渲染流程.md","lastUpdated":1718174182000}'),r={name:"guide/浏览器相关/浏览器渲染流程.md"},p=a('

浏览器渲染流程

浏览器渲染流程

  1. 发出请求到页面首次绘制

    • 第一阶段: 页面提交请求到服务器响应,这时候页面还是之前的页面
    • 第二阶段: 获取到响应数据提交到渲染进程,进行 HTML 解析、CSS 加载、JS 加载、JS 执行、CSSOM 解析、布局树生成、页面绘制
    • 第三阶段: 等首次加载完成后,页面一点点被渲染
  2. HTML 解析

  3. 生成 CSSOM 树

    CSS 不会阻塞 HTML 解析,但是会阻塞页面渲染,因为要生成渲染树

  4. 生成布局树

    去除不显示的节点,计算样式

  5. 分层和合成机制

    • 分层: 分层树在布局树之后,分层树的每一个节点都是图层,如没有,则和父节点同一个图层

    • 绘制阶段: 根据图层在绘制阶段生成绘制指令

    • 光栅化: 根据绘制指令,将每个图层都绘制成一张图片

    • 合成: 合成线程将多张图片合成一张图片,然后显示在屏幕上 (由合成线程完成,不影响主线程)

      • 优化操作1: 合成线程内会维护一个光栅化线程池,将绘制指令列表提交到 GPU 进行光栅化,生成位图,放在内存中
      • 优化操作2: 分块,合成线程将图层分块,优先渲染离屏幕最近的图块
      • 合成线程
  6. 页面显示

常见的问题

1 从输入 URL 到页面渲染完成,发生了什么?

  1. 浏览器会根据用户输入的内容判断是关键字还是URL
  2. 如果是关键字,会将其组成成带有搜索关键字的URL,通过IPC进程通信发送给网络进程
  3. 网络进程发起请求前,会判断是否命中强缓存,如命中直接返回存储资源
  4. 否则发起请求,根据 DNS 解析获取域名对应的 IP 地址,进行 TCP、HTTP 连接
  5. 服务端收到请求后,会判断是否命中协商缓存,如命中则返回304状态码
  6. 如返回的是301、302状态码,浏览器会根据响应头返回的location字段,进行重定向
  7. 如是正常返回资源类型,浏览器会根据 content-type 对资源做相对应的操作,如果是下载类型则进行下载,如果是html类型则会提交到渲染进程进行解析
  8. 解析 HTML,转换成浏览器能识别的 DOM 树
  9. 解析 CSS,转化成浏览器能识别的 CSS 样式树
  10. 根据 DOM 和 CSS 样式树,通过 布局计算生成 布局树
  11. 根据布局树上的分层属性(z-index),生成分层树
  12. 根据分层树,生成绘制指令列表
  13. 渲染主线程会将绘制指令列表提交给合成线程
  14. 合成线程会维护一个光栅化线程池,将绘制指令列表提交到 GPU 进行光栅化,生成位图,放在内存中
  15. 合成线程通信浏览器进程,浏览器进程将内存中的数据输出到显卡的后缓存区,在下一帧绘制之前,显卡的后缓冲区与前缓冲区对换,显示屏读取前缓冲区数据,显示到屏幕上

整体流程

2 回流和重绘有什么区别

回流:元素尺寸、定位改变,可能会影响到其他元素的位置

重绘:元素外观改变,如背景色、颜色,元素尺寸位置不改变且不影响其他元素

减少回流的方法:

  1. 集中修改
    • 修改样式,使用 class
    • 修改前将 DOM 改成 display: none,修改后再显示
    • 使用 DocumentFragment
    • resize、scroll 事件,使用防抖
  2. 使用 BFC
    • 隔离内部元素对外部元素的影响
  3. 脱离文档流
    • position: absolute、fixed
    • float
  4. 提升合成图层
    • CSS3 属性: will-change、transform: translate3d(0);
  5. 不是用 offsetHeight、getBoundingClientRect
    • 使用 intersectionObserver API - 判断元素是否在可视区域内

BFC: 块级格式化上下文 特点: BFC 内部元素不会影响到外部元素 形成条件:

  1. HTML 元素
  2. overflow: hidden、auto、scroll
  3. position: absolute、fixed
  4. float 元素
  5. display: inline-block、flex、inline-flex等

3 渲染流程图

渲染流程图

JS 会阻塞 HTML 的解析和渲染

CSS 不会阻塞 HTML 解析,但会阻塞 DOM 渲染,还会阻塞 JS 的执行

为什么 CSS 会阻塞 JS 的执行?

因为 JS 可能会操作 DOM 节点和 CSS 样式,因此浏览器为了获取到最新的 CSS 样式,样式表会在后面的 JS 执行前先加载执行完毕,所以 CSS 会阻塞 JS 的执行

',20),c=[p];function d(n,_,u,h,S,b){return i(),e("div",null,c)}const C=l(r,[["render",d]]);export{m as __pageData,C as default}; diff --git "a/assets/guide_\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263_\346\265\217\350\247\210\345\231\250\346\270\262\346\237\223\346\265\201\347\250\213.md.144e6f8e.lean.js" "b/assets/guide_\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263_\346\265\217\350\247\210\345\231\250\346\270\262\346\237\223\346\265\201\347\250\213.md.12bb6e51.lean.js" similarity index 90% rename from "assets/guide_\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263_\346\265\217\350\247\210\345\231\250\346\270\262\346\237\223\346\265\201\347\250\213.md.144e6f8e.lean.js" rename to "assets/guide_\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263_\346\265\217\350\247\210\345\231\250\346\270\262\346\237\223\346\265\201\347\250\213.md.12bb6e51.lean.js" index 36ff470e..3782c290 100644 --- "a/assets/guide_\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263_\346\265\217\350\247\210\345\231\250\346\270\262\346\237\223\346\265\201\347\250\213.md.144e6f8e.lean.js" +++ "b/assets/guide_\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263_\346\265\217\350\247\210\345\231\250\346\270\262\346\237\223\346\265\201\347\250\213.md.12bb6e51.lean.js" @@ -1 +1 @@ -import{_ as l,o as i,c as e,Q as a}from"./chunks/framework.b6910bb2.js";const o="/vitePress-blob/assets/3.8bc85ddd.png",t="/vitePress-blob/assets/4.9caf6b36.png",s="/vitePress-blob/assets/5.bbea4579.jpg",m=JSON.parse('{"title":"浏览器渲染流程","description":"","frontmatter":{},"headers":[],"relativePath":"guide/浏览器相关/浏览器渲染流程.md","filePath":"guide/浏览器相关/浏览器渲染流程.md","lastUpdated":1718173557000}'),r={name:"guide/浏览器相关/浏览器渲染流程.md"},p=a("",20),c=[p];function d(n,_,u,h,S,b){return i(),e("div",null,c)}const C=l(r,[["render",d]]);export{m as __pageData,C as default}; +import{_ as l,o as i,c as e,Q as a}from"./chunks/framework.b6910bb2.js";const o="/vitePress-blob/assets/3.8bc85ddd.png",t="/vitePress-blob/assets/4.9caf6b36.png",s="/vitePress-blob/assets/5.bbea4579.jpg",m=JSON.parse('{"title":"浏览器渲染流程","description":"","frontmatter":{},"headers":[],"relativePath":"guide/浏览器相关/浏览器渲染流程.md","filePath":"guide/浏览器相关/浏览器渲染流程.md","lastUpdated":1718174182000}'),r={name:"guide/浏览器相关/浏览器渲染流程.md"},p=a("",20),c=[p];function d(n,_,u,h,S,b){return i(),e("div",null,c)}const C=l(r,[["render",d]]);export{m as __pageData,C as default}; diff --git "a/assets/guide_\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263_\346\265\217\350\247\210\345\231\250\347\274\223\345\255\230.md.6792cab4.js" "b/assets/guide_\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263_\346\265\217\350\247\210\345\231\250\347\274\223\345\255\230.md.763b5a0b.js" similarity index 99% rename from "assets/guide_\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263_\346\265\217\350\247\210\345\231\250\347\274\223\345\255\230.md.6792cab4.js" rename to "assets/guide_\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263_\346\265\217\350\247\210\345\231\250\347\274\223\345\255\230.md.763b5a0b.js" index cea4ba1e..f3dd656b 100644 --- "a/assets/guide_\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263_\346\265\217\350\247\210\345\231\250\347\274\223\345\255\230.md.6792cab4.js" +++ "b/assets/guide_\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263_\346\265\217\350\247\210\345\231\250\347\274\223\345\255\230.md.763b5a0b.js" @@ -1,4 +1,4 @@ -import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.b6910bb2.js";const F=JSON.parse('{"title":"浏览器缓存","description":"","frontmatter":{},"headers":[],"relativePath":"guide/浏览器相关/浏览器缓存.md","filePath":"guide/浏览器相关/浏览器缓存.md","lastUpdated":1718173557000}'),p={name:"guide/浏览器相关/浏览器缓存.md"},o=l(`

浏览器缓存

缓存

从 HTTP 缓存策略来说

  • 强缓存
  • 协商缓存

从浏览器的缓存位置来说

  • Service Worker Cache (必须是 Https)
  • Memory Cache (内存缓存)
  • Disk Cache (硬盘缓存)
  • Push Cache (Http2.0)

本地存储

请求时携带,用于信息持久化

Local Storage 本地存储

用于长期不变化的数据,只能存储字符串

Session Storage 会话存储

用于存储当前会话的数据,只能存储字符串

indexedDB

非关系型数据库

Service Worker

运行在浏览器背后的独立线程(必须 HTTPS 才能使用)

js
// main.js
+import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.b6910bb2.js";const F=JSON.parse('{"title":"浏览器缓存","description":"","frontmatter":{},"headers":[],"relativePath":"guide/浏览器相关/浏览器缓存.md","filePath":"guide/浏览器相关/浏览器缓存.md","lastUpdated":1718174182000}'),p={name:"guide/浏览器相关/浏览器缓存.md"},o=l(`

浏览器缓存

缓存

从 HTTP 缓存策略来说

  • 强缓存
  • 协商缓存

从浏览器的缓存位置来说

  • Service Worker Cache (必须是 Https)
  • Memory Cache (内存缓存)
  • Disk Cache (硬盘缓存)
  • Push Cache (Http2.0)

本地存储

请求时携带,用于信息持久化

Local Storage 本地存储

用于长期不变化的数据,只能存储字符串

Session Storage 会话存储

用于存储当前会话的数据,只能存储字符串

indexedDB

非关系型数据库

Service Worker

运行在浏览器背后的独立线程(必须 HTTPS 才能使用)

js
// main.js
 /* 判断当前浏览器是否支持serviceWorker */
 if ('serviceWorker' in navigator) {
   /* 当页面加载完成就创建一个 serviceWorker */
diff --git "a/assets/guide_\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263_\346\265\217\350\247\210\345\231\250\347\274\223\345\255\230.md.6792cab4.lean.js" "b/assets/guide_\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263_\346\265\217\350\247\210\345\231\250\347\274\223\345\255\230.md.763b5a0b.lean.js"
similarity index 87%
rename from "assets/guide_\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263_\346\265\217\350\247\210\345\231\250\347\274\223\345\255\230.md.6792cab4.lean.js"
rename to "assets/guide_\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263_\346\265\217\350\247\210\345\231\250\347\274\223\345\255\230.md.763b5a0b.lean.js"
index ddea1a42..809978ec 100644
--- "a/assets/guide_\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263_\346\265\217\350\247\210\345\231\250\347\274\223\345\255\230.md.6792cab4.lean.js"
+++ "b/assets/guide_\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263_\346\265\217\350\247\210\345\231\250\347\274\223\345\255\230.md.763b5a0b.lean.js"
@@ -1 +1 @@
-import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.b6910bb2.js";const F=JSON.parse('{"title":"浏览器缓存","description":"","frontmatter":{},"headers":[],"relativePath":"guide/浏览器相关/浏览器缓存.md","filePath":"guide/浏览器相关/浏览器缓存.md","lastUpdated":1718173557000}'),p={name:"guide/浏览器相关/浏览器缓存.md"},o=l("",19),e=[o];function c(t,r,E,y,i,h){return n(),a("div",null,e)}const u=s(p,[["render",c]]);export{F as __pageData,u as default};
+import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.b6910bb2.js";const F=JSON.parse('{"title":"浏览器缓存","description":"","frontmatter":{},"headers":[],"relativePath":"guide/浏览器相关/浏览器缓存.md","filePath":"guide/浏览器相关/浏览器缓存.md","lastUpdated":1718174182000}'),p={name:"guide/浏览器相关/浏览器缓存.md"},o=l("",19),e=[o];function c(t,r,E,y,i,h){return n(),a("div",null,e)}const u=s(p,[["render",c]]);export{F as __pageData,u as default};
diff --git "a/assets/guide_\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263_\346\265\217\350\247\210\345\231\250\350\277\233\347\250\213\346\236\266\346\236\204.md.3c2952bb.js" "b/assets/guide_\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263_\346\265\217\350\247\210\345\231\250\350\277\233\347\250\213\346\236\266\346\236\204.md.3ca88720.js"
similarity index 97%
rename from "assets/guide_\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263_\346\265\217\350\247\210\345\231\250\350\277\233\347\250\213\346\236\266\346\236\204.md.3c2952bb.js"
rename to "assets/guide_\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263_\346\265\217\350\247\210\345\231\250\350\277\233\347\250\213\346\236\266\346\236\204.md.3ca88720.js"
index 4016b847..eaa21aec 100644
--- "a/assets/guide_\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263_\346\265\217\350\247\210\345\231\250\350\277\233\347\250\213\346\236\266\346\236\204.md.3c2952bb.js"
+++ "b/assets/guide_\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263_\346\265\217\350\247\210\345\231\250\350\277\233\347\250\213\346\236\266\346\236\204.md.3ca88720.js"
@@ -1 +1 @@
-import{_ as a,o as e,c as t,Q as r}from"./chunks/framework.b6910bb2.js";const b=JSON.parse('{"title":"浏览器进程架构","description":"","frontmatter":{},"headers":[],"relativePath":"guide/浏览器相关/浏览器进程架构.md","filePath":"guide/浏览器相关/浏览器进程架构.md","lastUpdated":1718173557000}'),i={name:"guide/浏览器相关/浏览器进程架构.md"},l=r('

浏览器进程架构

进程与线程

进程

进程是一个程序的实例

进程是系统进行资源调度和分配的最小单位

进程之间相互独立,通过 IPC 进行通信

线程

线程是 CPU 调度的最小单位

线程之间共享进程的数据

线程里面会有协程,但只能运行一个

浏览器架构

1 浏览器主进程

用户交互、文件存储、页面显示、子进程管理

2 渲染进程

解析资源、执行 js

渲染进程被浏览器放在安全沙箱里面,因此渲染进程的资源是通过网络获取

  • 渲染线程: 渲染页面
  • JS 线程:解析执行 js
  • 事件触发线程: 事件循环
  • 定时器线程:定时器相关
  • 异步 http 请求线程: 请求相关

3 GPU 进程

UI界面的绘制

4 网络进程

网络资源加载

5 插件进程

管理插件

',23),o=[l];function h(d,n,s,_,c,p){return e(),t("div",null,o)}const q=a(i,[["render",h]]);export{b as __pageData,q as default}; +import{_ as a,o as e,c as t,Q as r}from"./chunks/framework.b6910bb2.js";const b=JSON.parse('{"title":"浏览器进程架构","description":"","frontmatter":{},"headers":[],"relativePath":"guide/浏览器相关/浏览器进程架构.md","filePath":"guide/浏览器相关/浏览器进程架构.md","lastUpdated":1718174182000}'),i={name:"guide/浏览器相关/浏览器进程架构.md"},l=r('

浏览器进程架构

进程与线程

进程

进程是一个程序的实例

进程是系统进行资源调度和分配的最小单位

进程之间相互独立,通过 IPC 进行通信

线程

线程是 CPU 调度的最小单位

线程之间共享进程的数据

线程里面会有协程,但只能运行一个

浏览器架构

1 浏览器主进程

用户交互、文件存储、页面显示、子进程管理

2 渲染进程

解析资源、执行 js

渲染进程被浏览器放在安全沙箱里面,因此渲染进程的资源是通过网络获取

  • 渲染线程: 渲染页面
  • JS 线程:解析执行 js
  • 事件触发线程: 事件循环
  • 定时器线程:定时器相关
  • 异步 http 请求线程: 请求相关

3 GPU 进程

UI界面的绘制

4 网络进程

网络资源加载

5 插件进程

管理插件

',23),o=[l];function h(d,n,s,_,c,p){return e(),t("div",null,o)}const q=a(i,[["render",h]]);export{b as __pageData,q as default}; diff --git "a/assets/guide_\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263_\346\265\217\350\247\210\345\231\250\350\277\233\347\250\213\346\236\266\346\236\204.md.3c2952bb.lean.js" "b/assets/guide_\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263_\346\265\217\350\247\210\345\231\250\350\277\233\347\250\213\346\236\266\346\236\204.md.3ca88720.lean.js" similarity index 87% rename from "assets/guide_\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263_\346\265\217\350\247\210\345\231\250\350\277\233\347\250\213\346\236\266\346\236\204.md.3c2952bb.lean.js" rename to "assets/guide_\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263_\346\265\217\350\247\210\345\231\250\350\277\233\347\250\213\346\236\266\346\236\204.md.3ca88720.lean.js" index d34f6829..43ca10ab 100644 --- "a/assets/guide_\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263_\346\265\217\350\247\210\345\231\250\350\277\233\347\250\213\346\236\266\346\236\204.md.3c2952bb.lean.js" +++ "b/assets/guide_\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263_\346\265\217\350\247\210\345\231\250\350\277\233\347\250\213\346\236\266\346\236\204.md.3ca88720.lean.js" @@ -1 +1 @@ -import{_ as a,o as e,c as t,Q as r}from"./chunks/framework.b6910bb2.js";const b=JSON.parse('{"title":"浏览器进程架构","description":"","frontmatter":{},"headers":[],"relativePath":"guide/浏览器相关/浏览器进程架构.md","filePath":"guide/浏览器相关/浏览器进程架构.md","lastUpdated":1718173557000}'),i={name:"guide/浏览器相关/浏览器进程架构.md"},l=r("",23),o=[l];function h(d,n,s,_,c,p){return e(),t("div",null,o)}const q=a(i,[["render",h]]);export{b as __pageData,q as default}; +import{_ as a,o as e,c as t,Q as r}from"./chunks/framework.b6910bb2.js";const b=JSON.parse('{"title":"浏览器进程架构","description":"","frontmatter":{},"headers":[],"relativePath":"guide/浏览器相关/浏览器进程架构.md","filePath":"guide/浏览器相关/浏览器进程架构.md","lastUpdated":1718174182000}'),i={name:"guide/浏览器相关/浏览器进程架构.md"},l=r("",23),o=[l];function h(d,n,s,_,c,p){return e(),t("div",null,o)}const q=a(i,[["render",h]]);export{b as __pageData,q as default}; diff --git "a/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_CDN.md.17c0b1ee.js" "b/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_CDN.md.2fee8126.js" similarity index 98% rename from "assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_CDN.md.17c0b1ee.js" rename to "assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_CDN.md.2fee8126.js" index 0f35a141..2d46e0f2 100644 --- "a/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_CDN.md.17c0b1ee.js" +++ "b/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_CDN.md.2fee8126.js" @@ -1 +1 @@ -import{_ as l,o as a,c as i,Q as e}from"./chunks/framework.b6910bb2.js";const t="/vitePress-blob/assets/13.1322b23d.jpg",C=JSON.parse('{"title":"CDN","description":"","frontmatter":{},"headers":[],"relativePath":"guide/网络相关/CDN.md","filePath":"guide/网络相关/CDN.md","lastUpdated":1718173557000}'),o={name:"guide/网络相关/CDN.md"},r=e('

CDN

定义

内容分发网络,利用最靠近用户的服务器,将资源更快更可靠的给到用户

组成

  1. 分发服务系统

    最小单位是 Cache 设备

    • 响应用户请求
    • 与源站点进行资源同步
  2. 负载均衡系统

    负责对用户的请求进行调度

  3. 运营管理系统

    负责业务层面与外界系统的交互所需要的收集、整理、交付等工作 (为了做闭环)

    运营管理子系统 网络管理子系统

作用

托管 web 资源,加速 web 资源的获取速度

性能方面

  1. 用户从最近的 CDN 站点获取资源,访问速度更快
  2. 突破 TCP 只有同域名下只有 6 个的限制
  3. 减少源服务器的负担

安全方面

  1. 针对 DDos: 通过监控分析异常流量,限制请求频率
  2. 针对 MITM: 从源服务器到 CDN 节点到 ISP (Internet Service Provider, 网络运营提供商),全链路 HTTPS 通信

工作原理

没有使用 CDN 过程

  1. 浏览器通过 DNS 对域名进行解析,得到此域名对应的 IP 地址
  2. 浏览器根据得到的 IP 地址,向域名的服务主机发送数据请求
  3. 服务器向浏览器返回响应数据

使用了 CDN 过程

  1. 获取负载均衡服务器 IP 地址 (自底向上)

      1. 数据的 URL 先进行 DNS 系统解析,发现该 URL 对应的是一个 CDN 专用的 DNS 服务器,DNS 系统就会将域名解析权交给 CNAME 指向的 CDN 专用的 DNS 服务器
      1. CDN 专用的 DNS 服务器将 CDN 全局负载均衡设备 IP 地址返回给用户
      1. 用户向 CDN 的全局负载均衡设备发起数据请求
  2. 获取目标缓存服务器 IP 地址 (自顶向下)

      1. CDN 全局负载均衡设备根据用户 IP 地址以及用户请求的 URL,选择一台用户所属区域的负载均衡设备
      1. 区域负责均衡设备选择一台适合的缓存服务器来提供服务,将该缓存服务器的 IP 地址返回给全局负载均衡设备
      1. 全局负载均衡设备把服务器 IP 地址返回给用户
  3. 用户发起请求获取

    • 用户向该缓存服务器发起请求,缓存服务器响应用户的请求,将用户所需内容发送支用户终端 (如果缓存服务器没有用户想要的内容,那么缓存服务器会穿透 CDN 集群往源服务器获取设备)

流程

使用场景

  1. 使用第三方 CDN 服务 (例如开源框架可以使用第三方 CDN 服务,如 React、Vue、JQuery)
  2. 使用 CDN 进行静态资源的缓存 (将网站的资源放在 CDN 上)
  3. 直播传送 (直播本质也是使用流媒体进行传送,CDN 也支持流媒体传送,所以直播完全可以使用 CDN 来提高访问速度)
',19),h=[r];function n(d,s,c,p,u,D){return a(),i("div",null,h)}const _=l(o,[["render",n]]);export{C as __pageData,_ as default}; +import{_ as l,o as a,c as i,Q as e}from"./chunks/framework.b6910bb2.js";const t="/vitePress-blob/assets/13.1322b23d.jpg",C=JSON.parse('{"title":"CDN","description":"","frontmatter":{},"headers":[],"relativePath":"guide/网络相关/CDN.md","filePath":"guide/网络相关/CDN.md","lastUpdated":1718174182000}'),o={name:"guide/网络相关/CDN.md"},r=e('

CDN

定义

内容分发网络,利用最靠近用户的服务器,将资源更快更可靠的给到用户

组成

  1. 分发服务系统

    最小单位是 Cache 设备

    • 响应用户请求
    • 与源站点进行资源同步
  2. 负载均衡系统

    负责对用户的请求进行调度

  3. 运营管理系统

    负责业务层面与外界系统的交互所需要的收集、整理、交付等工作 (为了做闭环)

    运营管理子系统 网络管理子系统

作用

托管 web 资源,加速 web 资源的获取速度

性能方面

  1. 用户从最近的 CDN 站点获取资源,访问速度更快
  2. 突破 TCP 只有同域名下只有 6 个的限制
  3. 减少源服务器的负担

安全方面

  1. 针对 DDos: 通过监控分析异常流量,限制请求频率
  2. 针对 MITM: 从源服务器到 CDN 节点到 ISP (Internet Service Provider, 网络运营提供商),全链路 HTTPS 通信

工作原理

没有使用 CDN 过程

  1. 浏览器通过 DNS 对域名进行解析,得到此域名对应的 IP 地址
  2. 浏览器根据得到的 IP 地址,向域名的服务主机发送数据请求
  3. 服务器向浏览器返回响应数据

使用了 CDN 过程

  1. 获取负载均衡服务器 IP 地址 (自底向上)

      1. 数据的 URL 先进行 DNS 系统解析,发现该 URL 对应的是一个 CDN 专用的 DNS 服务器,DNS 系统就会将域名解析权交给 CNAME 指向的 CDN 专用的 DNS 服务器
      1. CDN 专用的 DNS 服务器将 CDN 全局负载均衡设备 IP 地址返回给用户
      1. 用户向 CDN 的全局负载均衡设备发起数据请求
  2. 获取目标缓存服务器 IP 地址 (自顶向下)

      1. CDN 全局负载均衡设备根据用户 IP 地址以及用户请求的 URL,选择一台用户所属区域的负载均衡设备
      1. 区域负责均衡设备选择一台适合的缓存服务器来提供服务,将该缓存服务器的 IP 地址返回给全局负载均衡设备
      1. 全局负载均衡设备把服务器 IP 地址返回给用户
  3. 用户发起请求获取

    • 用户向该缓存服务器发起请求,缓存服务器响应用户的请求,将用户所需内容发送支用户终端 (如果缓存服务器没有用户想要的内容,那么缓存服务器会穿透 CDN 集群往源服务器获取设备)

流程

使用场景

  1. 使用第三方 CDN 服务 (例如开源框架可以使用第三方 CDN 服务,如 React、Vue、JQuery)
  2. 使用 CDN 进行静态资源的缓存 (将网站的资源放在 CDN 上)
  3. 直播传送 (直播本质也是使用流媒体进行传送,CDN 也支持流媒体传送,所以直播完全可以使用 CDN 来提高访问速度)
',19),h=[r];function n(d,s,c,p,u,D){return a(),i("div",null,h)}const _=l(o,[["render",n]]);export{C as __pageData,_ as default}; diff --git "a/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_CDN.md.17c0b1ee.lean.js" "b/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_CDN.md.2fee8126.lean.js" similarity index 86% rename from "assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_CDN.md.17c0b1ee.lean.js" rename to "assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_CDN.md.2fee8126.lean.js" index 1da83f64..f5642b43 100644 --- "a/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_CDN.md.17c0b1ee.lean.js" +++ "b/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_CDN.md.2fee8126.lean.js" @@ -1 +1 @@ -import{_ as l,o as a,c as i,Q as e}from"./chunks/framework.b6910bb2.js";const t="/vitePress-blob/assets/13.1322b23d.jpg",C=JSON.parse('{"title":"CDN","description":"","frontmatter":{},"headers":[],"relativePath":"guide/网络相关/CDN.md","filePath":"guide/网络相关/CDN.md","lastUpdated":1718173557000}'),o={name:"guide/网络相关/CDN.md"},r=e("",19),h=[r];function n(d,s,c,p,u,D){return a(),i("div",null,h)}const _=l(o,[["render",n]]);export{C as __pageData,_ as default}; +import{_ as l,o as a,c as i,Q as e}from"./chunks/framework.b6910bb2.js";const t="/vitePress-blob/assets/13.1322b23d.jpg",C=JSON.parse('{"title":"CDN","description":"","frontmatter":{},"headers":[],"relativePath":"guide/网络相关/CDN.md","filePath":"guide/网络相关/CDN.md","lastUpdated":1718174182000}'),o={name:"guide/网络相关/CDN.md"},r=e("",19),h=[r];function n(d,s,c,p,u,D){return a(),i("div",null,h)}const _=l(o,[["render",n]]);export{C as __pageData,_ as default}; diff --git "a/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_DNS.md.a848b96e.js" "b/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_DNS.md.2f99cb22.js" similarity index 96% rename from "assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_DNS.md.a848b96e.js" rename to "assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_DNS.md.2f99cb22.js" index 42bb69e7..58f2e44e 100644 --- "a/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_DNS.md.a848b96e.js" +++ "b/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_DNS.md.2f99cb22.js" @@ -1 +1 @@ -import{_ as l,o as i,c as a,Q as e}from"./chunks/framework.b6910bb2.js";const S=JSON.parse('{"title":"DNS","description":"","frontmatter":{},"headers":[],"relativePath":"guide/网络相关/DNS.md","filePath":"guide/网络相关/DNS.md","lastUpdated":1718173557000}'),o={name:"guide/网络相关/DNS.md"},t=e('

DNS

定义

域名解析系统

工作原理 (自下而上)

例如查找 www.baidu.com 的 ip 地址

  1. 查找缓存
      1. 检查浏览器缓存
      1. 检查操作系统缓存 (常见的有 host 文件)
      1. 检查路由器缓存
  2. 如何缓存查找到,会向 ISP (网络服务提供商) 的本地 DNS 服务器查询
  3. 如果本地 DNS 服务器没有找到,会向根域名服务器请求解析,分为以下几步:(自顶向下)
      1. 根服务器返回顶级域名服务器(如.com、.cn、.org等)地址,例如该例子中的 .com 的地址
      1. 接着向顶级瑜域名服务器发送请求,然后会返回次级域名服务器的地址,例如该例子会返回 .baidu 的地址
      1. 接着向次级域名服务器发送请求,会返回通过三级域名地址的 IP,例如本例子返回的 www.baidu.com 的地址
    • 4.Local DNS Server会缓存结果,并返回给用户,缓存在系统中
',6),r=[t];function s(d,c,n,_,h,u){return i(),a("div",null,r)}const m=l(o,[["render",s]]);export{S as __pageData,m as default}; +import{_ as l,o as i,c as a,Q as e}from"./chunks/framework.b6910bb2.js";const S=JSON.parse('{"title":"DNS","description":"","frontmatter":{},"headers":[],"relativePath":"guide/网络相关/DNS.md","filePath":"guide/网络相关/DNS.md","lastUpdated":1718174182000}'),o={name:"guide/网络相关/DNS.md"},t=e('

DNS

定义

域名解析系统

工作原理 (自下而上)

例如查找 www.baidu.com 的 ip 地址

  1. 查找缓存
      1. 检查浏览器缓存
      1. 检查操作系统缓存 (常见的有 host 文件)
      1. 检查路由器缓存
  2. 如何缓存查找到,会向 ISP (网络服务提供商) 的本地 DNS 服务器查询
  3. 如果本地 DNS 服务器没有找到,会向根域名服务器请求解析,分为以下几步:(自顶向下)
      1. 根服务器返回顶级域名服务器(如.com、.cn、.org等)地址,例如该例子中的 .com 的地址
      1. 接着向顶级瑜域名服务器发送请求,然后会返回次级域名服务器的地址,例如该例子会返回 .baidu 的地址
      1. 接着向次级域名服务器发送请求,会返回通过三级域名地址的 IP,例如本例子返回的 www.baidu.com 的地址
    • 4.Local DNS Server会缓存结果,并返回给用户,缓存在系统中
',6),r=[t];function s(d,c,n,_,h,u){return i(),a("div",null,r)}const m=l(o,[["render",s]]);export{S as __pageData,m as default}; diff --git "a/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_DNS.md.a848b96e.lean.js" "b/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_DNS.md.2f99cb22.lean.js" similarity index 85% rename from "assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_DNS.md.a848b96e.lean.js" rename to "assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_DNS.md.2f99cb22.lean.js" index 96036613..28414ddc 100644 --- "a/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_DNS.md.a848b96e.lean.js" +++ "b/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_DNS.md.2f99cb22.lean.js" @@ -1 +1 @@ -import{_ as l,o as i,c as a,Q as e}from"./chunks/framework.b6910bb2.js";const S=JSON.parse('{"title":"DNS","description":"","frontmatter":{},"headers":[],"relativePath":"guide/网络相关/DNS.md","filePath":"guide/网络相关/DNS.md","lastUpdated":1718173557000}'),o={name:"guide/网络相关/DNS.md"},t=e("",6),r=[t];function s(d,c,n,_,h,u){return i(),a("div",null,r)}const m=l(o,[["render",s]]);export{S as __pageData,m as default}; +import{_ as l,o as i,c as a,Q as e}from"./chunks/framework.b6910bb2.js";const S=JSON.parse('{"title":"DNS","description":"","frontmatter":{},"headers":[],"relativePath":"guide/网络相关/DNS.md","filePath":"guide/网络相关/DNS.md","lastUpdated":1718174182000}'),o={name:"guide/网络相关/DNS.md"},t=e("",6),r=[t];function s(d,c,n,_,h,u){return i(),a("div",null,r)}const m=l(o,[["render",s]]);export{S as __pageData,m as default}; diff --git "a/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_GET\350\257\267\346\261\202\345\222\214POST\350\257\267\346\261\202\347\232\204\345\214\272\345\210\253.md.7fb12d4a.js" "b/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_GET\350\257\267\346\261\202\345\222\214POST\350\257\267\346\261\202\347\232\204\345\214\272\345\210\253.md.f8c99ea3.js" similarity index 95% rename from "assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_GET\350\257\267\346\261\202\345\222\214POST\350\257\267\346\261\202\347\232\204\345\214\272\345\210\253.md.7fb12d4a.js" rename to "assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_GET\350\257\267\346\261\202\345\222\214POST\350\257\267\346\261\202\347\232\204\345\214\272\345\210\253.md.f8c99ea3.js" index a98f969d..64d4530b 100644 --- "a/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_GET\350\257\267\346\261\202\345\222\214POST\350\257\267\346\261\202\347\232\204\345\214\272\345\210\253.md.7fb12d4a.js" +++ "b/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_GET\350\257\267\346\261\202\345\222\214POST\350\257\267\346\261\202\347\232\204\345\214\272\345\210\253.md.f8c99ea3.js" @@ -1 +1 @@ -import{_ as t,o as a,c as l,k as e,a as o}from"./chunks/framework.b6910bb2.js";const O=JSON.parse('{"title":"GET 请求和 POST 请求的区别","description":"","frontmatter":{},"headers":[],"relativePath":"guide/网络相关/GET请求和POST请求的区别.md","filePath":"guide/网络相关/GET请求和POST请求的区别.md","lastUpdated":1718173557000}'),s={name:"guide/网络相关/GET请求和POST请求的区别.md"},n=e("h1",{id:"get-请求和-post-请求的区别",tabindex:"-1"},[o("GET 请求和 POST 请求的区别 "),e("a",{class:"header-anchor",href:"#get-请求和-post-请求的区别","aria-label":'Permalink to "GET 请求和 POST 请求的区别"'},"​")],-1),i=e("ol",null,[e("li",null,"功能上: GET 请求常用于获取数据,POST 请求常用于提交数据"),e("li",null,"参数上: GET 请求参数放在 URL 上,POST 请求参数放在请求体上"),e("li",null,"参数类型上: POST 请求支持更多的参数类型"),e("li",null,"安全性上: POST 请求更加安全"),e("li",null,"是否有缓存上: GET 请求会被缓存"),e("li",null,"请求长度上: 由于浏览器存在 URL 长度限制,因此会影响 GET 请求的长度")],-1),r=[n,i];function _(d,T,c,u,p,P){return a(),l("div",null,r)}const S=t(s,[["render",_]]);export{O as __pageData,S as default}; +import{_ as t,o as a,c as l,k as e,a as o}from"./chunks/framework.b6910bb2.js";const O=JSON.parse('{"title":"GET 请求和 POST 请求的区别","description":"","frontmatter":{},"headers":[],"relativePath":"guide/网络相关/GET请求和POST请求的区别.md","filePath":"guide/网络相关/GET请求和POST请求的区别.md","lastUpdated":1718174182000}'),s={name:"guide/网络相关/GET请求和POST请求的区别.md"},n=e("h1",{id:"get-请求和-post-请求的区别",tabindex:"-1"},[o("GET 请求和 POST 请求的区别 "),e("a",{class:"header-anchor",href:"#get-请求和-post-请求的区别","aria-label":'Permalink to "GET 请求和 POST 请求的区别"'},"​")],-1),i=e("ol",null,[e("li",null,"功能上: GET 请求常用于获取数据,POST 请求常用于提交数据"),e("li",null,"参数上: GET 请求参数放在 URL 上,POST 请求参数放在请求体上"),e("li",null,"参数类型上: POST 请求支持更多的参数类型"),e("li",null,"安全性上: POST 请求更加安全"),e("li",null,"是否有缓存上: GET 请求会被缓存"),e("li",null,"请求长度上: 由于浏览器存在 URL 长度限制,因此会影响 GET 请求的长度")],-1),r=[n,i];function _(d,T,c,u,p,P){return a(),l("div",null,r)}const S=t(s,[["render",_]]);export{O as __pageData,S as default}; diff --git "a/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_GET\350\257\267\346\261\202\345\222\214POST\350\257\267\346\261\202\347\232\204\345\214\272\345\210\253.md.7fb12d4a.lean.js" "b/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_GET\350\257\267\346\261\202\345\222\214POST\350\257\267\346\261\202\347\232\204\345\214\272\345\210\253.md.f8c99ea3.lean.js" similarity index 95% rename from "assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_GET\350\257\267\346\261\202\345\222\214POST\350\257\267\346\261\202\347\232\204\345\214\272\345\210\253.md.7fb12d4a.lean.js" rename to "assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_GET\350\257\267\346\261\202\345\222\214POST\350\257\267\346\261\202\347\232\204\345\214\272\345\210\253.md.f8c99ea3.lean.js" index a98f969d..64d4530b 100644 --- "a/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_GET\350\257\267\346\261\202\345\222\214POST\350\257\267\346\261\202\347\232\204\345\214\272\345\210\253.md.7fb12d4a.lean.js" +++ "b/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_GET\350\257\267\346\261\202\345\222\214POST\350\257\267\346\261\202\347\232\204\345\214\272\345\210\253.md.f8c99ea3.lean.js" @@ -1 +1 @@ -import{_ as t,o as a,c as l,k as e,a as o}from"./chunks/framework.b6910bb2.js";const O=JSON.parse('{"title":"GET 请求和 POST 请求的区别","description":"","frontmatter":{},"headers":[],"relativePath":"guide/网络相关/GET请求和POST请求的区别.md","filePath":"guide/网络相关/GET请求和POST请求的区别.md","lastUpdated":1718173557000}'),s={name:"guide/网络相关/GET请求和POST请求的区别.md"},n=e("h1",{id:"get-请求和-post-请求的区别",tabindex:"-1"},[o("GET 请求和 POST 请求的区别 "),e("a",{class:"header-anchor",href:"#get-请求和-post-请求的区别","aria-label":'Permalink to "GET 请求和 POST 请求的区别"'},"​")],-1),i=e("ol",null,[e("li",null,"功能上: GET 请求常用于获取数据,POST 请求常用于提交数据"),e("li",null,"参数上: GET 请求参数放在 URL 上,POST 请求参数放在请求体上"),e("li",null,"参数类型上: POST 请求支持更多的参数类型"),e("li",null,"安全性上: POST 请求更加安全"),e("li",null,"是否有缓存上: GET 请求会被缓存"),e("li",null,"请求长度上: 由于浏览器存在 URL 长度限制,因此会影响 GET 请求的长度")],-1),r=[n,i];function _(d,T,c,u,p,P){return a(),l("div",null,r)}const S=t(s,[["render",_]]);export{O as __pageData,S as default}; +import{_ as t,o as a,c as l,k as e,a as o}from"./chunks/framework.b6910bb2.js";const O=JSON.parse('{"title":"GET 请求和 POST 请求的区别","description":"","frontmatter":{},"headers":[],"relativePath":"guide/网络相关/GET请求和POST请求的区别.md","filePath":"guide/网络相关/GET请求和POST请求的区别.md","lastUpdated":1718174182000}'),s={name:"guide/网络相关/GET请求和POST请求的区别.md"},n=e("h1",{id:"get-请求和-post-请求的区别",tabindex:"-1"},[o("GET 请求和 POST 请求的区别 "),e("a",{class:"header-anchor",href:"#get-请求和-post-请求的区别","aria-label":'Permalink to "GET 请求和 POST 请求的区别"'},"​")],-1),i=e("ol",null,[e("li",null,"功能上: GET 请求常用于获取数据,POST 请求常用于提交数据"),e("li",null,"参数上: GET 请求参数放在 URL 上,POST 请求参数放在请求体上"),e("li",null,"参数类型上: POST 请求支持更多的参数类型"),e("li",null,"安全性上: POST 请求更加安全"),e("li",null,"是否有缓存上: GET 请求会被缓存"),e("li",null,"请求长度上: 由于浏览器存在 URL 长度限制,因此会影响 GET 请求的长度")],-1),r=[n,i];function _(d,T,c,u,p,P){return a(),l("div",null,r)}const S=t(s,[["render",_]]);export{O as __pageData,S as default}; diff --git "a/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_HTTP.md.272df02e.js" "b/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_HTTP.md.0eca7c23.js" similarity index 99% rename from "assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_HTTP.md.272df02e.js" rename to "assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_HTTP.md.0eca7c23.js" index 989ed87e..ab6f2ace 100644 --- "a/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_HTTP.md.272df02e.js" +++ "b/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_HTTP.md.0eca7c23.js" @@ -1 +1 @@ -import{_ as a,o as t,c as e,Q as l}from"./chunks/framework.b6910bb2.js";const i="/vitePress-blob/assets/5.c8205ece.jpg",o="/vitePress-blob/assets/6.76a1cb50.jpg",r="/vitePress-blob/assets/7.ee9188c9.jpg",H=JSON.parse('{"title":"HTTP","description":"","frontmatter":{},"headers":[],"relativePath":"guide/网络相关/HTTP.md","filePath":"guide/网络相关/HTTP.md","lastUpdated":1718173557000}'),h={name:"guide/网络相关/HTTP.md"},T=l('

HTTP

HTTP 0.9

早期做学术研究使用,只是单纯的文本传输(只有请求行、没有请求头和请求体)

HTTP1.0

支持图片、视频传输,但传输效率太低

核心需求:支持多种类型的文件下载(引入了请求头和响应头)

HTTP1.1

持久连接 keep-alive

在此之前一个 HTTP 请求需要建立一个 TCP 连接

目前浏览器中对于 同一个域名,默认允许同时建立 6 个 TCP 连接

管道化连接

将串行请求改成并行请求

支持虚拟主机

HTTP 根据 Host 去区分同一 IP 物理机子上的不同虚拟主机

对动态生成的内容提供完美支持

Chunk transfer 机制

Cookie、完全机制

主要问题

    1. HTTP/1.1 对头阻塞问题 在 HTTP 中,因为前一条请求因某些原因没有及时返回,会导致后面的请求无法发起,容易导致对头阻塞(串行)。虽然 HTTP1.1 引入了管道化技术尝试解决队头阻塞问题,但服务端还是需要按顺序处理请求并返回,因此阻塞问题依然存在
    1. 带宽利用率不理想
    • 原因:
      • TCP 的慢启动: 传输数据的速度从慢到快
      • 同时开启多个 TCP 连接,那么这些连接会竞争固定的带宽(带宽不足时,TCP 传输速度会变慢)

HTTP/1.0 与 HTTP/1.1 的 区别?

1 连接方面

持久化连接: HTTP1.1 支持持久化连接,减少每次 HTTP 请求都需要建立 TCP 连接的耗时

管道化连接:提高请求效率

2 缓存方面

HTTP1.1 新增了协商缓存的字段 ETag 比 if-None-Match 更加紧准

3 新增 Host 字段

根据 Host 区分同一 IP 服务器上的不同网站

之前只能通过 IP 区分网站

4 请求资源方面

添加范围请求 (206 状态码)

5 新增了请求方法

PUT、HEAD、OPTIONS 等

HTTP/2.0

一个域名只有一个 TCP 长连接传输数据 (避规 HTTP 1.1 的 TCP 慢启动和多个 TCP 连接时竞争带宽资源)

多路复用机制

通过引入二进制分帧层,实现多路复用机制

整体流程整体流程

  1. 浏览器发起请求,经过二进制分帧层将请求拆分成一个个带请求id的帧,发送给服务端
  2. 服务端收到这些帧后,根据请求id组装成完整请求信息,服务端处理完请求后,将响应请求发送到二进制分帧层,经过二进制分帧层转化为一个个带有响应id的帧发送给浏览器
  3. 浏览器收到这些帧后,会组合成一个完整的响应请求

实现基础: HTTP2 是一个二进制协议,在 HTTP/1.1 版中,报文的头信息必须是文本(ASCII 编码),数据体可以是文本,也可以是二进制。HTTP/2 则是一个彻底的二进制协议,头信息和数据体都是二进制,并且统称为"帧",可以分为头信息帧和数据帧。 帧的概念是它实现多路复用的基础

头部压缩

HTTP/2 实现了头信息压缩,由于 HTTP 1.1 协议不带状态,每次请求都必须附上所有信息。所以,请求的很多字段都是重复的,比如 Cookie 和 User Agent ,一模一样的内容,每次请求都必须附带,这会浪费很多带宽,也影响速度。HTTP/2 对这一点做了优化,引入了头信息压缩机制。一方面,头信息使用 gzip 或 compress 压缩后再发送;另一方面,客户端和服务器同时维护一张头信息表,所有字段都会存入这个表,生成一个索引号,以后就不发送同样字段了,只发送索引号,这样就能提高速度了。

设置请求优先级

服务器推送

存在的问题

TCP 协议本身存在的问题:

    1. TCP 的队头阻塞 TCP 传输过程中把一份数据分成多个数据包进行传输,当某个数据包没有按顺序返回,接收端会一直保持连接等待数据包返回,这就阻塞了后续数据包的传输 整体流程
    1. TCP 建立连接需要耗时

优点

多路复用技术能有效利用带宽(只有一个TCP连接),缓解 TCP 慢启动带来的问题,解决了 HTTP 队头阻塞问题,同时还支持设置优先级、服务器推送、头部压缩极大的提高了 HTTP 的传输效率

http2 与 http1 的区别?

  1. 为了解决 HTTP1.1 的队头阻塞问题引入了二进制分帧层
  2. 只建立一个 TCP 连接,解决 HTTP1.1中 TCP 慢启动以及多个 TCP 之间相互竞争带宽问题
  3. 头部压缩,HTTP2 请求头部采用头部压缩,减少数据内容的大小,提高效率
  4. 服务端推送: 服务端可以向客户端推送资源

HTTP3.0

采用UDP + QUIC协议

  1. UDP 可以减少连接耗费的 RTT,加快数据传输
  2. 使用 QUIC 协议,可以使用多路复用、TLS、可靠性传输等 TCP 协议的特点

存在的问题:

  1. 规范的制定和落地有着较大的差异(比如官方的QUIC和谷歌的QUIC协议有较大差异)
  2. 是对底层协议的改造,落地成本高。

HTTP1.0/1.1/2.0有什么区别?

这道题应该从HTTP的发展历史的角度出发

  1. http1.0 在 http0.9 时代新增了图片、视频的传输,同时新增了请求、响应头,支持文件下载,但请求的效率低,因为每个http请求需要一次TCP连接
  2. HTTP1.1 引入了缓存策略、支持长连接keep-alive等,支持PUT/DELETE/OPTION方法,提高了HTTP的传输效率,但并发请求时会有一个HTTP的头部阻塞问题
  3. HTTP2 通过引入二进制分帧层、采用多路复用避规了HTTP的头部阻塞问题,还支持头部压缩,提高HTTP的传输效率,服务端推送

RTT

浏览器发送数据包到服务器 + 浏览器接收到服务器确认接收的数据包的往返时间,成为RTT

',60),s=[T];function P(n,p,d,c,u,b){return t(),e("div",null,s)}const m=a(h,[["render",P]]);export{H as __pageData,m as default}; +import{_ as a,o as t,c as e,Q as l}from"./chunks/framework.b6910bb2.js";const i="/vitePress-blob/assets/5.c8205ece.jpg",o="/vitePress-blob/assets/6.76a1cb50.jpg",r="/vitePress-blob/assets/7.ee9188c9.jpg",H=JSON.parse('{"title":"HTTP","description":"","frontmatter":{},"headers":[],"relativePath":"guide/网络相关/HTTP.md","filePath":"guide/网络相关/HTTP.md","lastUpdated":1718174182000}'),h={name:"guide/网络相关/HTTP.md"},T=l('

HTTP

HTTP 0.9

早期做学术研究使用,只是单纯的文本传输(只有请求行、没有请求头和请求体)

HTTP1.0

支持图片、视频传输,但传输效率太低

核心需求:支持多种类型的文件下载(引入了请求头和响应头)

HTTP1.1

持久连接 keep-alive

在此之前一个 HTTP 请求需要建立一个 TCP 连接

目前浏览器中对于 同一个域名,默认允许同时建立 6 个 TCP 连接

管道化连接

将串行请求改成并行请求

支持虚拟主机

HTTP 根据 Host 去区分同一 IP 物理机子上的不同虚拟主机

对动态生成的内容提供完美支持

Chunk transfer 机制

Cookie、完全机制

主要问题

    1. HTTP/1.1 对头阻塞问题 在 HTTP 中,因为前一条请求因某些原因没有及时返回,会导致后面的请求无法发起,容易导致对头阻塞(串行)。虽然 HTTP1.1 引入了管道化技术尝试解决队头阻塞问题,但服务端还是需要按顺序处理请求并返回,因此阻塞问题依然存在
    1. 带宽利用率不理想
    • 原因:
      • TCP 的慢启动: 传输数据的速度从慢到快
      • 同时开启多个 TCP 连接,那么这些连接会竞争固定的带宽(带宽不足时,TCP 传输速度会变慢)

HTTP/1.0 与 HTTP/1.1 的 区别?

1 连接方面

持久化连接: HTTP1.1 支持持久化连接,减少每次 HTTP 请求都需要建立 TCP 连接的耗时

管道化连接:提高请求效率

2 缓存方面

HTTP1.1 新增了协商缓存的字段 ETag 比 if-None-Match 更加紧准

3 新增 Host 字段

根据 Host 区分同一 IP 服务器上的不同网站

之前只能通过 IP 区分网站

4 请求资源方面

添加范围请求 (206 状态码)

5 新增了请求方法

PUT、HEAD、OPTIONS 等

HTTP/2.0

一个域名只有一个 TCP 长连接传输数据 (避规 HTTP 1.1 的 TCP 慢启动和多个 TCP 连接时竞争带宽资源)

多路复用机制

通过引入二进制分帧层,实现多路复用机制

整体流程整体流程

  1. 浏览器发起请求,经过二进制分帧层将请求拆分成一个个带请求id的帧,发送给服务端
  2. 服务端收到这些帧后,根据请求id组装成完整请求信息,服务端处理完请求后,将响应请求发送到二进制分帧层,经过二进制分帧层转化为一个个带有响应id的帧发送给浏览器
  3. 浏览器收到这些帧后,会组合成一个完整的响应请求

实现基础: HTTP2 是一个二进制协议,在 HTTP/1.1 版中,报文的头信息必须是文本(ASCII 编码),数据体可以是文本,也可以是二进制。HTTP/2 则是一个彻底的二进制协议,头信息和数据体都是二进制,并且统称为"帧",可以分为头信息帧和数据帧。 帧的概念是它实现多路复用的基础

头部压缩

HTTP/2 实现了头信息压缩,由于 HTTP 1.1 协议不带状态,每次请求都必须附上所有信息。所以,请求的很多字段都是重复的,比如 Cookie 和 User Agent ,一模一样的内容,每次请求都必须附带,这会浪费很多带宽,也影响速度。HTTP/2 对这一点做了优化,引入了头信息压缩机制。一方面,头信息使用 gzip 或 compress 压缩后再发送;另一方面,客户端和服务器同时维护一张头信息表,所有字段都会存入这个表,生成一个索引号,以后就不发送同样字段了,只发送索引号,这样就能提高速度了。

设置请求优先级

服务器推送

存在的问题

TCP 协议本身存在的问题:

    1. TCP 的队头阻塞 TCP 传输过程中把一份数据分成多个数据包进行传输,当某个数据包没有按顺序返回,接收端会一直保持连接等待数据包返回,这就阻塞了后续数据包的传输 整体流程
    1. TCP 建立连接需要耗时

优点

多路复用技术能有效利用带宽(只有一个TCP连接),缓解 TCP 慢启动带来的问题,解决了 HTTP 队头阻塞问题,同时还支持设置优先级、服务器推送、头部压缩极大的提高了 HTTP 的传输效率

http2 与 http1 的区别?

  1. 为了解决 HTTP1.1 的队头阻塞问题引入了二进制分帧层
  2. 只建立一个 TCP 连接,解决 HTTP1.1中 TCP 慢启动以及多个 TCP 之间相互竞争带宽问题
  3. 头部压缩,HTTP2 请求头部采用头部压缩,减少数据内容的大小,提高效率
  4. 服务端推送: 服务端可以向客户端推送资源

HTTP3.0

采用UDP + QUIC协议

  1. UDP 可以减少连接耗费的 RTT,加快数据传输
  2. 使用 QUIC 协议,可以使用多路复用、TLS、可靠性传输等 TCP 协议的特点

存在的问题:

  1. 规范的制定和落地有着较大的差异(比如官方的QUIC和谷歌的QUIC协议有较大差异)
  2. 是对底层协议的改造,落地成本高。

HTTP1.0/1.1/2.0有什么区别?

这道题应该从HTTP的发展历史的角度出发

  1. http1.0 在 http0.9 时代新增了图片、视频的传输,同时新增了请求、响应头,支持文件下载,但请求的效率低,因为每个http请求需要一次TCP连接
  2. HTTP1.1 引入了缓存策略、支持长连接keep-alive等,支持PUT/DELETE/OPTION方法,提高了HTTP的传输效率,但并发请求时会有一个HTTP的头部阻塞问题
  3. HTTP2 通过引入二进制分帧层、采用多路复用避规了HTTP的头部阻塞问题,还支持头部压缩,提高HTTP的传输效率,服务端推送

RTT

浏览器发送数据包到服务器 + 浏览器接收到服务器确认接收的数据包的往返时间,成为RTT

',60),s=[T];function P(n,p,d,c,u,b){return t(),e("div",null,s)}const m=a(h,[["render",P]]);export{H as __pageData,m as default}; diff --git "a/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_HTTP.md.272df02e.lean.js" "b/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_HTTP.md.0eca7c23.lean.js" similarity index 88% rename from "assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_HTTP.md.272df02e.lean.js" rename to "assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_HTTP.md.0eca7c23.lean.js" index 7dce07cf..dbc454d0 100644 --- "a/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_HTTP.md.272df02e.lean.js" +++ "b/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_HTTP.md.0eca7c23.lean.js" @@ -1 +1 @@ -import{_ as a,o as t,c as e,Q as l}from"./chunks/framework.b6910bb2.js";const i="/vitePress-blob/assets/5.c8205ece.jpg",o="/vitePress-blob/assets/6.76a1cb50.jpg",r="/vitePress-blob/assets/7.ee9188c9.jpg",H=JSON.parse('{"title":"HTTP","description":"","frontmatter":{},"headers":[],"relativePath":"guide/网络相关/HTTP.md","filePath":"guide/网络相关/HTTP.md","lastUpdated":1718173557000}'),h={name:"guide/网络相关/HTTP.md"},T=l("",60),s=[T];function P(n,p,d,c,u,b){return t(),e("div",null,s)}const m=a(h,[["render",P]]);export{H as __pageData,m as default}; +import{_ as a,o as t,c as e,Q as l}from"./chunks/framework.b6910bb2.js";const i="/vitePress-blob/assets/5.c8205ece.jpg",o="/vitePress-blob/assets/6.76a1cb50.jpg",r="/vitePress-blob/assets/7.ee9188c9.jpg",H=JSON.parse('{"title":"HTTP","description":"","frontmatter":{},"headers":[],"relativePath":"guide/网络相关/HTTP.md","filePath":"guide/网络相关/HTTP.md","lastUpdated":1718174182000}'),h={name:"guide/网络相关/HTTP.md"},T=l("",60),s=[T];function P(n,p,d,c,u,b){return t(),e("div",null,s)}const m=a(h,[["render",P]]);export{H as __pageData,m as default}; diff --git "a/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_HTTPS.md.6d2b716a.js" "b/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_HTTPS.md.c151d679.js" similarity index 98% rename from "assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_HTTPS.md.6d2b716a.js" rename to "assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_HTTPS.md.c151d679.js" index f7df9ddd..6340fee9 100644 --- "a/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_HTTPS.md.6d2b716a.js" +++ "b/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_HTTPS.md.c151d679.js" @@ -1 +1 @@ -import{_ as a,o as t,c as e,Q as i}from"./chunks/framework.b6910bb2.js";const l="/vitePress-blob/assets/8.428d7ec3.jpg",s="/vitePress-blob/assets/9.7081f11f.jpg",o="/vitePress-blob/assets/10.80b27028.jpg",r="/vitePress-blob/assets/11.8b44a308.jpg",h="/vitePress-blob/assets/12.c1a5b37b.jpg",S=JSON.parse('{"title":"HTTPS","description":"","frontmatter":{},"headers":[],"relativePath":"guide/网络相关/HTTPS.md","filePath":"guide/网络相关/HTTPS.md","lastUpdated":1718173557000}'),T={name:"guide/网络相关/HTTPS.md"},n=i('

HTTPS

HTTP 和 HTTPS 的区别

  1. HTTP 是超文本传输协议,明文传输、简单、无状态,而 HTTPS 是在 HTTP 基础上增加了 SSL 协议,更加安全
  2. HTTP 协议默认端口是 80,HTTPS 协议默认端口是 443
  3. HTTPS 需要 CA 证书、相对于 HTTP 费用更高

HTTPS 演进过程

第一版对称加密 - 不安全

流程

非对称加密 - 传输效率低

流程

对称加密与非对称加密结合 - 存在中间人攻击

流程

通过数字证书校验网站的真实性和获取网站的公钥

之前传输的是密钥,这种方式传输的是装有密钥的保险箱,就算获取到了保险箱,也没有保险箱的钥匙🔑

流程

  1. 浏览器将对称加密方法列表、非对称加密方法列表、随机数 A 传输给服务端
  2. 服务器接受后,将对称加密、非对称加密方法、服务器生成的随机数 B 、数字证书发送给浏览器
  3. 浏览器接受后,验证证书的可靠性,并获取证书内的非对称加密的公钥
  4. 浏览器通过 2 个随机数生成新的随机数 C,并通过非对成加密的公钥对随机数 C 进行加密发送给服务器
  5. 服务器确认后,服务器与浏览器通过 3 个随机数生成对称加密密钥,进行数据传输

如何验证证书的可靠性

  1. 浏览器获取到证书后,通过 CA 相同的 Hash 算法对证书信息进行加密得到摘要 A
  2. 通过 CA 的公钥对证书内的数字签名进行解密,获取到摘要 B
  3. 如果 AB 相同,则证书可靠

什么是 HTTPS 中间人攻击?如何预防?

  1. 先说下 HTTPS 传输过程
  2. 客户端和服务端通信之间,新增一个中间人,伪造 CA 证书和加密数据,获取服务器和客户端的通信信息

流程

如何预防?

使用正规厂商的第三方证书

',21),c=[n];function p(d,P,_,b,m,u){return t(),e("div",null,c)}const f=a(T,[["render",p]]);export{S as __pageData,f as default}; +import{_ as a,o as t,c as e,Q as i}from"./chunks/framework.b6910bb2.js";const l="/vitePress-blob/assets/8.428d7ec3.jpg",s="/vitePress-blob/assets/9.7081f11f.jpg",o="/vitePress-blob/assets/10.80b27028.jpg",r="/vitePress-blob/assets/11.8b44a308.jpg",h="/vitePress-blob/assets/12.c1a5b37b.jpg",S=JSON.parse('{"title":"HTTPS","description":"","frontmatter":{},"headers":[],"relativePath":"guide/网络相关/HTTPS.md","filePath":"guide/网络相关/HTTPS.md","lastUpdated":1718174182000}'),T={name:"guide/网络相关/HTTPS.md"},n=i('

HTTPS

HTTP 和 HTTPS 的区别

  1. HTTP 是超文本传输协议,明文传输、简单、无状态,而 HTTPS 是在 HTTP 基础上增加了 SSL 协议,更加安全
  2. HTTP 协议默认端口是 80,HTTPS 协议默认端口是 443
  3. HTTPS 需要 CA 证书、相对于 HTTP 费用更高

HTTPS 演进过程

第一版对称加密 - 不安全

流程

非对称加密 - 传输效率低

流程

对称加密与非对称加密结合 - 存在中间人攻击

流程

通过数字证书校验网站的真实性和获取网站的公钥

之前传输的是密钥,这种方式传输的是装有密钥的保险箱,就算获取到了保险箱,也没有保险箱的钥匙🔑

流程

  1. 浏览器将对称加密方法列表、非对称加密方法列表、随机数 A 传输给服务端
  2. 服务器接受后,将对称加密、非对称加密方法、服务器生成的随机数 B 、数字证书发送给浏览器
  3. 浏览器接受后,验证证书的可靠性,并获取证书内的非对称加密的公钥
  4. 浏览器通过 2 个随机数生成新的随机数 C,并通过非对成加密的公钥对随机数 C 进行加密发送给服务器
  5. 服务器确认后,服务器与浏览器通过 3 个随机数生成对称加密密钥,进行数据传输

如何验证证书的可靠性

  1. 浏览器获取到证书后,通过 CA 相同的 Hash 算法对证书信息进行加密得到摘要 A
  2. 通过 CA 的公钥对证书内的数字签名进行解密,获取到摘要 B
  3. 如果 AB 相同,则证书可靠

什么是 HTTPS 中间人攻击?如何预防?

  1. 先说下 HTTPS 传输过程
  2. 客户端和服务端通信之间,新增一个中间人,伪造 CA 证书和加密数据,获取服务器和客户端的通信信息

流程

如何预防?

使用正规厂商的第三方证书

',21),c=[n];function p(d,P,_,b,m,u){return t(),e("div",null,c)}const f=a(T,[["render",p]]);export{S as __pageData,f as default}; diff --git "a/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_HTTPS.md.6d2b716a.lean.js" "b/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_HTTPS.md.c151d679.lean.js" similarity index 90% rename from "assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_HTTPS.md.6d2b716a.lean.js" rename to "assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_HTTPS.md.c151d679.lean.js" index 14a83015..e5a55b39 100644 --- "a/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_HTTPS.md.6d2b716a.lean.js" +++ "b/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_HTTPS.md.c151d679.lean.js" @@ -1 +1 @@ -import{_ as a,o as t,c as e,Q as i}from"./chunks/framework.b6910bb2.js";const l="/vitePress-blob/assets/8.428d7ec3.jpg",s="/vitePress-blob/assets/9.7081f11f.jpg",o="/vitePress-blob/assets/10.80b27028.jpg",r="/vitePress-blob/assets/11.8b44a308.jpg",h="/vitePress-blob/assets/12.c1a5b37b.jpg",S=JSON.parse('{"title":"HTTPS","description":"","frontmatter":{},"headers":[],"relativePath":"guide/网络相关/HTTPS.md","filePath":"guide/网络相关/HTTPS.md","lastUpdated":1718173557000}'),T={name:"guide/网络相关/HTTPS.md"},n=i("",21),c=[n];function p(d,P,_,b,m,u){return t(),e("div",null,c)}const f=a(T,[["render",p]]);export{S as __pageData,f as default}; +import{_ as a,o as t,c as e,Q as i}from"./chunks/framework.b6910bb2.js";const l="/vitePress-blob/assets/8.428d7ec3.jpg",s="/vitePress-blob/assets/9.7081f11f.jpg",o="/vitePress-blob/assets/10.80b27028.jpg",r="/vitePress-blob/assets/11.8b44a308.jpg",h="/vitePress-blob/assets/12.c1a5b37b.jpg",S=JSON.parse('{"title":"HTTPS","description":"","frontmatter":{},"headers":[],"relativePath":"guide/网络相关/HTTPS.md","filePath":"guide/网络相关/HTTPS.md","lastUpdated":1718174182000}'),T={name:"guide/网络相关/HTTPS.md"},n=i("",21),c=[n];function p(d,P,_,b,m,u){return t(),e("div",null,c)}const f=a(T,[["render",p]]);export{S as __pageData,f as default}; diff --git "a/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_\345\223\215\345\272\224\346\212\245\346\226\207.md.4e44105b.js" "b/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_\345\223\215\345\272\224\346\212\245\346\226\207.md.c005c655.js" similarity index 99% rename from "assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_\345\223\215\345\272\224\346\212\245\346\226\207.md.4e44105b.js" rename to "assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_\345\223\215\345\272\224\346\212\245\346\226\207.md.c005c655.js" index a485697c..282d6c29 100644 --- "a/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_\345\223\215\345\272\224\346\212\245\346\226\207.md.4e44105b.js" +++ "b/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_\345\223\215\345\272\224\346\212\245\346\226\207.md.c005c655.js" @@ -1 +1 @@ -import{_ as i,o as l,c as a,Q as e}from"./chunks/framework.b6910bb2.js";const t="data:image/jpeg;base64,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",C=JSON.parse('{"title":"响应报文","description":"","frontmatter":{},"headers":[],"relativePath":"guide/网络相关/响应报文.md","filePath":"guide/网络相关/响应报文.md","lastUpdated":1718173557000}'),o={name:"guide/网络相关/响应报文.md"},r=e('

响应报文

由响应行、响应头、响应体组成

响应行

由版本、状态码、原因语句组成

状态码

  • 1xx: 请求已被接受,需要继续处理

  • 2xx: 请求已成功处理

    • 200 请求正常处理、命中强缓存
    • 204 请求处理成功,但没有资源返回
    • 206 客户端进行了范围请求,服务端成功执行了这部分 GET 请求
  • 3xx:客户端需要采取进一步操作才能完成

    • 301 永久重定向
    • 302 临时重定向
    • 304 命中协商缓存
  • 4xx: 客户端错误

    • 400 请求存在语法错误
    • 401 用户登录权限不通过
    • 403 用户登录了,但操作权限不通过
    • 404 资源不存在
    • 405 请求行中制定的方法不能被用于请求相应的资源
  • 5xx: 服务端错误

    • 500 服务端报错
    • 504 服务/网关超时

流程

响应头

响应内容相关

  • content-type 内容类型 Content-Type: text/plain;charset=UTF-8
    • 常见的有:
      • application/x-www-form-urlencoded: 浏览器的原生 form 表单,如果不设置 enctype 属性,那么最终就会以 application/x-www-form-urlencoded 方式提交数据。该种方式提交的数据放在 body 里面,数据按照 key1=val1&key2=val2 的方式进行编码,key 和 val 都进行了 URL转码
      • application/json: 服务器消息主体是序列化后的 JSON 字符串
      • multipart/form-data: 该种方式也是一个常见的 POST 提交方式,通常表单上传文件时使用该种方式。
  • content-length 内容长度

缓存相关

  • Cache-Control
  • Last-Modified
  • ETag

客户端相关

  • Set-Cookie: isGray=true;

跨域相关

  • 简单请求

    • Access-Control-Allow-Origin
  • 非简单请求

    • Access-Control-Allow-Methods
    • Access-Control-Allow-Headers
    • Access-Control-Max-Age
  • Cookie 相关

    • Access-Control-Allow-Credentials: true;

时间相关

Date: Mon, 21 Mar 2022 03:36:53 GMT

响应体

',19),d=[r];function n(h,s,p,u,c,A){return l(),a("div",null,d)}const f=i(o,[["render",n]]);export{C as __pageData,f as default}; +import{_ as i,o as l,c as a,Q as e}from"./chunks/framework.b6910bb2.js";const t="data:image/jpeg;base64,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",C=JSON.parse('{"title":"响应报文","description":"","frontmatter":{},"headers":[],"relativePath":"guide/网络相关/响应报文.md","filePath":"guide/网络相关/响应报文.md","lastUpdated":1718174182000}'),o={name:"guide/网络相关/响应报文.md"},r=e('

响应报文

由响应行、响应头、响应体组成

响应行

由版本、状态码、原因语句组成

状态码

  • 1xx: 请求已被接受,需要继续处理

  • 2xx: 请求已成功处理

    • 200 请求正常处理、命中强缓存
    • 204 请求处理成功,但没有资源返回
    • 206 客户端进行了范围请求,服务端成功执行了这部分 GET 请求
  • 3xx:客户端需要采取进一步操作才能完成

    • 301 永久重定向
    • 302 临时重定向
    • 304 命中协商缓存
  • 4xx: 客户端错误

    • 400 请求存在语法错误
    • 401 用户登录权限不通过
    • 403 用户登录了,但操作权限不通过
    • 404 资源不存在
    • 405 请求行中制定的方法不能被用于请求相应的资源
  • 5xx: 服务端错误

    • 500 服务端报错
    • 504 服务/网关超时

流程

响应头

响应内容相关

  • content-type 内容类型 Content-Type: text/plain;charset=UTF-8
    • 常见的有:
      • application/x-www-form-urlencoded: 浏览器的原生 form 表单,如果不设置 enctype 属性,那么最终就会以 application/x-www-form-urlencoded 方式提交数据。该种方式提交的数据放在 body 里面,数据按照 key1=val1&key2=val2 的方式进行编码,key 和 val 都进行了 URL转码
      • application/json: 服务器消息主体是序列化后的 JSON 字符串
      • multipart/form-data: 该种方式也是一个常见的 POST 提交方式,通常表单上传文件时使用该种方式。
  • content-length 内容长度

缓存相关

  • Cache-Control
  • Last-Modified
  • ETag

客户端相关

  • Set-Cookie: isGray=true;

跨域相关

  • 简单请求

    • Access-Control-Allow-Origin
  • 非简单请求

    • Access-Control-Allow-Methods
    • Access-Control-Allow-Headers
    • Access-Control-Max-Age
  • Cookie 相关

    • Access-Control-Allow-Credentials: true;

时间相关

Date: Mon, 21 Mar 2022 03:36:53 GMT

响应体

',19),d=[r];function n(h,s,p,u,c,A){return l(),a("div",null,d)}const f=i(o,[["render",n]]);export{C as __pageData,f as default}; diff --git "a/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_\345\223\215\345\272\224\346\212\245\346\226\207.md.4e44105b.lean.js" "b/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_\345\223\215\345\272\224\346\212\245\346\226\207.md.c005c655.lean.js" similarity index 98% rename from "assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_\345\223\215\345\272\224\346\212\245\346\226\207.md.4e44105b.lean.js" rename to "assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_\345\223\215\345\272\224\346\212\245\346\226\207.md.c005c655.lean.js" index 2e15c079..ba803a64 100644 --- "a/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_\345\223\215\345\272\224\346\212\245\346\226\207.md.4e44105b.lean.js" +++ "b/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_\345\223\215\345\272\224\346\212\245\346\226\207.md.c005c655.lean.js" @@ -1 +1 @@ -import{_ as i,o as l,c as a,Q as e}from"./chunks/framework.b6910bb2.js";const t="data:image/jpeg;base64,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",C=JSON.parse('{"title":"响应报文","description":"","frontmatter":{},"headers":[],"relativePath":"guide/网络相关/响应报文.md","filePath":"guide/网络相关/响应报文.md","lastUpdated":1718173557000}'),o={name:"guide/网络相关/响应报文.md"},r=e("",19),d=[r];function n(h,s,p,u,c,A){return l(),a("div",null,d)}const f=i(o,[["render",n]]);export{C as __pageData,f as default}; +import{_ as i,o as l,c as a,Q as e}from"./chunks/framework.b6910bb2.js";const t="data:image/jpeg;base64,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",C=JSON.parse('{"title":"响应报文","description":"","frontmatter":{},"headers":[],"relativePath":"guide/网络相关/响应报文.md","filePath":"guide/网络相关/响应报文.md","lastUpdated":1718174182000}'),o={name:"guide/网络相关/响应报文.md"},r=e("",19),d=[r];function n(h,s,p,u,c,A){return l(),a("div",null,d)}const f=i(o,[["render",n]]);export{C as __pageData,f as default}; diff --git "a/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_\345\270\270\350\247\201\347\232\204\351\227\256\351\242\230.md.c84a65b7.js" "b/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_\345\270\270\350\247\201\347\232\204\351\227\256\351\242\230.md.c094fe45.js" similarity index 85% rename from "assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_\345\270\270\350\247\201\347\232\204\351\227\256\351\242\230.md.c84a65b7.js" rename to "assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_\345\270\270\350\247\201\347\232\204\351\227\256\351\242\230.md.c094fe45.js" index e42cdf46..fd6e7147 100644 --- "a/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_\345\270\270\350\247\201\347\232\204\351\227\256\351\242\230.md.c84a65b7.js" +++ "b/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_\345\270\270\350\247\201\347\232\204\351\227\256\351\242\230.md.c094fe45.js" @@ -1 +1 @@ -import{_ as e,o as t,c as a}from"./chunks/framework.b6910bb2.js";const m=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"guide/网络相关/常见的问题.md","filePath":"guide/网络相关/常见的问题.md","lastUpdated":1718173557000}'),r={name:"guide/网络相关/常见的问题.md"};function o(s,_,c,d,n,i){return t(),a("div")}const f=e(r,[["render",o]]);export{m as __pageData,f as default}; +import{_ as e,o as t,c as a}from"./chunks/framework.b6910bb2.js";const m=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"guide/网络相关/常见的问题.md","filePath":"guide/网络相关/常见的问题.md","lastUpdated":1718174182000}'),r={name:"guide/网络相关/常见的问题.md"};function o(s,_,c,d,n,i){return t(),a("div")}const f=e(r,[["render",o]]);export{m as __pageData,f as default}; diff --git "a/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_\345\270\270\350\247\201\347\232\204\351\227\256\351\242\230.md.c84a65b7.lean.js" "b/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_\345\270\270\350\247\201\347\232\204\351\227\256\351\242\230.md.c094fe45.lean.js" similarity index 85% rename from "assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_\345\270\270\350\247\201\347\232\204\351\227\256\351\242\230.md.c84a65b7.lean.js" rename to "assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_\345\270\270\350\247\201\347\232\204\351\227\256\351\242\230.md.c094fe45.lean.js" index e42cdf46..fd6e7147 100644 --- "a/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_\345\270\270\350\247\201\347\232\204\351\227\256\351\242\230.md.c84a65b7.lean.js" +++ "b/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_\345\270\270\350\247\201\347\232\204\351\227\256\351\242\230.md.c094fe45.lean.js" @@ -1 +1 @@ -import{_ as e,o as t,c as a}from"./chunks/framework.b6910bb2.js";const m=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"guide/网络相关/常见的问题.md","filePath":"guide/网络相关/常见的问题.md","lastUpdated":1718173557000}'),r={name:"guide/网络相关/常见的问题.md"};function o(s,_,c,d,n,i){return t(),a("div")}const f=e(r,[["render",o]]);export{m as __pageData,f as default}; +import{_ as e,o as t,c as a}from"./chunks/framework.b6910bb2.js";const m=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"guide/网络相关/常见的问题.md","filePath":"guide/网络相关/常见的问题.md","lastUpdated":1718174182000}'),r={name:"guide/网络相关/常见的问题.md"};function o(s,_,c,d,n,i){return t(),a("div")}const f=e(r,[["render",o]]);export{m as __pageData,f as default}; diff --git "a/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_\346\246\202\350\246\201.md.39eb6321.js" "b/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_\346\246\202\350\246\201.md.b0fd3658.js" similarity index 88% rename from "assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_\346\246\202\350\246\201.md.39eb6321.js" rename to "assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_\346\246\202\350\246\201.md.b0fd3658.js" index b168a1a9..2d1d99cd 100644 --- "a/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_\346\246\202\350\246\201.md.39eb6321.js" +++ "b/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_\346\246\202\350\246\201.md.b0fd3658.js" @@ -1 +1 @@ -import{_ as e}from"./chunks/container.fad5294e.js";import{o as t,c as a,H as s}from"./chunks/framework.b6910bb2.js";const m=JSON.parse('{"title":"","description":"","frontmatter":{"aside":false,"outline":false},"headers":[],"relativePath":"guide/网络相关/概要.md","filePath":"guide/网络相关/概要.md","lastUpdated":1718173557000}'),o={name:"guide/网络相关/概要.md"},n=Object.assign(o,{setup(r){return(c,d)=>(t(),a("div",null,[s(e,{url:"https://www.mubu.com/doc/7RYbHADBDCK#m"})]))}});export{m as __pageData,n as default}; +import{_ as e}from"./chunks/container.fad5294e.js";import{o as t,c as a,H as s}from"./chunks/framework.b6910bb2.js";const m=JSON.parse('{"title":"","description":"","frontmatter":{"aside":false,"outline":false},"headers":[],"relativePath":"guide/网络相关/概要.md","filePath":"guide/网络相关/概要.md","lastUpdated":1718174182000}'),o={name:"guide/网络相关/概要.md"},n=Object.assign(o,{setup(r){return(c,d)=>(t(),a("div",null,[s(e,{url:"https://www.mubu.com/doc/7RYbHADBDCK#m"})]))}});export{m as __pageData,n as default}; diff --git "a/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_\346\246\202\350\246\201.md.39eb6321.lean.js" "b/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_\346\246\202\350\246\201.md.b0fd3658.lean.js" similarity index 88% rename from "assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_\346\246\202\350\246\201.md.39eb6321.lean.js" rename to "assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_\346\246\202\350\246\201.md.b0fd3658.lean.js" index b168a1a9..2d1d99cd 100644 --- "a/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_\346\246\202\350\246\201.md.39eb6321.lean.js" +++ "b/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_\346\246\202\350\246\201.md.b0fd3658.lean.js" @@ -1 +1 @@ -import{_ as e}from"./chunks/container.fad5294e.js";import{o as t,c as a,H as s}from"./chunks/framework.b6910bb2.js";const m=JSON.parse('{"title":"","description":"","frontmatter":{"aside":false,"outline":false},"headers":[],"relativePath":"guide/网络相关/概要.md","filePath":"guide/网络相关/概要.md","lastUpdated":1718173557000}'),o={name:"guide/网络相关/概要.md"},n=Object.assign(o,{setup(r){return(c,d)=>(t(),a("div",null,[s(e,{url:"https://www.mubu.com/doc/7RYbHADBDCK#m"})]))}});export{m as __pageData,n as default}; +import{_ as e}from"./chunks/container.fad5294e.js";import{o as t,c as a,H as s}from"./chunks/framework.b6910bb2.js";const m=JSON.parse('{"title":"","description":"","frontmatter":{"aside":false,"outline":false},"headers":[],"relativePath":"guide/网络相关/概要.md","filePath":"guide/网络相关/概要.md","lastUpdated":1718174182000}'),o={name:"guide/网络相关/概要.md"},n=Object.assign(o,{setup(r){return(c,d)=>(t(),a("div",null,[s(e,{url:"https://www.mubu.com/doc/7RYbHADBDCK#m"})]))}});export{m as __pageData,n as default}; diff --git "a/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_\350\257\267\346\261\202\346\212\245\346\226\207.md.0ba8148e.js" "b/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_\350\257\267\346\261\202\346\212\245\346\226\207.md.6db843bd.js" similarity index 98% rename from "assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_\350\257\267\346\261\202\346\212\245\346\226\207.md.0ba8148e.js" rename to "assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_\350\257\267\346\261\202\346\212\245\346\226\207.md.6db843bd.js" index 145f9704..4a3980b4 100644 --- "a/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_\350\257\267\346\261\202\346\212\245\346\226\207.md.0ba8148e.js" +++ "b/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_\350\257\267\346\261\202\346\212\245\346\226\207.md.6db843bd.js" @@ -1 +1 @@ -import{_ as a,o as e,c as i,Q as l}from"./chunks/framework.b6910bb2.js";const t="/vitePress-blob/assets/2.8a82dbf4.png",o="/vitePress-blob/assets/3.8de7cbe1.jpg",m=JSON.parse('{"title":"请求报文","description":"","frontmatter":{},"headers":[],"relativePath":"guide/网络相关/请求报文.md","filePath":"guide/网络相关/请求报文.md","lastUpdated":1718173557000}'),r={name:"guide/网络相关/请求报文.md"},n=l('

请求报文

由请求行、请求头、请求体组成

请求行

由请求方法、URI、协议版本组成

流程

请求方法

  1. GET 请求获取资源
  2. POST 提交数据
  3. PUT 更新资源
  4. DELETE 删除资源
  5. OPTIONS 查询针对请求 URL 指定的资源支持的方法(常用在非简单请求的预检上)
  6. HEAD 获取响应头
  7. CONNECT 要求用隧道协议链接代理
  8. TRACE 追踪请求经过的路径

URI 字段

协议版本

HTTP0.9、 HTTP1.0、HTTP1.1、HTTP2.0、HTTP3.0

请求头

接受内容相关

  1. Accept 浏览器接受的格式 Accept: application/json, text/plain, /
  2. Accept-Encoding 浏览器接受的压缩格式 Accept-Encoding: gzip, deflate, br
  3. Accept-Language 浏览器接受的语言 Accept-Language: zh-CN
  4. Accept-Charset 浏览器接受的字符集

强缓存相关

  1. Cache-Control

协商缓存相关

  1. If-Modified-Since 上一次访问时文件的更改时间 (存在校验问题,比如文件内容只是添加了空格,但是 Last-Modified 改变了)
  2. If-None-Match 上次访问的 ETag 信息 (如果 If-None-Match 和 ETag 一致,则命中 304 协商缓存)

请求域名相关

  1. HOST HTTP 请求的域名
  2. Origin 页面域名 (常用于防止 CSRF 攻击和跨域请求)
  3. Referer 发出请求的页面 URL

客户端相关

  • UA
  • COOKIE

连接相关

  • Connection Connection: keep-alive

流程

请求体

',25),h=[n];function c(s,d,u,p,_,b){return e(),i("div",null,h)}const P=a(r,[["render",c]]);export{m as __pageData,P as default}; +import{_ as a,o as e,c as i,Q as l}from"./chunks/framework.b6910bb2.js";const t="/vitePress-blob/assets/2.8a82dbf4.png",o="/vitePress-blob/assets/3.8de7cbe1.jpg",m=JSON.parse('{"title":"请求报文","description":"","frontmatter":{},"headers":[],"relativePath":"guide/网络相关/请求报文.md","filePath":"guide/网络相关/请求报文.md","lastUpdated":1718174182000}'),r={name:"guide/网络相关/请求报文.md"},n=l('

请求报文

由请求行、请求头、请求体组成

请求行

由请求方法、URI、协议版本组成

流程

请求方法

  1. GET 请求获取资源
  2. POST 提交数据
  3. PUT 更新资源
  4. DELETE 删除资源
  5. OPTIONS 查询针对请求 URL 指定的资源支持的方法(常用在非简单请求的预检上)
  6. HEAD 获取响应头
  7. CONNECT 要求用隧道协议链接代理
  8. TRACE 追踪请求经过的路径

URI 字段

协议版本

HTTP0.9、 HTTP1.0、HTTP1.1、HTTP2.0、HTTP3.0

请求头

接受内容相关

  1. Accept 浏览器接受的格式 Accept: application/json, text/plain, /
  2. Accept-Encoding 浏览器接受的压缩格式 Accept-Encoding: gzip, deflate, br
  3. Accept-Language 浏览器接受的语言 Accept-Language: zh-CN
  4. Accept-Charset 浏览器接受的字符集

强缓存相关

  1. Cache-Control

协商缓存相关

  1. If-Modified-Since 上一次访问时文件的更改时间 (存在校验问题,比如文件内容只是添加了空格,但是 Last-Modified 改变了)
  2. If-None-Match 上次访问的 ETag 信息 (如果 If-None-Match 和 ETag 一致,则命中 304 协商缓存)

请求域名相关

  1. HOST HTTP 请求的域名
  2. Origin 页面域名 (常用于防止 CSRF 攻击和跨域请求)
  3. Referer 发出请求的页面 URL

客户端相关

  • UA
  • COOKIE

连接相关

  • Connection Connection: keep-alive

流程

请求体

',25),h=[n];function c(s,d,u,p,_,b){return e(),i("div",null,h)}const P=a(r,[["render",c]]);export{m as __pageData,P as default}; diff --git "a/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_\350\257\267\346\261\202\346\212\245\346\226\207.md.0ba8148e.lean.js" "b/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_\350\257\267\346\261\202\346\212\245\346\226\207.md.6db843bd.lean.js" similarity index 88% rename from "assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_\350\257\267\346\261\202\346\212\245\346\226\207.md.0ba8148e.lean.js" rename to "assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_\350\257\267\346\261\202\346\212\245\346\226\207.md.6db843bd.lean.js" index b138a715..518ec33e 100644 --- "a/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_\350\257\267\346\261\202\346\212\245\346\226\207.md.0ba8148e.lean.js" +++ "b/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_\350\257\267\346\261\202\346\212\245\346\226\207.md.6db843bd.lean.js" @@ -1 +1 @@ -import{_ as a,o as e,c as i,Q as l}from"./chunks/framework.b6910bb2.js";const t="/vitePress-blob/assets/2.8a82dbf4.png",o="/vitePress-blob/assets/3.8de7cbe1.jpg",m=JSON.parse('{"title":"请求报文","description":"","frontmatter":{},"headers":[],"relativePath":"guide/网络相关/请求报文.md","filePath":"guide/网络相关/请求报文.md","lastUpdated":1718173557000}'),r={name:"guide/网络相关/请求报文.md"},n=l("",25),h=[n];function c(s,d,u,p,_,b){return e(),i("div",null,h)}const P=a(r,[["render",c]]);export{m as __pageData,P as default}; +import{_ as a,o as e,c as i,Q as l}from"./chunks/framework.b6910bb2.js";const t="/vitePress-blob/assets/2.8a82dbf4.png",o="/vitePress-blob/assets/3.8de7cbe1.jpg",m=JSON.parse('{"title":"请求报文","description":"","frontmatter":{},"headers":[],"relativePath":"guide/网络相关/请求报文.md","filePath":"guide/网络相关/请求报文.md","lastUpdated":1718174182000}'),r={name:"guide/网络相关/请求报文.md"},n=l("",25),h=[n];function c(s,d,u,p,_,b){return e(),i("div",null,h)}const P=a(r,[["render",c]]);export{m as __pageData,P as default}; diff --git "a/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_\350\267\250\345\237\237\350\257\267\346\261\202.md.d18aad93.js" "b/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_\350\267\250\345\237\237\350\257\267\346\261\202.md.a6d45f4f.js" similarity index 99% rename from "assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_\350\267\250\345\237\237\350\257\267\346\261\202.md.d18aad93.js" rename to "assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_\350\267\250\345\237\237\350\257\267\346\261\202.md.a6d45f4f.js" index 569209fd..16d5b149 100644 --- "a/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_\350\267\250\345\237\237\350\257\267\346\261\202.md.d18aad93.js" +++ "b/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_\350\267\250\345\237\237\350\257\267\346\261\202.md.a6d45f4f.js" @@ -1 +1 @@ -import{_ as i,o,c as l,Q as e}from"./chunks/framework.b6910bb2.js";const a="/vitePress-blob/assets/7.d0aefc74.jpg",t="/vitePress-blob/assets/8.28d1dcd9.jpg",s="/vitePress-blob/assets/16.ecfc65d2.jpg",r="/vitePress-blob/assets/17.8329667f.jpg",n="/vitePress-blob/assets/18.5204f2f6.jpg",q=JSON.parse('{"title":"跨域请求","description":"","frontmatter":{},"headers":[],"relativePath":"guide/网络相关/跨域请求.md","filePath":"guide/网络相关/跨域请求.md","lastUpdated":1718173557000}'),c={name:"guide/网络相关/跨域请求.md"},d=e('

跨域请求

简单请求

若请求满足所有下述条件,则该请求可视为简单请求:

  1. HEAD/GET/POST 请求
  2. Content-Type: text/plain、multipart/form-data、application/x-www-form-urlencoded
  3. 除了被用户代理自动设置的标头字段,剩下的请求头是: Accept、Accept-Language、Content-Language、Content-Type、Range

请求过程

  1. 发起请求,请求头会带上 Origin 字段,该字段用来说明请求来自哪个源(协议 + 域名 + 端口),服务器根据这个值决定是否同意这次请求
  2. 当服务器接收到请求后,根据 Origin 判断是否在允许的范围内
  3. 如果不在范围内,服务器会返回一个正常的 HTTP 响应,浏览器发现响应头信息没有 Access-Control-Allow-Origin 字段,就知道出错了,从而抛出错误,被 XML 的 onerror 回调函数捕获。(注意:由于正常响应,其状态码为200,因此该错误不能通过状态码识别)
  4. 如果 Origin 指定的域名在范围内,服务器返回的响应会多出几个头信息字段(Access-Control-Allow-Origin、Access-Control-Allow-Credentials、Access-Control-Expose-Header 等)

流程

非简单请求

请求方法是 PUT、DELETE 或者 Content-Type 是 application/json 类型

请求过程 (源、请求头、方法、缓存、Cookie)

  1. 浏览器发起 Option 预检请求
  2. 服务器收到预检请求以后,检查了 Origin、Access-Control-Request-Method 和 Access-Control-Request-Headers 字段后,确认允许跨域请求,就可以做出回应
    • Origin (必须): 发起请求的源信息
    • Access-Control-Request-Method(必须): 用来列出浏览器的 CORS 请求会用到哪些 HTTP 方法
    • Access-Control-Request-Headers 跨域请求而外的请求头字段
  3. 如果服务器预检请求,会返回一个正常的 HTTP 回应,但没有任何的 CORS 相关的头信息字段,这时浏览器就会认定服务器不同意预检请求,触发错误。
  4. 如果服务器通过了预检请求,以后每次浏览器正常的 CORS 请求就跟简单请求一样
    • Access-Control-Allow-Origin(必须): 运行哪些源跨域,如果是 * 无法携带 Cookie
    • Access-Control-Allow-Method(必须): 服务器支持哪些请求
    • Access-Control-Allow-Header: 服务器支持的头信息字段
    • Access-Control-Max-Age: 预检请求的有效期,单位秒

流程

  1. 响应头设置 Access-Control-Allow-Credentials 等于 true
  2. Access-Control-Allow-Origin 不能设置成 * (Cookie 的 SameSite 属性如果是 Lax 可能也会导致带不上去)
  3. 前端设置 withCredentials: true

常见的问题

cookie 一般用于登录验证,存储用户信息,大小为 4KB,会随着网络请求携带给服务端

session 一般存储在服务端,常用于与 Cookie 配合做登录检验

  • cookie 是 HTTP 的内容,token 是自定义的数据
  • cookie 可以默认存储在浏览器中,token 需要自行存储
  • token 没有跨域限制,cookie 存在跨域限制
  • token 常用于 CSRF 或者 JWT(JSON WEB TOKEN)
  • Cookie 常于 Session 配合,做用户登录鉴权
  • 基本属性:

    • name
    • value
  • 访问性:

    • expire
    • path
    • domain
  • 安全性:

    • secure
    • httpOnly
    • sameSite

Session 和 JWT 哪个更合适?

  • Session

    • 优点:
      1. 易于学习
      2. 用户信息存储在服务器,可以快速封禁某个用户
    • 缺点:
      1. 占用服务器资源,硬件成本高
      2. 多进程、多服务器时,不好同步 (需要第三方缓存, Redis)
      3. Session 需要配合 Cookie 使用,cookie 有域名限制
  • Json Web Token

    • 优点:
      1. 存储在客户端,不占用服务端资源
      2. 易于同步
      3. 没有跨域限制
    • 缺点:
      1. 无法快速封禁用户
      2. Token 不安全,一但秘钥被泄漏,容易窃取用户信息
      3. Token很大,影响请求体积
  • 使用场景:

    • 用户信息安全 -> 使用 Session
    • 没有特殊要求 -> 使用 JWT

如何实现 SSO 单点登录

Cookie 默认跨域不共享

可以通过设置 Cookie 的 domain 为相同的主域名,即可共享 Cookie

比如 www.baidu.com、image.baidu.com 主域名是相同的,设置 cookie domain 为主域名,即可共享 cookie

流程

如果主域名不一致

  1. 使用 SSO 第三方登录, 获取 ticket 返回给 A、B 系统

流程

  1. OAuth2.0

第三方登录(例如微信扫码登录)

流程

',36),h=[d];function p(u,k,m,b,C,_){return o(),l("div",null,h)}const A=i(c,[["render",p]]);export{q as __pageData,A as default}; +import{_ as i,o,c as l,Q as e}from"./chunks/framework.b6910bb2.js";const a="/vitePress-blob/assets/7.d0aefc74.jpg",t="/vitePress-blob/assets/8.28d1dcd9.jpg",s="/vitePress-blob/assets/16.ecfc65d2.jpg",r="/vitePress-blob/assets/17.8329667f.jpg",n="/vitePress-blob/assets/18.5204f2f6.jpg",q=JSON.parse('{"title":"跨域请求","description":"","frontmatter":{},"headers":[],"relativePath":"guide/网络相关/跨域请求.md","filePath":"guide/网络相关/跨域请求.md","lastUpdated":1718174182000}'),c={name:"guide/网络相关/跨域请求.md"},d=e('

跨域请求

简单请求

若请求满足所有下述条件,则该请求可视为简单请求:

  1. HEAD/GET/POST 请求
  2. Content-Type: text/plain、multipart/form-data、application/x-www-form-urlencoded
  3. 除了被用户代理自动设置的标头字段,剩下的请求头是: Accept、Accept-Language、Content-Language、Content-Type、Range

请求过程

  1. 发起请求,请求头会带上 Origin 字段,该字段用来说明请求来自哪个源(协议 + 域名 + 端口),服务器根据这个值决定是否同意这次请求
  2. 当服务器接收到请求后,根据 Origin 判断是否在允许的范围内
  3. 如果不在范围内,服务器会返回一个正常的 HTTP 响应,浏览器发现响应头信息没有 Access-Control-Allow-Origin 字段,就知道出错了,从而抛出错误,被 XML 的 onerror 回调函数捕获。(注意:由于正常响应,其状态码为200,因此该错误不能通过状态码识别)
  4. 如果 Origin 指定的域名在范围内,服务器返回的响应会多出几个头信息字段(Access-Control-Allow-Origin、Access-Control-Allow-Credentials、Access-Control-Expose-Header 等)

流程

非简单请求

请求方法是 PUT、DELETE 或者 Content-Type 是 application/json 类型

请求过程 (源、请求头、方法、缓存、Cookie)

  1. 浏览器发起 Option 预检请求
  2. 服务器收到预检请求以后,检查了 Origin、Access-Control-Request-Method 和 Access-Control-Request-Headers 字段后,确认允许跨域请求,就可以做出回应
    • Origin (必须): 发起请求的源信息
    • Access-Control-Request-Method(必须): 用来列出浏览器的 CORS 请求会用到哪些 HTTP 方法
    • Access-Control-Request-Headers 跨域请求而外的请求头字段
  3. 如果服务器预检请求,会返回一个正常的 HTTP 回应,但没有任何的 CORS 相关的头信息字段,这时浏览器就会认定服务器不同意预检请求,触发错误。
  4. 如果服务器通过了预检请求,以后每次浏览器正常的 CORS 请求就跟简单请求一样
    • Access-Control-Allow-Origin(必须): 运行哪些源跨域,如果是 * 无法携带 Cookie
    • Access-Control-Allow-Method(必须): 服务器支持哪些请求
    • Access-Control-Allow-Header: 服务器支持的头信息字段
    • Access-Control-Max-Age: 预检请求的有效期,单位秒

流程

  1. 响应头设置 Access-Control-Allow-Credentials 等于 true
  2. Access-Control-Allow-Origin 不能设置成 * (Cookie 的 SameSite 属性如果是 Lax 可能也会导致带不上去)
  3. 前端设置 withCredentials: true

常见的问题

cookie 一般用于登录验证,存储用户信息,大小为 4KB,会随着网络请求携带给服务端

session 一般存储在服务端,常用于与 Cookie 配合做登录检验

  • cookie 是 HTTP 的内容,token 是自定义的数据
  • cookie 可以默认存储在浏览器中,token 需要自行存储
  • token 没有跨域限制,cookie 存在跨域限制
  • token 常用于 CSRF 或者 JWT(JSON WEB TOKEN)
  • Cookie 常于 Session 配合,做用户登录鉴权
  • 基本属性:

    • name
    • value
  • 访问性:

    • expire
    • path
    • domain
  • 安全性:

    • secure
    • httpOnly
    • sameSite

Session 和 JWT 哪个更合适?

  • Session

    • 优点:
      1. 易于学习
      2. 用户信息存储在服务器,可以快速封禁某个用户
    • 缺点:
      1. 占用服务器资源,硬件成本高
      2. 多进程、多服务器时,不好同步 (需要第三方缓存, Redis)
      3. Session 需要配合 Cookie 使用,cookie 有域名限制
  • Json Web Token

    • 优点:
      1. 存储在客户端,不占用服务端资源
      2. 易于同步
      3. 没有跨域限制
    • 缺点:
      1. 无法快速封禁用户
      2. Token 不安全,一但秘钥被泄漏,容易窃取用户信息
      3. Token很大,影响请求体积
  • 使用场景:

    • 用户信息安全 -> 使用 Session
    • 没有特殊要求 -> 使用 JWT

如何实现 SSO 单点登录

Cookie 默认跨域不共享

可以通过设置 Cookie 的 domain 为相同的主域名,即可共享 Cookie

比如 www.baidu.com、image.baidu.com 主域名是相同的,设置 cookie domain 为主域名,即可共享 cookie

流程

如果主域名不一致

  1. 使用 SSO 第三方登录, 获取 ticket 返回给 A、B 系统

流程

  1. OAuth2.0

第三方登录(例如微信扫码登录)

流程

',36),h=[d];function p(u,k,m,b,C,_){return o(),l("div",null,h)}const A=i(c,[["render",p]]);export{q as __pageData,A as default}; diff --git "a/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_\350\267\250\345\237\237\350\257\267\346\261\202.md.d18aad93.lean.js" "b/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_\350\267\250\345\237\237\350\257\267\346\261\202.md.a6d45f4f.lean.js" similarity index 90% rename from "assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_\350\267\250\345\237\237\350\257\267\346\261\202.md.d18aad93.lean.js" rename to "assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_\350\267\250\345\237\237\350\257\267\346\261\202.md.a6d45f4f.lean.js" index 8ac93e90..944fca1a 100644 --- "a/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_\350\267\250\345\237\237\350\257\267\346\261\202.md.d18aad93.lean.js" +++ "b/assets/guide_\347\275\221\347\273\234\347\233\270\345\205\263_\350\267\250\345\237\237\350\257\267\346\261\202.md.a6d45f4f.lean.js" @@ -1 +1 @@ -import{_ as i,o,c as l,Q as e}from"./chunks/framework.b6910bb2.js";const a="/vitePress-blob/assets/7.d0aefc74.jpg",t="/vitePress-blob/assets/8.28d1dcd9.jpg",s="/vitePress-blob/assets/16.ecfc65d2.jpg",r="/vitePress-blob/assets/17.8329667f.jpg",n="/vitePress-blob/assets/18.5204f2f6.jpg",q=JSON.parse('{"title":"跨域请求","description":"","frontmatter":{},"headers":[],"relativePath":"guide/网络相关/跨域请求.md","filePath":"guide/网络相关/跨域请求.md","lastUpdated":1718173557000}'),c={name:"guide/网络相关/跨域请求.md"},d=e("",36),h=[d];function p(u,k,m,b,C,_){return o(),l("div",null,h)}const A=i(c,[["render",p]]);export{q as __pageData,A as default}; +import{_ as i,o,c as l,Q as e}from"./chunks/framework.b6910bb2.js";const a="/vitePress-blob/assets/7.d0aefc74.jpg",t="/vitePress-blob/assets/8.28d1dcd9.jpg",s="/vitePress-blob/assets/16.ecfc65d2.jpg",r="/vitePress-blob/assets/17.8329667f.jpg",n="/vitePress-blob/assets/18.5204f2f6.jpg",q=JSON.parse('{"title":"跨域请求","description":"","frontmatter":{},"headers":[],"relativePath":"guide/网络相关/跨域请求.md","filePath":"guide/网络相关/跨域请求.md","lastUpdated":1718174182000}'),c={name:"guide/网络相关/跨域请求.md"},d=e("",36),h=[d];function p(u,k,m,b,C,_){return o(),l("div",null,h)}const A=i(c,[["render",p]]);export{q as __pageData,A as default}; diff --git a/assets/index.md.7f4fdd92.js b/assets/index.md.6af0eea6.js similarity index 92% rename from assets/index.md.7f4fdd92.js rename to assets/index.md.6af0eea6.js index 9ffafc4f..cd34453a 100644 --- a/assets/index.md.7f4fdd92.js +++ b/assets/index.md.6af0eea6.js @@ -1 +1 @@ -import{_ as t,o as a,c as s,k as e,a as n}from"./chunks/framework.b6910bb2.js";const k=JSON.parse('{"title":"","description":"","frontmatter":{"layout":"doc"},"headers":[],"relativePath":"index.md","filePath":"index.md","lastUpdated":1718173557000}'),o={name:"index.md"},d=e("h3",{id:"个人知识库",tabindex:"-1"},[n("个人知识库 "),e("a",{class:"header-anchor",href:"#个人知识库","aria-label":'Permalink to "个人知识库"'},"​")],-1),r=e("p",null,"👋 欢迎来到我的博客,这里是我记录学习和生活的地方,希望能帮助到你",-1),_=e("p",null,"采用 VitePress 进行构建,为了有更好的阅读体验,请使用新版本浏览器",-1),c=[d,r,_];function i(l,p,h,m,x,f){return a(),s("div",null,c)}const P=t(o,[["render",i]]);export{k as __pageData,P as default}; +import{_ as t,o as a,c as s,k as e,a as n}from"./chunks/framework.b6910bb2.js";const k=JSON.parse('{"title":"","description":"","frontmatter":{"layout":"doc"},"headers":[],"relativePath":"index.md","filePath":"index.md","lastUpdated":1718174182000}'),o={name:"index.md"},d=e("h3",{id:"个人知识库",tabindex:"-1"},[n("个人知识库 "),e("a",{class:"header-anchor",href:"#个人知识库","aria-label":'Permalink to "个人知识库"'},"​")],-1),r=e("p",null,"👋 欢迎来到我的博客,这里是我记录学习和生活的地方,希望能帮助到你",-1),_=e("p",null,"采用 VitePress 进行构建,为了有更好的阅读体验,请使用新版本浏览器",-1),c=[d,r,_];function i(l,p,h,m,x,f){return a(),s("div",null,c)}const P=t(o,[["render",i]]);export{k as __pageData,P as default}; diff --git a/assets/index.md.7f4fdd92.lean.js b/assets/index.md.6af0eea6.lean.js similarity index 92% rename from assets/index.md.7f4fdd92.lean.js rename to assets/index.md.6af0eea6.lean.js index 9ffafc4f..cd34453a 100644 --- a/assets/index.md.7f4fdd92.lean.js +++ b/assets/index.md.6af0eea6.lean.js @@ -1 +1 @@ -import{_ as t,o as a,c as s,k as e,a as n}from"./chunks/framework.b6910bb2.js";const k=JSON.parse('{"title":"","description":"","frontmatter":{"layout":"doc"},"headers":[],"relativePath":"index.md","filePath":"index.md","lastUpdated":1718173557000}'),o={name:"index.md"},d=e("h3",{id:"个人知识库",tabindex:"-1"},[n("个人知识库 "),e("a",{class:"header-anchor",href:"#个人知识库","aria-label":'Permalink to "个人知识库"'},"​")],-1),r=e("p",null,"👋 欢迎来到我的博客,这里是我记录学习和生活的地方,希望能帮助到你",-1),_=e("p",null,"采用 VitePress 进行构建,为了有更好的阅读体验,请使用新版本浏览器",-1),c=[d,r,_];function i(l,p,h,m,x,f){return a(),s("div",null,c)}const P=t(o,[["render",i]]);export{k as __pageData,P as default}; +import{_ as t,o as a,c as s,k as e,a as n}from"./chunks/framework.b6910bb2.js";const k=JSON.parse('{"title":"","description":"","frontmatter":{"layout":"doc"},"headers":[],"relativePath":"index.md","filePath":"index.md","lastUpdated":1718174182000}'),o={name:"index.md"},d=e("h3",{id:"个人知识库",tabindex:"-1"},[n("个人知识库 "),e("a",{class:"header-anchor",href:"#个人知识库","aria-label":'Permalink to "个人知识库"'},"​")],-1),r=e("p",null,"👋 欢迎来到我的博客,这里是我记录学习和生活的地方,希望能帮助到你",-1),_=e("p",null,"采用 VitePress 进行构建,为了有更好的阅读体验,请使用新版本浏览器",-1),c=[d,r,_];function i(l,p,h,m,x,f){return a(),s("div",null,c)}const P=t(o,[["render",i]]);export{k as __pageData,P as default}; diff --git "a/assets/shoot_\345\237\272\347\241\200\346\246\202\345\277\265_ISO\346\204\237\345\205\211\345\272\246.md.9142d6ab.js" "b/assets/shoot_\345\237\272\347\241\200\346\246\202\345\277\265_ISO\346\204\237\345\205\211\345\272\246.md.bdf26bdf.js" similarity index 91% rename from "assets/shoot_\345\237\272\347\241\200\346\246\202\345\277\265_ISO\346\204\237\345\205\211\345\272\246.md.9142d6ab.js" rename to "assets/shoot_\345\237\272\347\241\200\346\246\202\345\277\265_ISO\346\204\237\345\205\211\345\272\246.md.bdf26bdf.js" index 6c5642a7..060aaf58 100644 --- "a/assets/shoot_\345\237\272\347\241\200\346\246\202\345\277\265_ISO\346\204\237\345\205\211\345\272\246.md.9142d6ab.js" +++ "b/assets/shoot_\345\237\272\347\241\200\346\246\202\345\277\265_ISO\346\204\237\345\205\211\345\272\246.md.bdf26bdf.js" @@ -1 +1 @@ -import{_ as t,o as a,c as o,k as e,a as s}from"./chunks/framework.b6910bb2.js";const S=JSON.parse('{"title":"ISO 感光度","description":"","frontmatter":{},"headers":[],"relativePath":"shoot/基础概念/ISO感光度.md","filePath":"shoot/基础概念/ISO感光度.md","lastUpdated":1718173557000}'),n={name:"shoot/基础概念/ISO感光度.md"},r=e("h1",{id:"iso-感光度",tabindex:"-1"},[s("ISO 感光度 "),e("a",{class:"header-anchor",href:"#iso-感光度","aria-label":'Permalink to "ISO 感光度"'},"​")],-1),c=e("p",null,"传感器对光线的敏感程度",-1),l=e("ul",null,[e("li",null,"感光度越大、图片越亮,但也容易出现噪点")],-1),_=[r,c,l];function d(i,h,p,m,f,u){return a(),o("div",null,_)}const I=t(n,[["render",d]]);export{S as __pageData,I as default}; +import{_ as t,o as a,c as o,k as e,a as s}from"./chunks/framework.b6910bb2.js";const S=JSON.parse('{"title":"ISO 感光度","description":"","frontmatter":{},"headers":[],"relativePath":"shoot/基础概念/ISO感光度.md","filePath":"shoot/基础概念/ISO感光度.md","lastUpdated":1718174182000}'),n={name:"shoot/基础概念/ISO感光度.md"},r=e("h1",{id:"iso-感光度",tabindex:"-1"},[s("ISO 感光度 "),e("a",{class:"header-anchor",href:"#iso-感光度","aria-label":'Permalink to "ISO 感光度"'},"​")],-1),c=e("p",null,"传感器对光线的敏感程度",-1),l=e("ul",null,[e("li",null,"感光度越大、图片越亮,但也容易出现噪点")],-1),_=[r,c,l];function d(i,h,p,m,f,u){return a(),o("div",null,_)}const I=t(n,[["render",d]]);export{S as __pageData,I as default}; diff --git "a/assets/shoot_\345\237\272\347\241\200\346\246\202\345\277\265_ISO\346\204\237\345\205\211\345\272\246.md.9142d6ab.lean.js" "b/assets/shoot_\345\237\272\347\241\200\346\246\202\345\277\265_ISO\346\204\237\345\205\211\345\272\246.md.bdf26bdf.lean.js" similarity index 91% rename from "assets/shoot_\345\237\272\347\241\200\346\246\202\345\277\265_ISO\346\204\237\345\205\211\345\272\246.md.9142d6ab.lean.js" rename to "assets/shoot_\345\237\272\347\241\200\346\246\202\345\277\265_ISO\346\204\237\345\205\211\345\272\246.md.bdf26bdf.lean.js" index 6c5642a7..060aaf58 100644 --- "a/assets/shoot_\345\237\272\347\241\200\346\246\202\345\277\265_ISO\346\204\237\345\205\211\345\272\246.md.9142d6ab.lean.js" +++ "b/assets/shoot_\345\237\272\347\241\200\346\246\202\345\277\265_ISO\346\204\237\345\205\211\345\272\246.md.bdf26bdf.lean.js" @@ -1 +1 @@ -import{_ as t,o as a,c as o,k as e,a as s}from"./chunks/framework.b6910bb2.js";const S=JSON.parse('{"title":"ISO 感光度","description":"","frontmatter":{},"headers":[],"relativePath":"shoot/基础概念/ISO感光度.md","filePath":"shoot/基础概念/ISO感光度.md","lastUpdated":1718173557000}'),n={name:"shoot/基础概念/ISO感光度.md"},r=e("h1",{id:"iso-感光度",tabindex:"-1"},[s("ISO 感光度 "),e("a",{class:"header-anchor",href:"#iso-感光度","aria-label":'Permalink to "ISO 感光度"'},"​")],-1),c=e("p",null,"传感器对光线的敏感程度",-1),l=e("ul",null,[e("li",null,"感光度越大、图片越亮,但也容易出现噪点")],-1),_=[r,c,l];function d(i,h,p,m,f,u){return a(),o("div",null,_)}const I=t(n,[["render",d]]);export{S as __pageData,I as default}; +import{_ as t,o as a,c as o,k as e,a as s}from"./chunks/framework.b6910bb2.js";const S=JSON.parse('{"title":"ISO 感光度","description":"","frontmatter":{},"headers":[],"relativePath":"shoot/基础概念/ISO感光度.md","filePath":"shoot/基础概念/ISO感光度.md","lastUpdated":1718174182000}'),n={name:"shoot/基础概念/ISO感光度.md"},r=e("h1",{id:"iso-感光度",tabindex:"-1"},[s("ISO 感光度 "),e("a",{class:"header-anchor",href:"#iso-感光度","aria-label":'Permalink to "ISO 感光度"'},"​")],-1),c=e("p",null,"传感器对光线的敏感程度",-1),l=e("ul",null,[e("li",null,"感光度越大、图片越亮,但也容易出现噪点")],-1),_=[r,c,l];function d(i,h,p,m,f,u){return a(),o("div",null,_)}const I=t(n,[["render",d]]);export{S as __pageData,I as default}; diff --git "a/assets/shoot_\345\237\272\347\241\200\346\246\202\345\277\265_\345\205\211\345\234\210.md.ff2db10b.js" "b/assets/shoot_\345\237\272\347\241\200\346\246\202\345\277\265_\345\205\211\345\234\210.md.25a49ca0.js" similarity index 92% rename from "assets/shoot_\345\237\272\347\241\200\346\246\202\345\277\265_\345\205\211\345\234\210.md.ff2db10b.js" rename to "assets/shoot_\345\237\272\347\241\200\346\246\202\345\277\265_\345\205\211\345\234\210.md.25a49ca0.js" index 35afdc59..6c1f637a 100644 --- "a/assets/shoot_\345\237\272\347\241\200\346\246\202\345\277\265_\345\205\211\345\234\210.md.ff2db10b.js" +++ "b/assets/shoot_\345\237\272\347\241\200\346\246\202\345\277\265_\345\205\211\345\234\210.md.25a49ca0.js" @@ -1 +1 @@ -import{_ as t,o as a,c as o,k as e,a as s}from"./chunks/framework.b6910bb2.js";const k=JSON.parse('{"title":"光圈","description":"","frontmatter":{},"headers":[],"relativePath":"shoot/基础概念/光圈.md","filePath":"shoot/基础概念/光圈.md","lastUpdated":1718173557000}'),n={name:"shoot/基础概念/光圈.md"},l=e("h1",{id:"光圈",tabindex:"-1"},[s("光圈 "),e("a",{class:"header-anchor",href:"#光圈","aria-label":'Permalink to "光圈"'},"​")],-1),r=e("p",null,"控制光圈大小",-1),c=e("ol",null,[e("li",null,"数字越大、光圈越小就越暗 - 图像越清晰"),e("li",null,"数字越小、光圈越大就越亮 - 光圈过大虚化效果明显")],-1),d=[l,r,c];function _(i,h,p,m,f,u){return a(),o("div",null,d)}const $=t(n,[["render",_]]);export{k as __pageData,$ as default}; +import{_ as t,o as a,c as o,k as e,a as s}from"./chunks/framework.b6910bb2.js";const k=JSON.parse('{"title":"光圈","description":"","frontmatter":{},"headers":[],"relativePath":"shoot/基础概念/光圈.md","filePath":"shoot/基础概念/光圈.md","lastUpdated":1718174182000}'),n={name:"shoot/基础概念/光圈.md"},l=e("h1",{id:"光圈",tabindex:"-1"},[s("光圈 "),e("a",{class:"header-anchor",href:"#光圈","aria-label":'Permalink to "光圈"'},"​")],-1),r=e("p",null,"控制光圈大小",-1),c=e("ol",null,[e("li",null,"数字越大、光圈越小就越暗 - 图像越清晰"),e("li",null,"数字越小、光圈越大就越亮 - 光圈过大虚化效果明显")],-1),d=[l,r,c];function _(i,h,p,m,f,u){return a(),o("div",null,d)}const $=t(n,[["render",_]]);export{k as __pageData,$ as default}; diff --git "a/assets/shoot_\345\237\272\347\241\200\346\246\202\345\277\265_\345\205\211\345\234\210.md.ff2db10b.lean.js" "b/assets/shoot_\345\237\272\347\241\200\346\246\202\345\277\265_\345\205\211\345\234\210.md.25a49ca0.lean.js" similarity index 92% rename from "assets/shoot_\345\237\272\347\241\200\346\246\202\345\277\265_\345\205\211\345\234\210.md.ff2db10b.lean.js" rename to "assets/shoot_\345\237\272\347\241\200\346\246\202\345\277\265_\345\205\211\345\234\210.md.25a49ca0.lean.js" index 35afdc59..6c1f637a 100644 --- "a/assets/shoot_\345\237\272\347\241\200\346\246\202\345\277\265_\345\205\211\345\234\210.md.ff2db10b.lean.js" +++ "b/assets/shoot_\345\237\272\347\241\200\346\246\202\345\277\265_\345\205\211\345\234\210.md.25a49ca0.lean.js" @@ -1 +1 @@ -import{_ as t,o as a,c as o,k as e,a as s}from"./chunks/framework.b6910bb2.js";const k=JSON.parse('{"title":"光圈","description":"","frontmatter":{},"headers":[],"relativePath":"shoot/基础概念/光圈.md","filePath":"shoot/基础概念/光圈.md","lastUpdated":1718173557000}'),n={name:"shoot/基础概念/光圈.md"},l=e("h1",{id:"光圈",tabindex:"-1"},[s("光圈 "),e("a",{class:"header-anchor",href:"#光圈","aria-label":'Permalink to "光圈"'},"​")],-1),r=e("p",null,"控制光圈大小",-1),c=e("ol",null,[e("li",null,"数字越大、光圈越小就越暗 - 图像越清晰"),e("li",null,"数字越小、光圈越大就越亮 - 光圈过大虚化效果明显")],-1),d=[l,r,c];function _(i,h,p,m,f,u){return a(),o("div",null,d)}const $=t(n,[["render",_]]);export{k as __pageData,$ as default}; +import{_ as t,o as a,c as o,k as e,a as s}from"./chunks/framework.b6910bb2.js";const k=JSON.parse('{"title":"光圈","description":"","frontmatter":{},"headers":[],"relativePath":"shoot/基础概念/光圈.md","filePath":"shoot/基础概念/光圈.md","lastUpdated":1718174182000}'),n={name:"shoot/基础概念/光圈.md"},l=e("h1",{id:"光圈",tabindex:"-1"},[s("光圈 "),e("a",{class:"header-anchor",href:"#光圈","aria-label":'Permalink to "光圈"'},"​")],-1),r=e("p",null,"控制光圈大小",-1),c=e("ol",null,[e("li",null,"数字越大、光圈越小就越暗 - 图像越清晰"),e("li",null,"数字越小、光圈越大就越亮 - 光圈过大虚化效果明显")],-1),d=[l,r,c];function _(i,h,p,m,f,u){return a(),o("div",null,d)}const $=t(n,[["render",_]]);export{k as __pageData,$ as default}; diff --git "a/assets/shoot_\345\237\272\347\241\200\346\246\202\345\277\265_\345\277\253\351\227\250\351\200\237\345\272\246.md.1a25ab06.js" "b/assets/shoot_\345\237\272\347\241\200\346\246\202\345\277\265_\345\277\253\351\227\250\351\200\237\345\272\246.md.dc196df4.js" similarity index 93% rename from "assets/shoot_\345\237\272\347\241\200\346\246\202\345\277\265_\345\277\253\351\227\250\351\200\237\345\272\246.md.1a25ab06.js" rename to "assets/shoot_\345\237\272\347\241\200\346\246\202\345\277\265_\345\277\253\351\227\250\351\200\237\345\272\246.md.dc196df4.js" index 70f8613d..d94bd05c 100644 --- "a/assets/shoot_\345\237\272\347\241\200\346\246\202\345\277\265_\345\277\253\351\227\250\351\200\237\345\272\246.md.1a25ab06.js" +++ "b/assets/shoot_\345\237\272\347\241\200\346\246\202\345\277\265_\345\277\253\351\227\250\351\200\237\345\272\246.md.dc196df4.js" @@ -1 +1 @@ -import{_ as a,o as s,c as o,k as e,a as t}from"./chunks/framework.b6910bb2.js";const l="/vitePress-blob/assets/1.2aa2aedd.png",k=JSON.parse('{"title":"快门速度","description":"","frontmatter":{},"headers":[],"relativePath":"shoot/基础概念/快门速度.md","filePath":"shoot/基础概念/快门速度.md","lastUpdated":1718173557000}'),n={name:"shoot/基础概念/快门速度.md"},r=e("h1",{id:"快门速度",tabindex:"-1"},[t("快门速度 "),e("a",{class:"header-anchor",href:"#快门速度","aria-label":'Permalink to "快门速度"'},"​")],-1),c=e("p",null,"控制开启传感器的时间",-1),i=e("ul",null,[e("li",null,"快门速度越短,越能凝固物体,常用在抓拍"),e("li",null,[t("快门速度越长,容易得到拖影的图 "),e("ul",null,[e("li",null,[e("img",{src:l,alt:"快门速度"})]),e("li",null,"拍静止的水面 (一般需要借助三脚架)")])])],-1),_=[r,c,i];function d(h,p,u,m,f,x){return s(),o("div",null,_)}const P=a(n,[["render",d]]);export{k as __pageData,P as default}; +import{_ as a,o as s,c as o,k as e,a as t}from"./chunks/framework.b6910bb2.js";const l="/vitePress-blob/assets/1.2aa2aedd.png",k=JSON.parse('{"title":"快门速度","description":"","frontmatter":{},"headers":[],"relativePath":"shoot/基础概念/快门速度.md","filePath":"shoot/基础概念/快门速度.md","lastUpdated":1718174182000}'),n={name:"shoot/基础概念/快门速度.md"},r=e("h1",{id:"快门速度",tabindex:"-1"},[t("快门速度 "),e("a",{class:"header-anchor",href:"#快门速度","aria-label":'Permalink to "快门速度"'},"​")],-1),c=e("p",null,"控制开启传感器的时间",-1),i=e("ul",null,[e("li",null,"快门速度越短,越能凝固物体,常用在抓拍"),e("li",null,[t("快门速度越长,容易得到拖影的图 "),e("ul",null,[e("li",null,[e("img",{src:l,alt:"快门速度"})]),e("li",null,"拍静止的水面 (一般需要借助三脚架)")])])],-1),_=[r,c,i];function d(h,p,u,m,f,x){return s(),o("div",null,_)}const P=a(n,[["render",d]]);export{k as __pageData,P as default}; diff --git "a/assets/shoot_\345\237\272\347\241\200\346\246\202\345\277\265_\345\277\253\351\227\250\351\200\237\345\272\246.md.1a25ab06.lean.js" "b/assets/shoot_\345\237\272\347\241\200\346\246\202\345\277\265_\345\277\253\351\227\250\351\200\237\345\272\246.md.dc196df4.lean.js" similarity index 93% rename from "assets/shoot_\345\237\272\347\241\200\346\246\202\345\277\265_\345\277\253\351\227\250\351\200\237\345\272\246.md.1a25ab06.lean.js" rename to "assets/shoot_\345\237\272\347\241\200\346\246\202\345\277\265_\345\277\253\351\227\250\351\200\237\345\272\246.md.dc196df4.lean.js" index 70f8613d..d94bd05c 100644 --- "a/assets/shoot_\345\237\272\347\241\200\346\246\202\345\277\265_\345\277\253\351\227\250\351\200\237\345\272\246.md.1a25ab06.lean.js" +++ "b/assets/shoot_\345\237\272\347\241\200\346\246\202\345\277\265_\345\277\253\351\227\250\351\200\237\345\272\246.md.dc196df4.lean.js" @@ -1 +1 @@ -import{_ as a,o as s,c as o,k as e,a as t}from"./chunks/framework.b6910bb2.js";const l="/vitePress-blob/assets/1.2aa2aedd.png",k=JSON.parse('{"title":"快门速度","description":"","frontmatter":{},"headers":[],"relativePath":"shoot/基础概念/快门速度.md","filePath":"shoot/基础概念/快门速度.md","lastUpdated":1718173557000}'),n={name:"shoot/基础概念/快门速度.md"},r=e("h1",{id:"快门速度",tabindex:"-1"},[t("快门速度 "),e("a",{class:"header-anchor",href:"#快门速度","aria-label":'Permalink to "快门速度"'},"​")],-1),c=e("p",null,"控制开启传感器的时间",-1),i=e("ul",null,[e("li",null,"快门速度越短,越能凝固物体,常用在抓拍"),e("li",null,[t("快门速度越长,容易得到拖影的图 "),e("ul",null,[e("li",null,[e("img",{src:l,alt:"快门速度"})]),e("li",null,"拍静止的水面 (一般需要借助三脚架)")])])],-1),_=[r,c,i];function d(h,p,u,m,f,x){return s(),o("div",null,_)}const P=a(n,[["render",d]]);export{k as __pageData,P as default}; +import{_ as a,o as s,c as o,k as e,a as t}from"./chunks/framework.b6910bb2.js";const l="/vitePress-blob/assets/1.2aa2aedd.png",k=JSON.parse('{"title":"快门速度","description":"","frontmatter":{},"headers":[],"relativePath":"shoot/基础概念/快门速度.md","filePath":"shoot/基础概念/快门速度.md","lastUpdated":1718174182000}'),n={name:"shoot/基础概念/快门速度.md"},r=e("h1",{id:"快门速度",tabindex:"-1"},[t("快门速度 "),e("a",{class:"header-anchor",href:"#快门速度","aria-label":'Permalink to "快门速度"'},"​")],-1),c=e("p",null,"控制开启传感器的时间",-1),i=e("ul",null,[e("li",null,"快门速度越短,越能凝固物体,常用在抓拍"),e("li",null,[t("快门速度越长,容易得到拖影的图 "),e("ul",null,[e("li",null,[e("img",{src:l,alt:"快门速度"})]),e("li",null,"拍静止的水面 (一般需要借助三脚架)")])])],-1),_=[r,c,i];function d(h,p,u,m,f,x){return s(),o("div",null,_)}const P=a(n,[["render",d]]);export{k as __pageData,P as default}; diff --git "a/assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_index.md.cc1925d6.js" "b/assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_index.md.a00862a6.js" similarity index 92% rename from "assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_index.md.cc1925d6.js" rename to "assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_index.md.a00862a6.js" index 6e58a1a0..80f459f0 100644 --- "a/assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_index.md.cc1925d6.js" +++ "b/assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_index.md.a00862a6.js" @@ -1 +1 @@ -import{_ as a,o as t,c as o,k as e,a as s}from"./chunks/framework.b6910bb2.js";const x=JSON.parse('{"title":"参考文章","description":"","frontmatter":{},"headers":[],"relativePath":"shoot/实战技巧/index.md","filePath":"shoot/实战技巧/index.md","lastUpdated":1718173557000}'),r={name:"shoot/实战技巧/index.md"},i=e("h1",{id:"参考文章",tabindex:"-1"},[s("参考文章 "),e("a",{class:"header-anchor",href:"#参考文章","aria-label":'Permalink to "参考文章"'},"​")],-1),c=e("ol",null,[e("li",null,[e("a",{href:"https://www.bilibili.com/video/BV1x4411F7bs?p=13&vd_source=3ede5fc64ebab3ac5654a5b43523a9b2",target:"_blank",rel:"noreferrer"},"https://www.bilibili.com/video/BV1x4411F7bs?p=13&vd_source=3ede5fc64ebab3ac5654a5b43523a9b2")])],-1),d=[i,c];function n(l,_,b,h,p,f){return t(),o("div",null,d)}const u=a(r,[["render",n]]);export{x as __pageData,u as default}; +import{_ as a,o as t,c as o,k as e,a as s}from"./chunks/framework.b6910bb2.js";const x=JSON.parse('{"title":"参考文章","description":"","frontmatter":{},"headers":[],"relativePath":"shoot/实战技巧/index.md","filePath":"shoot/实战技巧/index.md","lastUpdated":1718174182000}'),r={name:"shoot/实战技巧/index.md"},i=e("h1",{id:"参考文章",tabindex:"-1"},[s("参考文章 "),e("a",{class:"header-anchor",href:"#参考文章","aria-label":'Permalink to "参考文章"'},"​")],-1),c=e("ol",null,[e("li",null,[e("a",{href:"https://www.bilibili.com/video/BV1x4411F7bs?p=13&vd_source=3ede5fc64ebab3ac5654a5b43523a9b2",target:"_blank",rel:"noreferrer"},"https://www.bilibili.com/video/BV1x4411F7bs?p=13&vd_source=3ede5fc64ebab3ac5654a5b43523a9b2")])],-1),d=[i,c];function n(l,_,b,h,p,f){return t(),o("div",null,d)}const u=a(r,[["render",n]]);export{x as __pageData,u as default}; diff --git "a/assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_index.md.cc1925d6.lean.js" "b/assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_index.md.a00862a6.lean.js" similarity index 92% rename from "assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_index.md.cc1925d6.lean.js" rename to "assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_index.md.a00862a6.lean.js" index 6e58a1a0..80f459f0 100644 --- "a/assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_index.md.cc1925d6.lean.js" +++ "b/assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_index.md.a00862a6.lean.js" @@ -1 +1 @@ -import{_ as a,o as t,c as o,k as e,a as s}from"./chunks/framework.b6910bb2.js";const x=JSON.parse('{"title":"参考文章","description":"","frontmatter":{},"headers":[],"relativePath":"shoot/实战技巧/index.md","filePath":"shoot/实战技巧/index.md","lastUpdated":1718173557000}'),r={name:"shoot/实战技巧/index.md"},i=e("h1",{id:"参考文章",tabindex:"-1"},[s("参考文章 "),e("a",{class:"header-anchor",href:"#参考文章","aria-label":'Permalink to "参考文章"'},"​")],-1),c=e("ol",null,[e("li",null,[e("a",{href:"https://www.bilibili.com/video/BV1x4411F7bs?p=13&vd_source=3ede5fc64ebab3ac5654a5b43523a9b2",target:"_blank",rel:"noreferrer"},"https://www.bilibili.com/video/BV1x4411F7bs?p=13&vd_source=3ede5fc64ebab3ac5654a5b43523a9b2")])],-1),d=[i,c];function n(l,_,b,h,p,f){return t(),o("div",null,d)}const u=a(r,[["render",n]]);export{x as __pageData,u as default}; +import{_ as a,o as t,c as o,k as e,a as s}from"./chunks/framework.b6910bb2.js";const x=JSON.parse('{"title":"参考文章","description":"","frontmatter":{},"headers":[],"relativePath":"shoot/实战技巧/index.md","filePath":"shoot/实战技巧/index.md","lastUpdated":1718174182000}'),r={name:"shoot/实战技巧/index.md"},i=e("h1",{id:"参考文章",tabindex:"-1"},[s("参考文章 "),e("a",{class:"header-anchor",href:"#参考文章","aria-label":'Permalink to "参考文章"'},"​")],-1),c=e("ol",null,[e("li",null,[e("a",{href:"https://www.bilibili.com/video/BV1x4411F7bs?p=13&vd_source=3ede5fc64ebab3ac5654a5b43523a9b2",target:"_blank",rel:"noreferrer"},"https://www.bilibili.com/video/BV1x4411F7bs?p=13&vd_source=3ede5fc64ebab3ac5654a5b43523a9b2")])],-1),d=[i,c];function n(l,_,b,h,p,f){return t(),o("div",null,d)}const u=a(r,[["render",n]]);export{x as __pageData,u as default}; diff --git "a/assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\344\272\256\350\260\203\344\272\272\345\203\217.md.bfb2f833.js" "b/assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\344\272\256\350\260\203\344\272\272\345\203\217.md.c68e12f4.js" similarity index 94% rename from "assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\344\272\256\350\260\203\344\272\272\345\203\217.md.bfb2f833.js" rename to "assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\344\272\256\350\260\203\344\272\272\345\203\217.md.c68e12f4.js" index 1943359e..df9abed3 100644 --- "a/assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\344\272\256\350\260\203\344\272\272\345\203\217.md.bfb2f833.js" +++ "b/assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\344\272\256\350\260\203\344\272\272\345\203\217.md.c68e12f4.js" @@ -1 +1 @@ -import{_ as a,o as e,c as t,Q as o}from"./chunks/framework.b6910bb2.js";const f=JSON.parse('{"title":"亮调人像","description":"","frontmatter":{},"headers":[],"relativePath":"shoot/实战技巧/亮调人像.md","filePath":"shoot/实战技巧/亮调人像.md","lastUpdated":1718173557000}'),l={name:"shoot/实战技巧/亮调人像.md"},r=o('

亮调人像

百分之 70 都是浅色系

前置

  1. 背景是浅色
  2. 人物衣服也是浅色

如何拍摄

  1. 评价测光
  2. 可适当增加曝光补偿
',6),i=[r];function s(_,n,c,d,h,p){return e(),t("div",null,i)}const u=a(l,[["render",s]]);export{f as __pageData,u as default}; +import{_ as a,o as e,c as t,Q as o}from"./chunks/framework.b6910bb2.js";const f=JSON.parse('{"title":"亮调人像","description":"","frontmatter":{},"headers":[],"relativePath":"shoot/实战技巧/亮调人像.md","filePath":"shoot/实战技巧/亮调人像.md","lastUpdated":1718174182000}'),l={name:"shoot/实战技巧/亮调人像.md"},r=o('

亮调人像

百分之 70 都是浅色系

前置

  1. 背景是浅色
  2. 人物衣服也是浅色

如何拍摄

  1. 评价测光
  2. 可适当增加曝光补偿
',6),i=[r];function s(_,n,c,d,h,p){return e(),t("div",null,i)}const u=a(l,[["render",s]]);export{f as __pageData,u as default}; diff --git "a/assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\344\272\256\350\260\203\344\272\272\345\203\217.md.bfb2f833.lean.js" "b/assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\344\272\256\350\260\203\344\272\272\345\203\217.md.c68e12f4.lean.js" similarity index 86% rename from "assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\344\272\256\350\260\203\344\272\272\345\203\217.md.bfb2f833.lean.js" rename to "assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\344\272\256\350\260\203\344\272\272\345\203\217.md.c68e12f4.lean.js" index ca9f96e7..b34a8bb8 100644 --- "a/assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\344\272\256\350\260\203\344\272\272\345\203\217.md.bfb2f833.lean.js" +++ "b/assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\344\272\256\350\260\203\344\272\272\345\203\217.md.c68e12f4.lean.js" @@ -1 +1 @@ -import{_ as a,o as e,c as t,Q as o}from"./chunks/framework.b6910bb2.js";const f=JSON.parse('{"title":"亮调人像","description":"","frontmatter":{},"headers":[],"relativePath":"shoot/实战技巧/亮调人像.md","filePath":"shoot/实战技巧/亮调人像.md","lastUpdated":1718173557000}'),l={name:"shoot/实战技巧/亮调人像.md"},r=o("",6),i=[r];function s(_,n,c,d,h,p){return e(),t("div",null,i)}const u=a(l,[["render",s]]);export{f as __pageData,u as default}; +import{_ as a,o as e,c as t,Q as o}from"./chunks/framework.b6910bb2.js";const f=JSON.parse('{"title":"亮调人像","description":"","frontmatter":{},"headers":[],"relativePath":"shoot/实战技巧/亮调人像.md","filePath":"shoot/实战技巧/亮调人像.md","lastUpdated":1718174182000}'),l={name:"shoot/实战技巧/亮调人像.md"},r=o("",6),i=[r];function s(_,n,c,d,h,p){return e(),t("div",null,i)}const u=a(l,[["render",s]]);export{f as __pageData,u as default}; diff --git "a/assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\345\206\267\346\232\226\345\257\271\346\257\224\344\272\272\345\203\217.md.9a713713.js" "b/assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\345\206\267\346\232\226\345\257\271\346\257\224\344\272\272\345\203\217.md.c1cc2cbc.js" similarity index 94% rename from "assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\345\206\267\346\232\226\345\257\271\346\257\224\344\272\272\345\203\217.md.9a713713.js" rename to "assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\345\206\267\346\232\226\345\257\271\346\257\224\344\272\272\345\203\217.md.c1cc2cbc.js" index fe50452d..9a75d8fa 100644 --- "a/assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\345\206\267\346\232\226\345\257\271\346\257\224\344\272\272\345\203\217.md.9a713713.js" +++ "b/assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\345\206\267\346\232\226\345\257\271\346\257\224\344\272\272\345\203\217.md.c1cc2cbc.js" @@ -1 +1 @@ -import{_ as a,o as e,c as t,Q as o}from"./chunks/framework.b6910bb2.js";const f=JSON.parse('{"title":"冷暖对比人像","description":"","frontmatter":{},"headers":[],"relativePath":"shoot/实战技巧/冷暖对比人像.md","filePath":"shoot/实战技巧/冷暖对比人像.md","lastUpdated":1718173557000}'),l={name:"shoot/实战技巧/冷暖对比人像.md"},r=o('

冷暖对比人像

人物和背景冷暖色系不同

场景

  1. 蓝调时刻 - 太阳刚落山

如何拍摄

  1. 暖色 - 可以通过补光灯
  2. 色温 - 3500 - 4000k
  3. 白平衡 - b2m2
',6),i=[r];function _(s,n,c,d,h,p){return e(),t("div",null,i)}const u=a(l,[["render",_]]);export{f as __pageData,u as default}; +import{_ as a,o as e,c as t,Q as o}from"./chunks/framework.b6910bb2.js";const f=JSON.parse('{"title":"冷暖对比人像","description":"","frontmatter":{},"headers":[],"relativePath":"shoot/实战技巧/冷暖对比人像.md","filePath":"shoot/实战技巧/冷暖对比人像.md","lastUpdated":1718174182000}'),l={name:"shoot/实战技巧/冷暖对比人像.md"},r=o('

冷暖对比人像

人物和背景冷暖色系不同

场景

  1. 蓝调时刻 - 太阳刚落山

如何拍摄

  1. 暖色 - 可以通过补光灯
  2. 色温 - 3500 - 4000k
  3. 白平衡 - b2m2
',6),i=[r];function _(s,n,c,d,h,p){return e(),t("div",null,i)}const u=a(l,[["render",_]]);export{f as __pageData,u as default}; diff --git "a/assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\345\206\267\346\232\226\345\257\271\346\257\224\344\272\272\345\203\217.md.9a713713.lean.js" "b/assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\345\206\267\346\232\226\345\257\271\346\257\224\344\272\272\345\203\217.md.c1cc2cbc.lean.js" similarity index 87% rename from "assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\345\206\267\346\232\226\345\257\271\346\257\224\344\272\272\345\203\217.md.9a713713.lean.js" rename to "assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\345\206\267\346\232\226\345\257\271\346\257\224\344\272\272\345\203\217.md.c1cc2cbc.lean.js" index 1084bb44..c52076f3 100644 --- "a/assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\345\206\267\346\232\226\345\257\271\346\257\224\344\272\272\345\203\217.md.9a713713.lean.js" +++ "b/assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\345\206\267\346\232\226\345\257\271\346\257\224\344\272\272\345\203\217.md.c1cc2cbc.lean.js" @@ -1 +1 @@ -import{_ as a,o as e,c as t,Q as o}from"./chunks/framework.b6910bb2.js";const f=JSON.parse('{"title":"冷暖对比人像","description":"","frontmatter":{},"headers":[],"relativePath":"shoot/实战技巧/冷暖对比人像.md","filePath":"shoot/实战技巧/冷暖对比人像.md","lastUpdated":1718173557000}'),l={name:"shoot/实战技巧/冷暖对比人像.md"},r=o("",6),i=[r];function _(s,n,c,d,h,p){return e(),t("div",null,i)}const u=a(l,[["render",_]]);export{f as __pageData,u as default}; +import{_ as a,o as e,c as t,Q as o}from"./chunks/framework.b6910bb2.js";const f=JSON.parse('{"title":"冷暖对比人像","description":"","frontmatter":{},"headers":[],"relativePath":"shoot/实战技巧/冷暖对比人像.md","filePath":"shoot/实战技巧/冷暖对比人像.md","lastUpdated":1718174182000}'),l={name:"shoot/实战技巧/冷暖对比人像.md"},r=o("",6),i=[r];function _(s,n,c,d,h,p){return e(),t("div",null,i)}const u=a(l,[["render",_]]);export{f as __pageData,u as default}; diff --git "a/assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\345\246\202\344\275\225\346\213\215\350\212\261\347\232\204\351\273\221\350\203\214\346\231\257.md.4e78f8b6.js" "b/assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\345\246\202\344\275\225\346\213\215\350\212\261\347\232\204\351\273\221\350\203\214\346\231\257.md.1b7e842b.js" similarity index 93% rename from "assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\345\246\202\344\275\225\346\213\215\350\212\261\347\232\204\351\273\221\350\203\214\346\231\257.md.4e78f8b6.js" rename to "assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\345\246\202\344\275\225\346\213\215\350\212\261\347\232\204\351\273\221\350\203\214\346\231\257.md.1b7e842b.js" index e9e9db50..9a44908a 100644 --- "a/assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\345\246\202\344\275\225\346\213\215\350\212\261\347\232\204\351\273\221\350\203\214\346\231\257.md.4e78f8b6.js" +++ "b/assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\345\246\202\344\275\225\346\213\215\350\212\261\347\232\204\351\273\221\350\203\214\346\231\257.md.1b7e842b.js" @@ -1 +1 @@ -import{_ as t,o,c as s,k as e,a}from"./chunks/framework.b6910bb2.js";const k=JSON.parse('{"title":"如何拍花","description":"","frontmatter":{},"headers":[],"relativePath":"shoot/实战技巧/如何拍花的黑背景.md","filePath":"shoot/实战技巧/如何拍花的黑背景.md","lastUpdated":1718173557000}'),l={name:"shoot/实战技巧/如何拍花的黑背景.md"},n=e("h1",{id:"如何拍花",tabindex:"-1"},[a("如何拍花 "),e("a",{class:"header-anchor",href:"#如何拍花","aria-label":'Permalink to "如何拍花"'},"​")],-1),r=e("h2",{id:"如何拍摄",tabindex:"-1"},[a("如何拍摄 "),e("a",{class:"header-anchor",href:"#如何拍摄","aria-label":'Permalink to "如何拍摄"'},"​")],-1),c=e("ol",null,[e("li",null,[a("采用 "),e("code",null,"点测光"),a(" 突出花的亮度")]),e("li",null,[a("背景采用 "),e("code",null,"深色系"),a(" 突出主体")])],-1),_=[n,r,c];function d(i,h,p,m,f,u){return o(),s("div",null,_)}const b=t(l,[["render",d]]);export{k as __pageData,b as default}; +import{_ as t,o,c as s,k as e,a}from"./chunks/framework.b6910bb2.js";const k=JSON.parse('{"title":"如何拍花","description":"","frontmatter":{},"headers":[],"relativePath":"shoot/实战技巧/如何拍花的黑背景.md","filePath":"shoot/实战技巧/如何拍花的黑背景.md","lastUpdated":1718174182000}'),l={name:"shoot/实战技巧/如何拍花的黑背景.md"},n=e("h1",{id:"如何拍花",tabindex:"-1"},[a("如何拍花 "),e("a",{class:"header-anchor",href:"#如何拍花","aria-label":'Permalink to "如何拍花"'},"​")],-1),r=e("h2",{id:"如何拍摄",tabindex:"-1"},[a("如何拍摄 "),e("a",{class:"header-anchor",href:"#如何拍摄","aria-label":'Permalink to "如何拍摄"'},"​")],-1),c=e("ol",null,[e("li",null,[a("采用 "),e("code",null,"点测光"),a(" 突出花的亮度")]),e("li",null,[a("背景采用 "),e("code",null,"深色系"),a(" 突出主体")])],-1),_=[n,r,c];function d(i,h,p,m,f,u){return o(),s("div",null,_)}const b=t(l,[["render",d]]);export{k as __pageData,b as default}; diff --git "a/assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\345\246\202\344\275\225\346\213\215\350\212\261\347\232\204\351\273\221\350\203\214\346\231\257.md.4e78f8b6.lean.js" "b/assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\345\246\202\344\275\225\346\213\215\350\212\261\347\232\204\351\273\221\350\203\214\346\231\257.md.1b7e842b.lean.js" similarity index 93% rename from "assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\345\246\202\344\275\225\346\213\215\350\212\261\347\232\204\351\273\221\350\203\214\346\231\257.md.4e78f8b6.lean.js" rename to "assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\345\246\202\344\275\225\346\213\215\350\212\261\347\232\204\351\273\221\350\203\214\346\231\257.md.1b7e842b.lean.js" index e9e9db50..9a44908a 100644 --- "a/assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\345\246\202\344\275\225\346\213\215\350\212\261\347\232\204\351\273\221\350\203\214\346\231\257.md.4e78f8b6.lean.js" +++ "b/assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\345\246\202\344\275\225\346\213\215\350\212\261\347\232\204\351\273\221\350\203\214\346\231\257.md.1b7e842b.lean.js" @@ -1 +1 @@ -import{_ as t,o,c as s,k as e,a}from"./chunks/framework.b6910bb2.js";const k=JSON.parse('{"title":"如何拍花","description":"","frontmatter":{},"headers":[],"relativePath":"shoot/实战技巧/如何拍花的黑背景.md","filePath":"shoot/实战技巧/如何拍花的黑背景.md","lastUpdated":1718173557000}'),l={name:"shoot/实战技巧/如何拍花的黑背景.md"},n=e("h1",{id:"如何拍花",tabindex:"-1"},[a("如何拍花 "),e("a",{class:"header-anchor",href:"#如何拍花","aria-label":'Permalink to "如何拍花"'},"​")],-1),r=e("h2",{id:"如何拍摄",tabindex:"-1"},[a("如何拍摄 "),e("a",{class:"header-anchor",href:"#如何拍摄","aria-label":'Permalink to "如何拍摄"'},"​")],-1),c=e("ol",null,[e("li",null,[a("采用 "),e("code",null,"点测光"),a(" 突出花的亮度")]),e("li",null,[a("背景采用 "),e("code",null,"深色系"),a(" 突出主体")])],-1),_=[n,r,c];function d(i,h,p,m,f,u){return o(),s("div",null,_)}const b=t(l,[["render",d]]);export{k as __pageData,b as default}; +import{_ as t,o,c as s,k as e,a}from"./chunks/framework.b6910bb2.js";const k=JSON.parse('{"title":"如何拍花","description":"","frontmatter":{},"headers":[],"relativePath":"shoot/实战技巧/如何拍花的黑背景.md","filePath":"shoot/实战技巧/如何拍花的黑背景.md","lastUpdated":1718174182000}'),l={name:"shoot/实战技巧/如何拍花的黑背景.md"},n=e("h1",{id:"如何拍花",tabindex:"-1"},[a("如何拍花 "),e("a",{class:"header-anchor",href:"#如何拍花","aria-label":'Permalink to "如何拍花"'},"​")],-1),r=e("h2",{id:"如何拍摄",tabindex:"-1"},[a("如何拍摄 "),e("a",{class:"header-anchor",href:"#如何拍摄","aria-label":'Permalink to "如何拍摄"'},"​")],-1),c=e("ol",null,[e("li",null,[a("采用 "),e("code",null,"点测光"),a(" 突出花的亮度")]),e("li",null,[a("背景采用 "),e("code",null,"深色系"),a(" 突出主体")])],-1),_=[n,r,c];function d(i,h,p,m,f,u){return o(),s("div",null,_)}const b=t(l,[["render",d]]);export{k as __pageData,b as default}; diff --git "a/assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\345\246\202\344\275\225\346\213\215\351\233\250\344\270\235.md.3892fb19.js" "b/assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\345\246\202\344\275\225\346\213\215\351\233\250\344\270\235.md.97a4b635.js" similarity index 96% rename from "assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\345\246\202\344\275\225\346\213\215\351\233\250\344\270\235.md.3892fb19.js" rename to "assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\345\246\202\344\275\225\346\213\215\351\233\250\344\270\235.md.97a4b635.js" index 1a21c946..f7522bf4 100644 --- "a/assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\345\246\202\344\275\225\346\213\215\351\233\250\344\270\235.md.3892fb19.js" +++ "b/assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\345\246\202\344\275\225\346\213\215\351\233\250\344\270\235.md.97a4b635.js" @@ -1 +1 @@ -import{_ as a,o as e,c as t,Q as o}from"./chunks/framework.b6910bb2.js";const r="/vitePress-blob/assets/1.b55cef29.png",f=JSON.parse('{"title":"如何拍雨丝","description":"","frontmatter":{},"headers":[],"relativePath":"shoot/实战技巧/如何拍雨丝.md","filePath":"shoot/实战技巧/如何拍雨丝.md","lastUpdated":1718173557000}'),i={name:"shoot/实战技巧/如何拍雨丝.md"},l=o('

如何拍雨丝

如何拍摄

灯位要求

需要俩盏灯

  • 逆光灯: 在拍摄物体后方 (容易拍摄到雨丝,而且物体会有光边效果)
  • 正光灯:在拍摄物体前方(避免物体逆光,变黑)

逆光灯亮度 > 主光灯

灯位要求

白平衡

如果拍摄物体偏黄,可以调低白平衡,使物体变白

快门速度

  • 快门速度越慢,雨水成丝
  • 快门速度越快,雨水成点
',11),s=[l];function n(h,_,c,d,p,u){return e(),t("div",null,s)}const b=a(i,[["render",n]]);export{f as __pageData,b as default}; +import{_ as a,o as e,c as t,Q as o}from"./chunks/framework.b6910bb2.js";const r="/vitePress-blob/assets/1.b55cef29.png",f=JSON.parse('{"title":"如何拍雨丝","description":"","frontmatter":{},"headers":[],"relativePath":"shoot/实战技巧/如何拍雨丝.md","filePath":"shoot/实战技巧/如何拍雨丝.md","lastUpdated":1718174182000}'),i={name:"shoot/实战技巧/如何拍雨丝.md"},l=o('

如何拍雨丝

如何拍摄

灯位要求

需要俩盏灯

  • 逆光灯: 在拍摄物体后方 (容易拍摄到雨丝,而且物体会有光边效果)
  • 正光灯:在拍摄物体前方(避免物体逆光,变黑)

逆光灯亮度 > 主光灯

灯位要求

白平衡

如果拍摄物体偏黄,可以调低白平衡,使物体变白

快门速度

  • 快门速度越慢,雨水成丝
  • 快门速度越快,雨水成点
',11),s=[l];function n(h,_,c,d,p,u){return e(),t("div",null,s)}const b=a(i,[["render",n]]);export{f as __pageData,b as default}; diff --git "a/assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\345\246\202\344\275\225\346\213\215\351\233\250\344\270\235.md.3892fb19.lean.js" "b/assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\345\246\202\344\275\225\346\213\215\351\233\250\344\270\235.md.97a4b635.lean.js" similarity index 87% rename from "assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\345\246\202\344\275\225\346\213\215\351\233\250\344\270\235.md.3892fb19.lean.js" rename to "assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\345\246\202\344\275\225\346\213\215\351\233\250\344\270\235.md.97a4b635.lean.js" index 0d7d7836..defa850f 100644 --- "a/assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\345\246\202\344\275\225\346\213\215\351\233\250\344\270\235.md.3892fb19.lean.js" +++ "b/assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\345\246\202\344\275\225\346\213\215\351\233\250\344\270\235.md.97a4b635.lean.js" @@ -1 +1 @@ -import{_ as a,o as e,c as t,Q as o}from"./chunks/framework.b6910bb2.js";const r="/vitePress-blob/assets/1.b55cef29.png",f=JSON.parse('{"title":"如何拍雨丝","description":"","frontmatter":{},"headers":[],"relativePath":"shoot/实战技巧/如何拍雨丝.md","filePath":"shoot/实战技巧/如何拍雨丝.md","lastUpdated":1718173557000}'),i={name:"shoot/实战技巧/如何拍雨丝.md"},l=o("",11),s=[l];function n(h,_,c,d,p,u){return e(),t("div",null,s)}const b=a(i,[["render",n]]);export{f as __pageData,b as default}; +import{_ as a,o as e,c as t,Q as o}from"./chunks/framework.b6910bb2.js";const r="/vitePress-blob/assets/1.b55cef29.png",f=JSON.parse('{"title":"如何拍雨丝","description":"","frontmatter":{},"headers":[],"relativePath":"shoot/实战技巧/如何拍雨丝.md","filePath":"shoot/实战技巧/如何拍雨丝.md","lastUpdated":1718174182000}'),i={name:"shoot/实战技巧/如何拍雨丝.md"},l=o("",11),s=[l];function n(h,_,c,d,p,u){return e(),t("div",null,s)}const b=a(i,[["render",n]]);export{f as __pageData,b as default}; diff --git "a/assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\346\213\215\346\221\204\346\242\246\345\271\273\345\205\211\346\226\221.md.53b8014d.js" "b/assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\346\213\215\346\221\204\346\242\246\345\271\273\345\205\211\346\226\221.md.5cd55bb7.js" similarity index 94% rename from "assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\346\213\215\346\221\204\346\242\246\345\271\273\345\205\211\346\226\221.md.53b8014d.js" rename to "assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\346\213\215\346\221\204\346\242\246\345\271\273\345\205\211\346\226\221.md.5cd55bb7.js" index 268ea5eb..3a445fba 100644 --- "a/assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\346\213\215\346\221\204\346\242\246\345\271\273\345\205\211\346\226\221.md.53b8014d.js" +++ "b/assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\346\213\215\346\221\204\346\242\246\345\271\273\345\205\211\346\226\221.md.5cd55bb7.js" @@ -1 +1 @@ -import{_ as t,o,c as l,k as e,a}from"./chunks/framework.b6910bb2.js";const k=JSON.parse('{"title":"拍摄梦幻光斑","description":"","frontmatter":{},"headers":[],"relativePath":"shoot/实战技巧/拍摄梦幻光斑.md","filePath":"shoot/实战技巧/拍摄梦幻光斑.md","lastUpdated":1718173557000}'),s={name:"shoot/实战技巧/拍摄梦幻光斑.md"},n=e("h1",{id:"拍摄梦幻光斑",tabindex:"-1"},[a("拍摄梦幻光斑 "),e("a",{class:"header-anchor",href:"#拍摄梦幻光斑","aria-label":'Permalink to "拍摄梦幻光斑"'},"​")],-1),r=e("h2",{id:"如何拍摄",tabindex:"-1"},[a("如何拍摄 "),e("a",{class:"header-anchor",href:"#如何拍摄","aria-label":'Permalink to "如何拍摄"'},"​")],-1),i=e("ul",null,[e("li",null,"采用大光圈镜头,有很好的背景虚化效果"),e("li",null,[a("需要一个补光灯,减少避免人物逆光导致过黑 "),e("ul",null,[e("li",null,"拍摄物体在光斑前面"),e("li",null,"对焦到物体上(也可以通过精细对焦,即放大后手动对焦)")])])],-1),c=[n,r,i];function _(d,h,u,p,m,f){return o(),l("div",null,c)}const b=t(s,[["render",_]]);export{k as __pageData,b as default}; +import{_ as t,o,c as l,k as e,a}from"./chunks/framework.b6910bb2.js";const k=JSON.parse('{"title":"拍摄梦幻光斑","description":"","frontmatter":{},"headers":[],"relativePath":"shoot/实战技巧/拍摄梦幻光斑.md","filePath":"shoot/实战技巧/拍摄梦幻光斑.md","lastUpdated":1718174182000}'),s={name:"shoot/实战技巧/拍摄梦幻光斑.md"},n=e("h1",{id:"拍摄梦幻光斑",tabindex:"-1"},[a("拍摄梦幻光斑 "),e("a",{class:"header-anchor",href:"#拍摄梦幻光斑","aria-label":'Permalink to "拍摄梦幻光斑"'},"​")],-1),r=e("h2",{id:"如何拍摄",tabindex:"-1"},[a("如何拍摄 "),e("a",{class:"header-anchor",href:"#如何拍摄","aria-label":'Permalink to "如何拍摄"'},"​")],-1),i=e("ul",null,[e("li",null,"采用大光圈镜头,有很好的背景虚化效果"),e("li",null,[a("需要一个补光灯,减少避免人物逆光导致过黑 "),e("ul",null,[e("li",null,"拍摄物体在光斑前面"),e("li",null,"对焦到物体上(也可以通过精细对焦,即放大后手动对焦)")])])],-1),c=[n,r,i];function _(d,h,u,p,m,f){return o(),l("div",null,c)}const b=t(s,[["render",_]]);export{k as __pageData,b as default}; diff --git "a/assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\346\213\215\346\221\204\346\242\246\345\271\273\345\205\211\346\226\221.md.53b8014d.lean.js" "b/assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\346\213\215\346\221\204\346\242\246\345\271\273\345\205\211\346\226\221.md.5cd55bb7.lean.js" similarity index 94% rename from "assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\346\213\215\346\221\204\346\242\246\345\271\273\345\205\211\346\226\221.md.53b8014d.lean.js" rename to "assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\346\213\215\346\221\204\346\242\246\345\271\273\345\205\211\346\226\221.md.5cd55bb7.lean.js" index 268ea5eb..3a445fba 100644 --- "a/assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\346\213\215\346\221\204\346\242\246\345\271\273\345\205\211\346\226\221.md.53b8014d.lean.js" +++ "b/assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\346\213\215\346\221\204\346\242\246\345\271\273\345\205\211\346\226\221.md.5cd55bb7.lean.js" @@ -1 +1 @@ -import{_ as t,o,c as l,k as e,a}from"./chunks/framework.b6910bb2.js";const k=JSON.parse('{"title":"拍摄梦幻光斑","description":"","frontmatter":{},"headers":[],"relativePath":"shoot/实战技巧/拍摄梦幻光斑.md","filePath":"shoot/实战技巧/拍摄梦幻光斑.md","lastUpdated":1718173557000}'),s={name:"shoot/实战技巧/拍摄梦幻光斑.md"},n=e("h1",{id:"拍摄梦幻光斑",tabindex:"-1"},[a("拍摄梦幻光斑 "),e("a",{class:"header-anchor",href:"#拍摄梦幻光斑","aria-label":'Permalink to "拍摄梦幻光斑"'},"​")],-1),r=e("h2",{id:"如何拍摄",tabindex:"-1"},[a("如何拍摄 "),e("a",{class:"header-anchor",href:"#如何拍摄","aria-label":'Permalink to "如何拍摄"'},"​")],-1),i=e("ul",null,[e("li",null,"采用大光圈镜头,有很好的背景虚化效果"),e("li",null,[a("需要一个补光灯,减少避免人物逆光导致过黑 "),e("ul",null,[e("li",null,"拍摄物体在光斑前面"),e("li",null,"对焦到物体上(也可以通过精细对焦,即放大后手动对焦)")])])],-1),c=[n,r,i];function _(d,h,u,p,m,f){return o(),l("div",null,c)}const b=t(s,[["render",_]]);export{k as __pageData,b as default}; +import{_ as t,o,c as l,k as e,a}from"./chunks/framework.b6910bb2.js";const k=JSON.parse('{"title":"拍摄梦幻光斑","description":"","frontmatter":{},"headers":[],"relativePath":"shoot/实战技巧/拍摄梦幻光斑.md","filePath":"shoot/实战技巧/拍摄梦幻光斑.md","lastUpdated":1718174182000}'),s={name:"shoot/实战技巧/拍摄梦幻光斑.md"},n=e("h1",{id:"拍摄梦幻光斑",tabindex:"-1"},[a("拍摄梦幻光斑 "),e("a",{class:"header-anchor",href:"#拍摄梦幻光斑","aria-label":'Permalink to "拍摄梦幻光斑"'},"​")],-1),r=e("h2",{id:"如何拍摄",tabindex:"-1"},[a("如何拍摄 "),e("a",{class:"header-anchor",href:"#如何拍摄","aria-label":'Permalink to "如何拍摄"'},"​")],-1),i=e("ul",null,[e("li",null,"采用大光圈镜头,有很好的背景虚化效果"),e("li",null,[a("需要一个补光灯,减少避免人物逆光导致过黑 "),e("ul",null,[e("li",null,"拍摄物体在光斑前面"),e("li",null,"对焦到物体上(也可以通过精细对焦,即放大后手动对焦)")])])],-1),c=[n,r,i];function _(d,h,u,p,m,f){return o(),l("div",null,c)}const b=t(s,[["render",_]]);export{k as __pageData,b as default}; diff --git "a/assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\346\232\227\350\260\203\344\272\272\345\203\217.md.ff643be2.js" "b/assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\346\232\227\350\260\203\344\272\272\345\203\217.md.da9ae4b2.js" similarity index 95% rename from "assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\346\232\227\350\260\203\344\272\272\345\203\217.md.ff643be2.js" rename to "assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\346\232\227\350\260\203\344\272\272\345\203\217.md.da9ae4b2.js" index 5e2d1805..a4750a1b 100644 --- "a/assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\346\232\227\350\260\203\344\272\272\345\203\217.md.ff643be2.js" +++ "b/assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\346\232\227\350\260\203\344\272\272\345\203\217.md.da9ae4b2.js" @@ -1 +1 @@ -import{_ as a,o as e,c as t,Q as o}from"./chunks/framework.b6910bb2.js";const f=JSON.parse('{"title":"暗调人像","description":"","frontmatter":{},"headers":[],"relativePath":"shoot/实战技巧/暗调人像.md","filePath":"shoot/实战技巧/暗调人像.md","lastUpdated":1718173557000}'),l={name:"shoot/实战技巧/暗调人像.md"},i=o('

暗调人像

百分之 70 都是黑色的

前置

  1. 背景是黑色
  2. 人物衣服也是黑色

如何拍摄

  1. 点测光人物面部,保证面部光亮
  2. 为了避免人物和背景重合,可以在人物背面打一束光
  3. 如果周围环境还是比较亮,可以减少一两档曝光补偿

参数参考

  • 光圈:f/2.8、曝光时间 1/125、ISO: 1600
',8),r=[i];function s(_,n,h,c,d,u){return e(),t("div",null,r)}const m=a(l,[["render",s]]);export{f as __pageData,m as default}; +import{_ as a,o as e,c as t,Q as o}from"./chunks/framework.b6910bb2.js";const f=JSON.parse('{"title":"暗调人像","description":"","frontmatter":{},"headers":[],"relativePath":"shoot/实战技巧/暗调人像.md","filePath":"shoot/实战技巧/暗调人像.md","lastUpdated":1718174182000}'),l={name:"shoot/实战技巧/暗调人像.md"},i=o('

暗调人像

百分之 70 都是黑色的

前置

  1. 背景是黑色
  2. 人物衣服也是黑色

如何拍摄

  1. 点测光人物面部,保证面部光亮
  2. 为了避免人物和背景重合,可以在人物背面打一束光
  3. 如果周围环境还是比较亮,可以减少一两档曝光补偿

参数参考

  • 光圈:f/2.8、曝光时间 1/125、ISO: 1600
',8),r=[i];function s(_,n,h,c,d,u){return e(),t("div",null,r)}const m=a(l,[["render",s]]);export{f as __pageData,m as default}; diff --git "a/assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\346\232\227\350\260\203\344\272\272\345\203\217.md.ff643be2.lean.js" "b/assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\346\232\227\350\260\203\344\272\272\345\203\217.md.da9ae4b2.lean.js" similarity index 86% rename from "assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\346\232\227\350\260\203\344\272\272\345\203\217.md.ff643be2.lean.js" rename to "assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\346\232\227\350\260\203\344\272\272\345\203\217.md.da9ae4b2.lean.js" index c046d589..ef43b83d 100644 --- "a/assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\346\232\227\350\260\203\344\272\272\345\203\217.md.ff643be2.lean.js" +++ "b/assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\346\232\227\350\260\203\344\272\272\345\203\217.md.da9ae4b2.lean.js" @@ -1 +1 @@ -import{_ as a,o as e,c as t,Q as o}from"./chunks/framework.b6910bb2.js";const f=JSON.parse('{"title":"暗调人像","description":"","frontmatter":{},"headers":[],"relativePath":"shoot/实战技巧/暗调人像.md","filePath":"shoot/实战技巧/暗调人像.md","lastUpdated":1718173557000}'),l={name:"shoot/实战技巧/暗调人像.md"},i=o("",8),r=[i];function s(_,n,h,c,d,u){return e(),t("div",null,r)}const m=a(l,[["render",s]]);export{f as __pageData,m as default}; +import{_ as a,o as e,c as t,Q as o}from"./chunks/framework.b6910bb2.js";const f=JSON.parse('{"title":"暗调人像","description":"","frontmatter":{},"headers":[],"relativePath":"shoot/实战技巧/暗调人像.md","filePath":"shoot/实战技巧/暗调人像.md","lastUpdated":1718174182000}'),l={name:"shoot/实战技巧/暗调人像.md"},i=o("",8),r=[i];function s(_,n,h,c,d,u){return e(),t("div",null,r)}const m=a(l,[["render",s]]);export{f as __pageData,m as default}; diff --git "a/assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\351\200\206\345\205\211\344\272\272\345\203\217.md.294aa0a7.js" "b/assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\351\200\206\345\205\211\344\272\272\345\203\217.md.8e2d1ea7.js" similarity index 95% rename from "assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\351\200\206\345\205\211\344\272\272\345\203\217.md.294aa0a7.js" rename to "assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\351\200\206\345\205\211\344\272\272\345\203\217.md.8e2d1ea7.js" index 73d30454..88fc19cc 100644 --- "a/assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\351\200\206\345\205\211\344\272\272\345\203\217.md.294aa0a7.js" +++ "b/assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\351\200\206\345\205\211\344\272\272\345\203\217.md.8e2d1ea7.js" @@ -1 +1 @@ -import{_ as a,o as t,c as e,Q as o}from"./chunks/framework.b6910bb2.js";const s="/vitePress-blob/assets/2.cbd8c2b6.png",u=JSON.parse('{"title":"逆光人像","description":"","frontmatter":{},"headers":[],"relativePath":"shoot/实战技巧/逆光人像.md","filePath":"shoot/实战技巧/逆光人像.md","lastUpdated":1718173557000}'),i={name:"shoot/实战技巧/逆光人像.md"},l=o('

逆光人像

前置

  1. 逆光,光线较好(如夕阳)
  2. 背景建议干净,突出人物

如何拍摄

  1. 采用手动对焦,避免对焦有偏差
  2. 使用点测光,对人物面部最亮部分测光
  3. 前景补光,避免人像面部过暗

灯位要求

',6),r=[l];function _(c,n,d,h,p,m){return t(),e("div",null,r)}const b=a(i,[["render",_]]);export{u as __pageData,b as default}; +import{_ as a,o as t,c as e,Q as o}from"./chunks/framework.b6910bb2.js";const s="/vitePress-blob/assets/2.cbd8c2b6.png",u=JSON.parse('{"title":"逆光人像","description":"","frontmatter":{},"headers":[],"relativePath":"shoot/实战技巧/逆光人像.md","filePath":"shoot/实战技巧/逆光人像.md","lastUpdated":1718174182000}'),i={name:"shoot/实战技巧/逆光人像.md"},l=o('

逆光人像

前置

  1. 逆光,光线较好(如夕阳)
  2. 背景建议干净,突出人物

如何拍摄

  1. 采用手动对焦,避免对焦有偏差
  2. 使用点测光,对人物面部最亮部分测光
  3. 前景补光,避免人像面部过暗

灯位要求

',6),r=[l];function _(c,n,d,h,p,m){return t(),e("div",null,r)}const b=a(i,[["render",_]]);export{u as __pageData,b as default}; diff --git "a/assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\351\200\206\345\205\211\344\272\272\345\203\217.md.294aa0a7.lean.js" "b/assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\351\200\206\345\205\211\344\272\272\345\203\217.md.8e2d1ea7.lean.js" similarity index 87% rename from "assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\351\200\206\345\205\211\344\272\272\345\203\217.md.294aa0a7.lean.js" rename to "assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\351\200\206\345\205\211\344\272\272\345\203\217.md.8e2d1ea7.lean.js" index 231d2c56..cf55e0b5 100644 --- "a/assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\351\200\206\345\205\211\344\272\272\345\203\217.md.294aa0a7.lean.js" +++ "b/assets/shoot_\345\256\236\346\210\230\346\212\200\345\267\247_\351\200\206\345\205\211\344\272\272\345\203\217.md.8e2d1ea7.lean.js" @@ -1 +1 @@ -import{_ as a,o as t,c as e,Q as o}from"./chunks/framework.b6910bb2.js";const s="/vitePress-blob/assets/2.cbd8c2b6.png",u=JSON.parse('{"title":"逆光人像","description":"","frontmatter":{},"headers":[],"relativePath":"shoot/实战技巧/逆光人像.md","filePath":"shoot/实战技巧/逆光人像.md","lastUpdated":1718173557000}'),i={name:"shoot/实战技巧/逆光人像.md"},l=o("",6),r=[l];function _(c,n,d,h,p,m){return t(),e("div",null,r)}const b=a(i,[["render",_]]);export{u as __pageData,b as default}; +import{_ as a,o as t,c as e,Q as o}from"./chunks/framework.b6910bb2.js";const s="/vitePress-blob/assets/2.cbd8c2b6.png",u=JSON.parse('{"title":"逆光人像","description":"","frontmatter":{},"headers":[],"relativePath":"shoot/实战技巧/逆光人像.md","filePath":"shoot/实战技巧/逆光人像.md","lastUpdated":1718174182000}'),i={name:"shoot/实战技巧/逆光人像.md"},l=o("",6),r=[l];function _(c,n,d,h,p,m){return t(),e("div",null,r)}const b=a(i,[["render",_]]);export{u as __pageData,b as default}; diff --git "a/assets/shoot_\346\236\204\345\233\276\345\275\242\345\274\217_\346\236\204\345\233\276\346\212\200\345\267\247.md.d90509e0.js" "b/assets/shoot_\346\236\204\345\233\276\345\275\242\345\274\217_\346\236\204\345\233\276\346\212\200\345\267\247.md.78cc0528.js" similarity index 98% rename from "assets/shoot_\346\236\204\345\233\276\345\275\242\345\274\217_\346\236\204\345\233\276\346\212\200\345\267\247.md.d90509e0.js" rename to "assets/shoot_\346\236\204\345\233\276\345\275\242\345\274\217_\346\236\204\345\233\276\346\212\200\345\267\247.md.78cc0528.js" index 7a4c529e..6831719e 100644 --- "a/assets/shoot_\346\236\204\345\233\276\345\275\242\345\274\217_\346\236\204\345\233\276\346\212\200\345\267\247.md.d90509e0.js" +++ "b/assets/shoot_\346\236\204\345\233\276\345\275\242\345\274\217_\346\236\204\345\233\276\346\212\200\345\267\247.md.78cc0528.js" @@ -1 +1 @@ -import{_ as t,o as a,c as e,Q as s}from"./chunks/framework.b6910bb2.js";const r="/vitePress-blob/assets/2.1e53a7e0.png",o="/vitePress-blob/assets/3.e934bbc6.png",i="/vitePress-blob/assets/4.ec3f3077.png",l="/vitePress-blob/assets/5.4c018a0f.png",n="/vitePress-blob/assets/6.f0091254.png",c="/vitePress-blob/assets/7.3dfb1ea6.png",p="/vitePress-blob/assets/8.4e45aae0.png",h="/vitePress-blob/assets/9.9c5e8ea1.png",_="/vitePress-blob/assets/10.f2b0f532.png",b="/vitePress-blob/assets/11.dce03aa0.png",d="/vitePress-blob/assets/12.d9df251e.png",m="/vitePress-blob/assets/13.677bfe09.png",g="/vitePress-blob/assets/14.3340cffc.png",P="/vitePress-blob/assets/15.58d84e53.png",f="/vitePress-blob/assets/16.7ce6920c.png",B=JSON.parse('{"title":"构图技巧","description":"","frontmatter":{},"headers":[],"relativePath":"shoot/构图形式/构图技巧.md","filePath":"shoot/构图形式/构图技巧.md","lastUpdated":1718173557000}'),u={name:"shoot/构图形式/构图技巧.md"},x=s('

构图技巧

点构图

中心点构图

将主题放在中心,突出主题

中心点构图

中心点构图

三分点构图

三分点构图

alt text

线构图

对称线构图

可以展示对称的秩序感,常用于风光、风光 + 人文 alt text

alt text

alt text

对角线构图

alt text

alt text

引导线构图

充分利用场景中的线条,用于引导观者的注意力落在主体上,并让画面产生深度和透视感 alt text

面构图

前景构图

例如通过树叶、花草、植物等做前景

alt text

框架构图

拍摄中利用框架将主体框起来,突出主体

alt text

alt text

留白构图

留有空白,让画面更加简洁,突出主题

alt text

alt text

',31),q=[x];function v(k,T,S,$,A,N){return a(),e("div",null,q)}const C=t(u,[["render",v]]);export{B as __pageData,C as default}; +import{_ as t,o as a,c as e,Q as s}from"./chunks/framework.b6910bb2.js";const r="/vitePress-blob/assets/2.1e53a7e0.png",o="/vitePress-blob/assets/3.e934bbc6.png",i="/vitePress-blob/assets/4.ec3f3077.png",l="/vitePress-blob/assets/5.4c018a0f.png",n="/vitePress-blob/assets/6.f0091254.png",c="/vitePress-blob/assets/7.3dfb1ea6.png",p="/vitePress-blob/assets/8.4e45aae0.png",h="/vitePress-blob/assets/9.9c5e8ea1.png",_="/vitePress-blob/assets/10.f2b0f532.png",b="/vitePress-blob/assets/11.dce03aa0.png",d="/vitePress-blob/assets/12.d9df251e.png",m="/vitePress-blob/assets/13.677bfe09.png",g="/vitePress-blob/assets/14.3340cffc.png",P="/vitePress-blob/assets/15.58d84e53.png",f="/vitePress-blob/assets/16.7ce6920c.png",B=JSON.parse('{"title":"构图技巧","description":"","frontmatter":{},"headers":[],"relativePath":"shoot/构图形式/构图技巧.md","filePath":"shoot/构图形式/构图技巧.md","lastUpdated":1718174182000}'),u={name:"shoot/构图形式/构图技巧.md"},x=s('

构图技巧

点构图

中心点构图

将主题放在中心,突出主题

中心点构图

中心点构图

三分点构图

三分点构图

alt text

线构图

对称线构图

可以展示对称的秩序感,常用于风光、风光 + 人文 alt text

alt text

alt text

对角线构图

alt text

alt text

引导线构图

充分利用场景中的线条,用于引导观者的注意力落在主体上,并让画面产生深度和透视感 alt text

面构图

前景构图

例如通过树叶、花草、植物等做前景

alt text

框架构图

拍摄中利用框架将主体框起来,突出主体

alt text

alt text

留白构图

留有空白,让画面更加简洁,突出主题

alt text

alt text

',31),q=[x];function v(k,T,S,$,A,N){return a(),e("div",null,q)}const C=t(u,[["render",v]]);export{B as __pageData,C as default}; diff --git "a/assets/shoot_\346\236\204\345\233\276\345\275\242\345\274\217_\346\236\204\345\233\276\346\212\200\345\267\247.md.d90509e0.lean.js" "b/assets/shoot_\346\236\204\345\233\276\345\275\242\345\274\217_\346\236\204\345\233\276\346\212\200\345\267\247.md.78cc0528.lean.js" similarity index 94% rename from "assets/shoot_\346\236\204\345\233\276\345\275\242\345\274\217_\346\236\204\345\233\276\346\212\200\345\267\247.md.d90509e0.lean.js" rename to "assets/shoot_\346\236\204\345\233\276\345\275\242\345\274\217_\346\236\204\345\233\276\346\212\200\345\267\247.md.78cc0528.lean.js" index 25879672..5c84f405 100644 --- "a/assets/shoot_\346\236\204\345\233\276\345\275\242\345\274\217_\346\236\204\345\233\276\346\212\200\345\267\247.md.d90509e0.lean.js" +++ "b/assets/shoot_\346\236\204\345\233\276\345\275\242\345\274\217_\346\236\204\345\233\276\346\212\200\345\267\247.md.78cc0528.lean.js" @@ -1 +1 @@ -import{_ as t,o as a,c as e,Q as s}from"./chunks/framework.b6910bb2.js";const r="/vitePress-blob/assets/2.1e53a7e0.png",o="/vitePress-blob/assets/3.e934bbc6.png",i="/vitePress-blob/assets/4.ec3f3077.png",l="/vitePress-blob/assets/5.4c018a0f.png",n="/vitePress-blob/assets/6.f0091254.png",c="/vitePress-blob/assets/7.3dfb1ea6.png",p="/vitePress-blob/assets/8.4e45aae0.png",h="/vitePress-blob/assets/9.9c5e8ea1.png",_="/vitePress-blob/assets/10.f2b0f532.png",b="/vitePress-blob/assets/11.dce03aa0.png",d="/vitePress-blob/assets/12.d9df251e.png",m="/vitePress-blob/assets/13.677bfe09.png",g="/vitePress-blob/assets/14.3340cffc.png",P="/vitePress-blob/assets/15.58d84e53.png",f="/vitePress-blob/assets/16.7ce6920c.png",B=JSON.parse('{"title":"构图技巧","description":"","frontmatter":{},"headers":[],"relativePath":"shoot/构图形式/构图技巧.md","filePath":"shoot/构图形式/构图技巧.md","lastUpdated":1718173557000}'),u={name:"shoot/构图形式/构图技巧.md"},x=s("",31),q=[x];function v(k,T,S,$,A,N){return a(),e("div",null,q)}const C=t(u,[["render",v]]);export{B as __pageData,C as default}; +import{_ as t,o as a,c as e,Q as s}from"./chunks/framework.b6910bb2.js";const r="/vitePress-blob/assets/2.1e53a7e0.png",o="/vitePress-blob/assets/3.e934bbc6.png",i="/vitePress-blob/assets/4.ec3f3077.png",l="/vitePress-blob/assets/5.4c018a0f.png",n="/vitePress-blob/assets/6.f0091254.png",c="/vitePress-blob/assets/7.3dfb1ea6.png",p="/vitePress-blob/assets/8.4e45aae0.png",h="/vitePress-blob/assets/9.9c5e8ea1.png",_="/vitePress-blob/assets/10.f2b0f532.png",b="/vitePress-blob/assets/11.dce03aa0.png",d="/vitePress-blob/assets/12.d9df251e.png",m="/vitePress-blob/assets/13.677bfe09.png",g="/vitePress-blob/assets/14.3340cffc.png",P="/vitePress-blob/assets/15.58d84e53.png",f="/vitePress-blob/assets/16.7ce6920c.png",B=JSON.parse('{"title":"构图技巧","description":"","frontmatter":{},"headers":[],"relativePath":"shoot/构图形式/构图技巧.md","filePath":"shoot/构图形式/构图技巧.md","lastUpdated":1718174182000}'),u={name:"shoot/构图形式/构图技巧.md"},x=s("",31),q=[x];function v(k,T,S,$,A,N){return a(),e("div",null,q)}const C=t(u,[["render",v]]);export{B as __pageData,C as default}; diff --git "a/assets/shoot_\350\207\252\346\210\221\345\256\236\346\210\230\346\200\273\347\273\223_\345\273\266\350\277\237\346\221\204\345\275\261.md.46ca809f.js" "b/assets/shoot_\350\207\252\346\210\221\345\256\236\346\210\230\346\200\273\347\273\223_\345\273\266\350\277\237\346\221\204\345\275\261.md.7da692c4.js" similarity index 97% rename from "assets/shoot_\350\207\252\346\210\221\345\256\236\346\210\230\346\200\273\347\273\223_\345\273\266\350\277\237\346\221\204\345\275\261.md.46ca809f.js" rename to "assets/shoot_\350\207\252\346\210\221\345\256\236\346\210\230\346\200\273\347\273\223_\345\273\266\350\277\237\346\221\204\345\275\261.md.7da692c4.js" index 3f6a7c31..8956a50b 100644 --- "a/assets/shoot_\350\207\252\346\210\221\345\256\236\346\210\230\346\200\273\347\273\223_\345\273\266\350\277\237\346\221\204\345\275\261.md.46ca809f.js" +++ "b/assets/shoot_\350\207\252\346\210\221\345\256\236\346\210\230\346\200\273\347\273\223_\345\273\266\350\277\237\346\221\204\345\275\261.md.7da692c4.js" @@ -1 +1 @@ -import{_ as e,o as a,c as t,Q as o}from"./chunks/framework.b6910bb2.js";const s="/vitePress-blob/assets/2.be68a57d.png",r="/vitePress-blob/assets/4.9aaf818a.png",i="/vitePress-blob/assets/3.038403c4.png",g=JSON.parse('{"title":"延迟摄影","description":"","frontmatter":{},"headers":[],"relativePath":"shoot/自我实战总结/延迟摄影.md","filePath":"shoot/自我实战总结/延迟摄影.md","lastUpdated":1718173557000}'),l={name:"shoot/自我实战总结/延迟摄影.md"},n=o('

延迟摄影

如何拍摄

  1. 调节到视频模式

  2. 打开 Menu 菜单,在第一大项的第4小项中找到延时短片,打开这一功能。之后,回到主屏幕,我们发现左上角摄影机图标旁多出了一个时针图案和一组4位数字,这代表延时摄影已打开成功,准备进入拍摄。 Menu 菜单

  3. 此时,主屏幕下方的三个参数均可手动调整,从左到右依次是快门、光圈、感光度ISO Menu 菜单

  4. 自动曝光设置 固定第一帧: 固定第一帧指的是延时短片将始终以第一帧曝光的参数拍摄下去,中途不会发生改变,适用于光源亮度变化不大的场景 每一帧: 延时短片将由相机依据环境光线的变化,自动测光来决定每一帧的曝光值,适用于光源有较大改变的场景,如日转夜或夜转日 (ISO 感光度要设置成 AUTO) 自动曝光

参考文章

  1. https://www.xiaohongshu.com/explore/651389a3000000001e023777
',5),_=[n];function c(h,p,d,m,u,b){return a(),t("div",null,_)}const x=e(l,[["render",c]]);export{g as __pageData,x as default}; +import{_ as e,o as a,c as t,Q as o}from"./chunks/framework.b6910bb2.js";const s="/vitePress-blob/assets/2.be68a57d.png",r="/vitePress-blob/assets/4.9aaf818a.png",i="/vitePress-blob/assets/3.038403c4.png",g=JSON.parse('{"title":"延迟摄影","description":"","frontmatter":{},"headers":[],"relativePath":"shoot/自我实战总结/延迟摄影.md","filePath":"shoot/自我实战总结/延迟摄影.md","lastUpdated":1718174182000}'),l={name:"shoot/自我实战总结/延迟摄影.md"},n=o('

延迟摄影

如何拍摄

  1. 调节到视频模式

  2. 打开 Menu 菜单,在第一大项的第4小项中找到延时短片,打开这一功能。之后,回到主屏幕,我们发现左上角摄影机图标旁多出了一个时针图案和一组4位数字,这代表延时摄影已打开成功,准备进入拍摄。 Menu 菜单

  3. 此时,主屏幕下方的三个参数均可手动调整,从左到右依次是快门、光圈、感光度ISO Menu 菜单

  4. 自动曝光设置 固定第一帧: 固定第一帧指的是延时短片将始终以第一帧曝光的参数拍摄下去,中途不会发生改变,适用于光源亮度变化不大的场景 每一帧: 延时短片将由相机依据环境光线的变化,自动测光来决定每一帧的曝光值,适用于光源有较大改变的场景,如日转夜或夜转日 (ISO 感光度要设置成 AUTO) 自动曝光

参考文章

  1. https://www.xiaohongshu.com/explore/651389a3000000001e023777
',5),_=[n];function c(h,p,d,m,u,b){return a(),t("div",null,_)}const x=e(l,[["render",c]]);export{g as __pageData,x as default}; diff --git "a/assets/shoot_\350\207\252\346\210\221\345\256\236\346\210\230\346\200\273\347\273\223_\345\273\266\350\277\237\346\221\204\345\275\261.md.46ca809f.lean.js" "b/assets/shoot_\350\207\252\346\210\221\345\256\236\346\210\230\346\200\273\347\273\223_\345\273\266\350\277\237\346\221\204\345\275\261.md.7da692c4.lean.js" similarity index 89% rename from "assets/shoot_\350\207\252\346\210\221\345\256\236\346\210\230\346\200\273\347\273\223_\345\273\266\350\277\237\346\221\204\345\275\261.md.46ca809f.lean.js" rename to "assets/shoot_\350\207\252\346\210\221\345\256\236\346\210\230\346\200\273\347\273\223_\345\273\266\350\277\237\346\221\204\345\275\261.md.7da692c4.lean.js" index 29e76ae4..31b5f776 100644 --- "a/assets/shoot_\350\207\252\346\210\221\345\256\236\346\210\230\346\200\273\347\273\223_\345\273\266\350\277\237\346\221\204\345\275\261.md.46ca809f.lean.js" +++ "b/assets/shoot_\350\207\252\346\210\221\345\256\236\346\210\230\346\200\273\347\273\223_\345\273\266\350\277\237\346\221\204\345\275\261.md.7da692c4.lean.js" @@ -1 +1 @@ -import{_ as e,o as a,c as t,Q as o}from"./chunks/framework.b6910bb2.js";const s="/vitePress-blob/assets/2.be68a57d.png",r="/vitePress-blob/assets/4.9aaf818a.png",i="/vitePress-blob/assets/3.038403c4.png",g=JSON.parse('{"title":"延迟摄影","description":"","frontmatter":{},"headers":[],"relativePath":"shoot/自我实战总结/延迟摄影.md","filePath":"shoot/自我实战总结/延迟摄影.md","lastUpdated":1718173557000}'),l={name:"shoot/自我实战总结/延迟摄影.md"},n=o("",5),_=[n];function c(h,p,d,m,u,b){return a(),t("div",null,_)}const x=e(l,[["render",c]]);export{g as __pageData,x as default}; +import{_ as e,o as a,c as t,Q as o}from"./chunks/framework.b6910bb2.js";const s="/vitePress-blob/assets/2.be68a57d.png",r="/vitePress-blob/assets/4.9aaf818a.png",i="/vitePress-blob/assets/3.038403c4.png",g=JSON.parse('{"title":"延迟摄影","description":"","frontmatter":{},"headers":[],"relativePath":"shoot/自我实战总结/延迟摄影.md","filePath":"shoot/自我实战总结/延迟摄影.md","lastUpdated":1718174182000}'),l={name:"shoot/自我实战总结/延迟摄影.md"},n=o("",5),_=[n];function c(h,p,d,m,u,b){return a(),t("div",null,_)}const x=e(l,[["render",c]]);export{g as __pageData,x as default}; diff --git "a/assets/shoot_\350\207\252\346\210\221\345\256\236\346\210\230\346\200\273\347\273\223_\346\213\215\346\221\204\346\230\237\347\251\272.md.2de1cbd8.js" "b/assets/shoot_\350\207\252\346\210\221\345\256\236\346\210\230\346\200\273\347\273\223_\346\213\215\346\221\204\346\230\237\347\251\272.md.59c72bc3.js" similarity index 97% rename from "assets/shoot_\350\207\252\346\210\221\345\256\236\346\210\230\346\200\273\347\273\223_\346\213\215\346\221\204\346\230\237\347\251\272.md.2de1cbd8.js" rename to "assets/shoot_\350\207\252\346\210\221\345\256\236\346\210\230\346\200\273\347\273\223_\346\213\215\346\221\204\346\230\237\347\251\272.md.59c72bc3.js" index 6770223f..4c3312af 100644 --- "a/assets/shoot_\350\207\252\346\210\221\345\256\236\346\210\230\346\200\273\347\273\223_\346\213\215\346\221\204\346\230\237\347\251\272.md.2de1cbd8.js" +++ "b/assets/shoot_\350\207\252\346\210\221\345\256\236\346\210\230\346\200\273\347\273\223_\346\213\215\346\221\204\346\230\237\347\251\272.md.59c72bc3.js" @@ -1 +1 @@ -import{_ as a,o as e,c as t,Q as o}from"./chunks/framework.b6910bb2.js";const r="/vitePress-blob/assets/5.469845e2.png",s="/vitePress-blob/assets/6.c6e8eb70.png",f=JSON.parse('{"title":"拍摄星空","description":"","frontmatter":{},"headers":[],"relativePath":"shoot/自我实战总结/拍摄星空.md","filePath":"shoot/自我实战总结/拍摄星空.md","lastUpdated":1718173557000}'),h={name:"shoot/自我实战总结/拍摄星空.md"},i=o('

拍摄星空

大光圈、感光度、长曝光,这是拍摄星空的三大要素。

大光圈

f1.8

感光度

ISO:2000 以上(感光度越大、图片越亮,但也容易出现噪点)

手动对焦

手动对焦到某一颗星星上,然后锁定对焦

长曝光

快门速度 10秒以上, 连续拍10张以上后期堆栈(拍得多更好)

脚架

需要使用三脚架

星空

星空参数

参考文章

  1. https://www.xiaohongshu.com/explore/6507b277000000001e02de1a
',16),l=[i];function n(c,d,p,_,b,m){return e(),t("div",null,l)}const q=a(h,[["render",n]]);export{f as __pageData,q as default}; +import{_ as a,o as e,c as t,Q as o}from"./chunks/framework.b6910bb2.js";const r="/vitePress-blob/assets/5.469845e2.png",s="/vitePress-blob/assets/6.c6e8eb70.png",f=JSON.parse('{"title":"拍摄星空","description":"","frontmatter":{},"headers":[],"relativePath":"shoot/自我实战总结/拍摄星空.md","filePath":"shoot/自我实战总结/拍摄星空.md","lastUpdated":1718174182000}'),h={name:"shoot/自我实战总结/拍摄星空.md"},i=o('

拍摄星空

大光圈、感光度、长曝光,这是拍摄星空的三大要素。

大光圈

f1.8

感光度

ISO:2000 以上(感光度越大、图片越亮,但也容易出现噪点)

手动对焦

手动对焦到某一颗星星上,然后锁定对焦

长曝光

快门速度 10秒以上, 连续拍10张以上后期堆栈(拍得多更好)

脚架

需要使用三脚架

星空

星空参数

参考文章

  1. https://www.xiaohongshu.com/explore/6507b277000000001e02de1a
',16),l=[i];function n(c,d,p,_,b,m){return e(),t("div",null,l)}const q=a(h,[["render",n]]);export{f as __pageData,q as default}; diff --git "a/assets/shoot_\350\207\252\346\210\221\345\256\236\346\210\230\346\200\273\347\273\223_\346\213\215\346\221\204\346\230\237\347\251\272.md.2de1cbd8.lean.js" "b/assets/shoot_\350\207\252\346\210\221\345\256\236\346\210\230\346\200\273\347\273\223_\346\213\215\346\221\204\346\230\237\347\251\272.md.59c72bc3.lean.js" similarity index 88% rename from "assets/shoot_\350\207\252\346\210\221\345\256\236\346\210\230\346\200\273\347\273\223_\346\213\215\346\221\204\346\230\237\347\251\272.md.2de1cbd8.lean.js" rename to "assets/shoot_\350\207\252\346\210\221\345\256\236\346\210\230\346\200\273\347\273\223_\346\213\215\346\221\204\346\230\237\347\251\272.md.59c72bc3.lean.js" index 8ac07384..46cdf7cc 100644 --- "a/assets/shoot_\350\207\252\346\210\221\345\256\236\346\210\230\346\200\273\347\273\223_\346\213\215\346\221\204\346\230\237\347\251\272.md.2de1cbd8.lean.js" +++ "b/assets/shoot_\350\207\252\346\210\221\345\256\236\346\210\230\346\200\273\347\273\223_\346\213\215\346\221\204\346\230\237\347\251\272.md.59c72bc3.lean.js" @@ -1 +1 @@ -import{_ as a,o as e,c as t,Q as o}from"./chunks/framework.b6910bb2.js";const r="/vitePress-blob/assets/5.469845e2.png",s="/vitePress-blob/assets/6.c6e8eb70.png",f=JSON.parse('{"title":"拍摄星空","description":"","frontmatter":{},"headers":[],"relativePath":"shoot/自我实战总结/拍摄星空.md","filePath":"shoot/自我实战总结/拍摄星空.md","lastUpdated":1718173557000}'),h={name:"shoot/自我实战总结/拍摄星空.md"},i=o("",16),l=[i];function n(c,d,p,_,b,m){return e(),t("div",null,l)}const q=a(h,[["render",n]]);export{f as __pageData,q as default}; +import{_ as a,o as e,c as t,Q as o}from"./chunks/framework.b6910bb2.js";const r="/vitePress-blob/assets/5.469845e2.png",s="/vitePress-blob/assets/6.c6e8eb70.png",f=JSON.parse('{"title":"拍摄星空","description":"","frontmatter":{},"headers":[],"relativePath":"shoot/自我实战总结/拍摄星空.md","filePath":"shoot/自我实战总结/拍摄星空.md","lastUpdated":1718174182000}'),h={name:"shoot/自我实战总结/拍摄星空.md"},i=o("",16),l=[i];function n(c,d,p,_,b,m){return e(),t("div",null,l)}const q=a(h,[["render",n]]);export{f as __pageData,q as default}; diff --git "a/assets/shoot_\350\207\252\346\210\221\345\256\236\346\210\230\346\200\273\347\273\223_\346\213\215\346\221\204\346\234\210\344\272\256.md.fc1809ae.js" "b/assets/shoot_\350\207\252\346\210\221\345\256\236\346\210\230\346\200\273\347\273\223_\346\213\215\346\221\204\346\234\210\344\272\256.md.bf540294.js" similarity index 92% rename from "assets/shoot_\350\207\252\346\210\221\345\256\236\346\210\230\346\200\273\347\273\223_\346\213\215\346\221\204\346\234\210\344\272\256.md.fc1809ae.js" rename to "assets/shoot_\350\207\252\346\210\221\345\256\236\346\210\230\346\200\273\347\273\223_\346\213\215\346\221\204\346\234\210\344\272\256.md.bf540294.js" index ac137162..78feae71 100644 --- "a/assets/shoot_\350\207\252\346\210\221\345\256\236\346\210\230\346\200\273\347\273\223_\346\213\215\346\221\204\346\234\210\344\272\256.md.fc1809ae.js" +++ "b/assets/shoot_\350\207\252\346\210\221\345\256\236\346\210\230\346\200\273\347\273\223_\346\213\215\346\221\204\346\234\210\344\272\256.md.bf540294.js" @@ -1 +1 @@ -import{_ as t,o as a,c as o,k as e,a as s}from"./chunks/framework.b6910bb2.js";const x=JSON.parse('{"title":"拍摄月亮","description":"","frontmatter":{},"headers":[],"relativePath":"shoot/自我实战总结/拍摄月亮.md","filePath":"shoot/自我实战总结/拍摄月亮.md","lastUpdated":1718173557000}'),n={name:"shoot/自我实战总结/拍摄月亮.md"},r=e("h1",{id:"拍摄月亮",tabindex:"-1"},[s("拍摄月亮 "),e("a",{class:"header-anchor",href:"#拍摄月亮","aria-label":'Permalink to "拍摄月亮"'},"​")],-1),l=e("ul",null,[e("li",null,"光圈一般我喜欢小光圈 在 f8 - f10 之间"),e("li",null,"需要使用长焦镜头,例如 70-200mm")],-1),c=[r,l];function _(d,i,h,m,p,f){return a(),o("div",null,c)}const k=t(n,[["render",_]]);export{x as __pageData,k as default}; +import{_ as t,o as a,c as o,k as e,a as s}from"./chunks/framework.b6910bb2.js";const x=JSON.parse('{"title":"拍摄月亮","description":"","frontmatter":{},"headers":[],"relativePath":"shoot/自我实战总结/拍摄月亮.md","filePath":"shoot/自我实战总结/拍摄月亮.md","lastUpdated":1718174182000}'),n={name:"shoot/自我实战总结/拍摄月亮.md"},r=e("h1",{id:"拍摄月亮",tabindex:"-1"},[s("拍摄月亮 "),e("a",{class:"header-anchor",href:"#拍摄月亮","aria-label":'Permalink to "拍摄月亮"'},"​")],-1),l=e("ul",null,[e("li",null,"光圈一般我喜欢小光圈 在 f8 - f10 之间"),e("li",null,"需要使用长焦镜头,例如 70-200mm")],-1),c=[r,l];function _(d,i,h,m,p,f){return a(),o("div",null,c)}const k=t(n,[["render",_]]);export{x as __pageData,k as default}; diff --git "a/assets/shoot_\350\207\252\346\210\221\345\256\236\346\210\230\346\200\273\347\273\223_\346\213\215\346\221\204\346\234\210\344\272\256.md.fc1809ae.lean.js" "b/assets/shoot_\350\207\252\346\210\221\345\256\236\346\210\230\346\200\273\347\273\223_\346\213\215\346\221\204\346\234\210\344\272\256.md.bf540294.lean.js" similarity index 92% rename from "assets/shoot_\350\207\252\346\210\221\345\256\236\346\210\230\346\200\273\347\273\223_\346\213\215\346\221\204\346\234\210\344\272\256.md.fc1809ae.lean.js" rename to "assets/shoot_\350\207\252\346\210\221\345\256\236\346\210\230\346\200\273\347\273\223_\346\213\215\346\221\204\346\234\210\344\272\256.md.bf540294.lean.js" index ac137162..78feae71 100644 --- "a/assets/shoot_\350\207\252\346\210\221\345\256\236\346\210\230\346\200\273\347\273\223_\346\213\215\346\221\204\346\234\210\344\272\256.md.fc1809ae.lean.js" +++ "b/assets/shoot_\350\207\252\346\210\221\345\256\236\346\210\230\346\200\273\347\273\223_\346\213\215\346\221\204\346\234\210\344\272\256.md.bf540294.lean.js" @@ -1 +1 @@ -import{_ as t,o as a,c as o,k as e,a as s}from"./chunks/framework.b6910bb2.js";const x=JSON.parse('{"title":"拍摄月亮","description":"","frontmatter":{},"headers":[],"relativePath":"shoot/自我实战总结/拍摄月亮.md","filePath":"shoot/自我实战总结/拍摄月亮.md","lastUpdated":1718173557000}'),n={name:"shoot/自我实战总结/拍摄月亮.md"},r=e("h1",{id:"拍摄月亮",tabindex:"-1"},[s("拍摄月亮 "),e("a",{class:"header-anchor",href:"#拍摄月亮","aria-label":'Permalink to "拍摄月亮"'},"​")],-1),l=e("ul",null,[e("li",null,"光圈一般我喜欢小光圈 在 f8 - f10 之间"),e("li",null,"需要使用长焦镜头,例如 70-200mm")],-1),c=[r,l];function _(d,i,h,m,p,f){return a(),o("div",null,c)}const k=t(n,[["render",_]]);export{x as __pageData,k as default}; +import{_ as t,o as a,c as o,k as e,a as s}from"./chunks/framework.b6910bb2.js";const x=JSON.parse('{"title":"拍摄月亮","description":"","frontmatter":{},"headers":[],"relativePath":"shoot/自我实战总结/拍摄月亮.md","filePath":"shoot/自我实战总结/拍摄月亮.md","lastUpdated":1718174182000}'),n={name:"shoot/自我实战总结/拍摄月亮.md"},r=e("h1",{id:"拍摄月亮",tabindex:"-1"},[s("拍摄月亮 "),e("a",{class:"header-anchor",href:"#拍摄月亮","aria-label":'Permalink to "拍摄月亮"'},"​")],-1),l=e("ul",null,[e("li",null,"光圈一般我喜欢小光圈 在 f8 - f10 之间"),e("li",null,"需要使用长焦镜头,例如 70-200mm")],-1),c=[r,l];function _(d,i,h,m,p,f){return a(),o("div",null,c)}const k=t(n,[["render",_]]);export{x as __pageData,k as default}; diff --git "a/assets/shoot_\350\207\252\346\210\221\345\256\236\346\210\230\346\200\273\347\273\223_\346\213\215\346\221\204\347\203\237\350\212\261.md.fb21693e.js" "b/assets/shoot_\350\207\252\346\210\221\345\256\236\346\210\230\346\200\273\347\273\223_\346\213\215\346\221\204\347\203\237\350\212\261.md.5d5410ff.js" similarity index 93% rename from "assets/shoot_\350\207\252\346\210\221\345\256\236\346\210\230\346\200\273\347\273\223_\346\213\215\346\221\204\347\203\237\350\212\261.md.fb21693e.js" rename to "assets/shoot_\350\207\252\346\210\221\345\256\236\346\210\230\346\200\273\347\273\223_\346\213\215\346\221\204\347\203\237\350\212\261.md.5d5410ff.js" index b0fb6cb2..36f76379 100644 --- "a/assets/shoot_\350\207\252\346\210\221\345\256\236\346\210\230\346\200\273\347\273\223_\346\213\215\346\221\204\347\203\237\350\212\261.md.fb21693e.js" +++ "b/assets/shoot_\350\207\252\346\210\221\345\256\236\346\210\230\346\200\273\347\273\223_\346\213\215\346\221\204\347\203\237\350\212\261.md.5d5410ff.js" @@ -1 +1 @@ -import{_ as t,o as s,c as a,k as e,a as o}from"./chunks/framework.b6910bb2.js";const l="/vitePress-blob/assets/1.00dedace.jpg",k=JSON.parse('{"title":"拍摄烟花","description":"","frontmatter":{},"headers":[],"relativePath":"shoot/自我实战总结/拍摄烟花.md","filePath":"shoot/自我实战总结/拍摄烟花.md","lastUpdated":1718173557000}'),n={name:"shoot/自我实战总结/拍摄烟花.md"},r=e("h1",{id:"拍摄烟花",tabindex:"-1"},[o("拍摄烟花 "),e("a",{class:"header-anchor",href:"#拍摄烟花","aria-label":'Permalink to "拍摄烟花"'},"​")],-1),c=e("ul",null,[e("li",null,"快门速度一般比较长可以出现拉线效果,例如 0.5s/1s"),e("li",null,"ISO 感光度一般在 500 以下,这样背景会黑一些"),e("li",null,"光圈一般我喜欢小光圈 在 f10 以后")],-1),_=e("p",null,[e("img",{src:l,alt:"快门速度"})],-1),i=[r,c,_];function d(h,p,m,u,f,x){return s(),a("div",null,i)}const P=t(n,[["render",d]]);export{k as __pageData,P as default}; +import{_ as t,o as s,c as a,k as e,a as o}from"./chunks/framework.b6910bb2.js";const l="/vitePress-blob/assets/1.00dedace.jpg",k=JSON.parse('{"title":"拍摄烟花","description":"","frontmatter":{},"headers":[],"relativePath":"shoot/自我实战总结/拍摄烟花.md","filePath":"shoot/自我实战总结/拍摄烟花.md","lastUpdated":1718174182000}'),n={name:"shoot/自我实战总结/拍摄烟花.md"},r=e("h1",{id:"拍摄烟花",tabindex:"-1"},[o("拍摄烟花 "),e("a",{class:"header-anchor",href:"#拍摄烟花","aria-label":'Permalink to "拍摄烟花"'},"​")],-1),c=e("ul",null,[e("li",null,"快门速度一般比较长可以出现拉线效果,例如 0.5s/1s"),e("li",null,"ISO 感光度一般在 500 以下,这样背景会黑一些"),e("li",null,"光圈一般我喜欢小光圈 在 f10 以后")],-1),_=e("p",null,[e("img",{src:l,alt:"快门速度"})],-1),i=[r,c,_];function d(h,p,m,u,f,x){return s(),a("div",null,i)}const P=t(n,[["render",d]]);export{k as __pageData,P as default}; diff --git "a/assets/shoot_\350\207\252\346\210\221\345\256\236\346\210\230\346\200\273\347\273\223_\346\213\215\346\221\204\347\203\237\350\212\261.md.fb21693e.lean.js" "b/assets/shoot_\350\207\252\346\210\221\345\256\236\346\210\230\346\200\273\347\273\223_\346\213\215\346\221\204\347\203\237\350\212\261.md.5d5410ff.lean.js" similarity index 93% rename from "assets/shoot_\350\207\252\346\210\221\345\256\236\346\210\230\346\200\273\347\273\223_\346\213\215\346\221\204\347\203\237\350\212\261.md.fb21693e.lean.js" rename to "assets/shoot_\350\207\252\346\210\221\345\256\236\346\210\230\346\200\273\347\273\223_\346\213\215\346\221\204\347\203\237\350\212\261.md.5d5410ff.lean.js" index b0fb6cb2..36f76379 100644 --- "a/assets/shoot_\350\207\252\346\210\221\345\256\236\346\210\230\346\200\273\347\273\223_\346\213\215\346\221\204\347\203\237\350\212\261.md.fb21693e.lean.js" +++ "b/assets/shoot_\350\207\252\346\210\221\345\256\236\346\210\230\346\200\273\347\273\223_\346\213\215\346\221\204\347\203\237\350\212\261.md.5d5410ff.lean.js" @@ -1 +1 @@ -import{_ as t,o as s,c as a,k as e,a as o}from"./chunks/framework.b6910bb2.js";const l="/vitePress-blob/assets/1.00dedace.jpg",k=JSON.parse('{"title":"拍摄烟花","description":"","frontmatter":{},"headers":[],"relativePath":"shoot/自我实战总结/拍摄烟花.md","filePath":"shoot/自我实战总结/拍摄烟花.md","lastUpdated":1718173557000}'),n={name:"shoot/自我实战总结/拍摄烟花.md"},r=e("h1",{id:"拍摄烟花",tabindex:"-1"},[o("拍摄烟花 "),e("a",{class:"header-anchor",href:"#拍摄烟花","aria-label":'Permalink to "拍摄烟花"'},"​")],-1),c=e("ul",null,[e("li",null,"快门速度一般比较长可以出现拉线效果,例如 0.5s/1s"),e("li",null,"ISO 感光度一般在 500 以下,这样背景会黑一些"),e("li",null,"光圈一般我喜欢小光圈 在 f10 以后")],-1),_=e("p",null,[e("img",{src:l,alt:"快门速度"})],-1),i=[r,c,_];function d(h,p,m,u,f,x){return s(),a("div",null,i)}const P=t(n,[["render",d]]);export{k as __pageData,P as default}; +import{_ as t,o as s,c as a,k as e,a as o}from"./chunks/framework.b6910bb2.js";const l="/vitePress-blob/assets/1.00dedace.jpg",k=JSON.parse('{"title":"拍摄烟花","description":"","frontmatter":{},"headers":[],"relativePath":"shoot/自我实战总结/拍摄烟花.md","filePath":"shoot/自我实战总结/拍摄烟花.md","lastUpdated":1718174182000}'),n={name:"shoot/自我实战总结/拍摄烟花.md"},r=e("h1",{id:"拍摄烟花",tabindex:"-1"},[o("拍摄烟花 "),e("a",{class:"header-anchor",href:"#拍摄烟花","aria-label":'Permalink to "拍摄烟花"'},"​")],-1),c=e("ul",null,[e("li",null,"快门速度一般比较长可以出现拉线效果,例如 0.5s/1s"),e("li",null,"ISO 感光度一般在 500 以下,这样背景会黑一些"),e("li",null,"光圈一般我喜欢小光圈 在 f10 以后")],-1),_=e("p",null,[e("img",{src:l,alt:"快门速度"})],-1),i=[r,c,_];function d(h,p,m,u,f,x){return s(),a("div",null,i)}const P=t(n,[["render",d]]);export{k as __pageData,P as default}; diff --git "a/guide/DDD \351\242\206\345\237\237\351\251\261\345\212\250\350\256\276\350\256\241/index.html" "b/guide/DDD \351\242\206\345\237\237\351\251\261\345\212\250\350\256\276\350\256\241/index.html" index df3ec08b..091cc9a6 100644 --- "a/guide/DDD \351\242\206\345\237\237\351\251\261\345\212\250\350\256\276\350\256\241/index.html" +++ "b/guide/DDD \351\242\206\345\237\237\351\251\261\345\212\250\350\256\276\350\256\241/index.html" @@ -11,7 +11,7 @@ - + @@ -23,8 +23,8 @@ -
Skip to content

领域驱动设计

定义

- +
Skip to content

领域驱动设计

定义

+ \ No newline at end of file diff --git "a/guide/Fabric.js/\345\246\202\344\275\225\350\260\203\350\257\225Fabric.html" "b/guide/Fabric.js/\345\246\202\344\275\225\350\260\203\350\257\225Fabric.html" index 96a184ed..d63f1249 100644 --- "a/guide/Fabric.js/\345\246\202\344\275\225\350\260\203\350\257\225Fabric.html" +++ "b/guide/Fabric.js/\345\246\202\344\275\225\350\260\203\350\257\225Fabric.html" @@ -11,7 +11,7 @@ - + @@ -23,8 +23,8 @@ -
Skip to content

如何调试 Fabric.js

为了更好的学习 Fabric.js 的源码,我们需要了解如何调试 Fabric.js。

第一步:下载源码

首先,我们需要下载 Fabric.js 的源码。Fabric.js 的源码托管在 GitHub 上,我们可以通过 git clone 命令将源码下载到本地。

bash
git clone https://github.com/fabricjs/fabricjs.com.git
git clone https://github.com/fabricjs/fabricjs.com.git

第二步:安装依赖

Fabric.js 使用 Jekyll 来提供页面服务,因此我们需要安装 Jekyll

Jekyll 提供了多种安装方式,在下将以 macOS 为例

Step 1: Install Homebrew

bash
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

Step 2: Install chruby and the latest Ruby with ruby-install

bash
brew install chruby ruby-install xz
brew install chruby ruby-install xz

Step 3: Install Ruby

bash
ruby-install ruby 3.1.3
ruby-install ruby 3.1.3

Step 4: 检查 ruby 是否安装成功

bash
ruby -v
ruby -v

它应该显示 ruby​​ 3.1.3p185(2022-11-24 修订版 1a6b16756e)或更新版本。 alt text

Step 5: 安装 Jekyll

bash
gem install jekyll
gem install jekyll

Step 6: 运行环境 安装完成后,在项目仓库根目录中运行命令 jekyll serve 即可.在此命令的控制台输出中,您将看到 Server address: <base_url> ,在浏览器中访问此 base_url ,您将看到 fabricjs.com 上的内容以及本地更改应用。

- +
Skip to content

如何调试 Fabric.js

为了更好的学习 Fabric.js 的源码,我们需要了解如何调试 Fabric.js。

第一步:下载源码

首先,我们需要下载 Fabric.js 的源码。Fabric.js 的源码托管在 GitHub 上,我们可以通过 git clone 命令将源码下载到本地。

bash
git clone https://github.com/fabricjs/fabricjs.com.git
git clone https://github.com/fabricjs/fabricjs.com.git

第二步:安装依赖

Fabric.js 使用 Jekyll 来提供页面服务,因此我们需要安装 Jekyll

Jekyll 提供了多种安装方式,在下将以 macOS 为例

Step 1: Install Homebrew

bash
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

Step 2: Install chruby and the latest Ruby with ruby-install

bash
brew install chruby ruby-install xz
brew install chruby ruby-install xz

Step 3: Install Ruby

bash
ruby-install ruby 3.1.3
ruby-install ruby 3.1.3

Step 4: 检查 ruby 是否安装成功

bash
ruby -v
ruby -v

它应该显示 ruby​​ 3.1.3p185(2022-11-24 修订版 1a6b16756e)或更新版本。 alt text

Step 5: 安装 Jekyll

bash
gem install jekyll
gem install jekyll

Step 6: 运行环境 安装完成后,在项目仓库根目录中运行命令 jekyll serve 即可.在此命令的控制台输出中,您将看到 Server address: <base_url> ,在浏览器中访问此 base_url ,您将看到 fabricjs.com 上的内容以及本地更改应用。

+ \ No newline at end of file diff --git "a/guide/Node\347\233\270\345\205\263/\346\246\202\350\246\201.html" "b/guide/Node\347\233\270\345\205\263/\346\246\202\350\246\201.html" index b5957372..63975943 100644 --- "a/guide/Node\347\233\270\345\205\263/\346\246\202\350\246\201.html" +++ "b/guide/Node\347\233\270\345\205\263/\346\246\202\350\246\201.html" @@ -11,7 +11,7 @@ - + @@ -23,8 +23,8 @@ -
Skip to content
- +
Skip to content
+ \ No newline at end of file diff --git "a/guide/React/React\344\270\216Vue\347\232\204\345\214\272\345\210\253.html" "b/guide/React/React\344\270\216Vue\347\232\204\345\214\272\345\210\253.html" index 1250d9af..6923897b 100644 --- "a/guide/React/React\344\270\216Vue\347\232\204\345\214\272\345\210\253.html" +++ "b/guide/React/React\344\270\216Vue\347\232\204\345\214\272\345\210\253.html" @@ -11,7 +11,7 @@ - + @@ -23,8 +23,8 @@ -
Skip to content
- +
Skip to content
+ \ No newline at end of file diff --git "a/guide/React/React\344\270\255\347\232\204\344\272\213\344\273\266\346\234\272\345\210\266.html" "b/guide/React/React\344\270\255\347\232\204\344\272\213\344\273\266\346\234\272\345\210\266.html" index 59f1a613..7b389f4a 100644 --- "a/guide/React/React\344\270\255\347\232\204\344\272\213\344\273\266\346\234\272\345\210\266.html" +++ "b/guide/React/React\344\270\255\347\232\204\344\272\213\344\273\266\346\234\272\345\210\266.html" @@ -11,7 +11,7 @@ - + @@ -23,8 +23,8 @@ -
Skip to content

React 事件机制

概要

为了抹平各个浏览器之间的差异以及统一维护和管理事件,React 自行实现了合成事件,用来模拟原生事件的行为 在 React 16 之前,React 的合成事件放在了 document 的冒泡阶段 在 React 16 之后,为了兼容各个版本,React 的合成事件放在了 根节点 的捕获和冒泡阶段

具体实现

- +
Skip to content

React 事件机制

概要

为了抹平各个浏览器之间的差异以及统一维护和管理事件,React 自行实现了合成事件,用来模拟原生事件的行为 在 React 16 之前,React 的合成事件放在了 document 的冒泡阶段 在 React 16 之后,为了兼容各个版本,React 的合成事件放在了 根节点 的捕获和冒泡阶段

具体实现

+ \ No newline at end of file diff --git "a/guide/React/React\344\270\255\347\232\204\345\274\202\345\270\270\346\234\272\345\210\266.html" "b/guide/React/React\344\270\255\347\232\204\345\274\202\345\270\270\346\234\272\345\210\266.html" index 903bd39e..e3662434 100644 --- "a/guide/React/React\344\270\255\347\232\204\345\274\202\345\270\270\346\234\272\345\210\266.html" +++ "b/guide/React/React\344\270\255\347\232\204\345\274\202\345\270\270\346\234\272\345\210\266.html" @@ -11,7 +11,7 @@ - + @@ -23,8 +23,8 @@ -
Skip to content
- +
Skip to content
+ \ No newline at end of file diff --git "a/guide/React/React\344\270\255\347\232\204\346\200\247\350\203\275\344\274\230\345\214\226.html" "b/guide/React/React\344\270\255\347\232\204\346\200\247\350\203\275\344\274\230\345\214\226.html" index 707d0635..760002af 100644 --- "a/guide/React/React\344\270\255\347\232\204\346\200\247\350\203\275\344\274\230\345\214\226.html" +++ "b/guide/React/React\344\270\255\347\232\204\346\200\247\350\203\275\344\274\230\345\214\226.html" @@ -11,7 +11,7 @@ - + @@ -23,7 +23,7 @@ -
Skip to content

React 中的性能优化

在 React 中当我们的父组件更新时,将渲染整个子组件树,这样会造成很大的性能开销,所以我们需要对组件进行优化,避免不必要的渲染。

常见的性能优化手段有:

  1. 减少不必要的渲染

    1. 使用 useMemo 缓存数据、使用 useCallback 缓存函数
    2. 使用 React.memo 缓存组件
    3. 合理的使用 Key
    4. 使用 Fragment 避免额外标记
    5. 通过 Suspense 和 Lazy 拆分组件
  2. 通用方案

    1. 在组件销毁的时候清除定时器/事件
    2. 频繁切换时使用 display: none; 避免不必要的性能开销
    3. 为组件创建错误边界

1 使用 useMemo 缓存数据、使用 useCallback 缓存函数

jsx
/**
+    
Skip to content

React 中的性能优化

在 React 中当我们的父组件更新时,将渲染整个子组件树,这样会造成很大的性能开销,所以我们需要对组件进行优化,避免不必要的渲染。

常见的性能优化手段有:

  1. 减少不必要的渲染

    1. 使用 useMemo 缓存数据、使用 useCallback 缓存函数
    2. 使用 React.memo 缓存组件
    3. 合理的使用 Key
    4. 使用 Fragment 避免额外标记
    5. 通过 Suspense 和 Lazy 拆分组件
  2. 通用方案

    1. 在组件销毁的时候清除定时器/事件
    2. 频繁切换时使用 display: none; 避免不必要的性能开销
    3. 为组件创建错误边界

1 使用 useMemo 缓存数据、使用 useCallback 缓存函数

jsx
/**
  * 使用 useMemo 缓存数据,类似于 Vue 的 computed 计算属性
  * 使用 useCallback 缓存函数
  * @returns
@@ -459,8 +459,8 @@
 
     return this.props.children;
   }
-}

参考文章

  1. https://juejin.cn/post/6965747225154732069#heading-15
  2. https://cloud.tencent.com/developer/article/1810002
- +}

参考文章

  1. https://juejin.cn/post/6965747225154732069#heading-15
  2. https://cloud.tencent.com/developer/article/1810002
+ \ No newline at end of file diff --git "a/guide/React/React\344\270\272\344\273\200\344\271\210\350\246\201\344\275\277\347\224\250JSX.html" "b/guide/React/React\344\270\272\344\273\200\344\271\210\350\246\201\344\275\277\347\224\250JSX.html" index 926d5ed8..dc963970 100644 --- "a/guide/React/React\344\270\272\344\273\200\344\271\210\350\246\201\344\275\277\347\224\250JSX.html" +++ "b/guide/React/React\344\270\272\344\273\200\344\271\210\350\246\201\344\275\277\347\224\250JSX.html" @@ -11,7 +11,7 @@ - + @@ -23,8 +23,8 @@ -
Skip to content

React 为什么要使用 JSX ?

JSX 是 JavaScript 语法拓展,结构类似于 XML,它可以在 JavaScript 中直接使用 HTML 标签,这样可以方便开发者编写组件,提高开发效率。

没有JSX时,也可以使用 React.createElement 实现一个组件,但是这样的代码可读性很差,而且不方便复用,所以 React 推荐使用 JSX。

- +
Skip to content

React 为什么要使用 JSX ?

JSX 是 JavaScript 语法拓展,结构类似于 XML,它可以在 JavaScript 中直接使用 HTML 标签,这样可以方便开发者编写组件,提高开发效率。

没有JSX时,也可以使用 React.createElement 实现一个组件,但是这样的代码可读性很差,而且不方便复用,所以 React 推荐使用 JSX。

+ \ No newline at end of file diff --git "a/guide/React/React\346\230\257\344\273\200\344\271\210.html" "b/guide/React/React\346\230\257\344\273\200\344\271\210.html" index deab03f0..3f2de8f1 100644 --- "a/guide/React/React\346\230\257\344\273\200\344\271\210.html" +++ "b/guide/React/React\346\230\257\344\273\200\344\271\210.html" @@ -11,7 +11,7 @@ - + @@ -23,12 +23,12 @@ -
Skip to content

React 是什么?

React 是一个用于构建用户界面的 JavaScript 库, 通过组件化的方式解决视图层复用的问题。

它的核心思路是: 声明式、组件化、通用型

声明式

相比 JQ 的命令式编程: $(body).css('color', 'red');, 声明式编程更加直观、便于复用:

jsx
const Body = (props) => {
+    
Skip to content

React 是什么?

React 是一个用于构建用户界面的 JavaScript 库, 通过组件化的方式解决视图层复用的问题。

它的核心思路是: 声明式、组件化、通用型

声明式

相比 JQ 的命令式编程: $(body).css('color', 'red');, 声明式编程更加直观、便于复用:

jsx
const Body = (props) => {
    return <div style={{color: 'red'}}>{props.children}</div>
 }
const Body = (props) => {
    return <div style={{color: 'red'}}>{props.children}</div>
-}

组件化

可以降低功能之间的耦合、提高功能的内聚性,便于复用

通用性

虚拟DOM的实现,保证了跨平台和可移植性

缺点

没有提供全链路的解决方法,比如 router、数据仓库,需要借助第三方库

- +}

组件化

可以降低功能之间的耦合、提高功能的内聚性,便于复用

通用性

虚拟DOM的实现,保证了跨平台和可移植性

缺点

没有提供全链路的解决方法,比如 router、数据仓库,需要借助第三方库

+ \ No newline at end of file diff --git "a/guide/React/React\346\230\257\345\246\202\344\275\225\346\270\262\346\237\223\347\232\204.html" "b/guide/React/React\346\230\257\345\246\202\344\275\225\346\270\262\346\237\223\347\232\204.html" index 0679ab1f..fec1ec77 100644 --- "a/guide/React/React\346\230\257\345\246\202\344\275\225\346\270\262\346\237\223\347\232\204.html" +++ "b/guide/React/React\346\230\257\345\246\202\344\275\225\346\270\262\346\237\223\347\232\204.html" @@ -11,7 +11,7 @@ - + @@ -23,8 +23,8 @@ -
Skip to content

React 是如何渲染的

概要

React 的渲染过程可以分成 2 大阶段, 分别是调和阶段和提交阶段。 调和阶段可以分成 beginWork 阶段、 completeWork 阶段。 在 beginWork 阶段中,React 会根据新生成的 ReactElement 对象和旧的 Fiber 节点进行对比,判断是否可以复用旧的 Fiber 节点并对 Fiber 进行标记。 在 completeWork 节点中,会自底向上构建副作用链表,用来记录需要更新的节点,生成的 DOM 节点会挂载在 Fiber 的 stateNode 属性上。

提交阶段主要分成:操作 DOM 前阶段、操作 DOM 阶段、操作 DOM 后阶段。

React 16 以前

在浏览器中 js 线程与渲染线程是互斥的,如果 js 线程长期占用着浏览器的主线程,那么界面将长时间不更新,在动画等一些场景下会造成卡顿效果。

因为 Stack Reconciler 是一个同步的递归过程,随着业务复杂度增加,Stack Reconciler 需要的调和时间会变长,

这意味着 js 将长时间占用浏览器,进而导致页面卡顿

Stack Reconciler

React 16 以后

将同步执行的 Stack Reconciler 替换成了异步可中断的 Fiber Reconciler

Fiber Reconciler

在更新时,每个任务会被赋予一个优先级,当任务抵达调度器时,高优先级的任务会更快抵达协调器,如有新的更高优先级的任务进入调度器时,当前协调器的任务就会被中断,更高优先级的任务将进入 reconciler

Fiber Reconciler

新的架构会导致部分生命周期重复执行:

  • componentWillMount
  • componentWillUpdate
  • showComponentUpdate
  • componentWillReceiveProps

Render Performance

从首次渲染的调用栈来看,React 的渲染过程主要分为以下几个步骤:

    1. Mount 阶段
    1. Render 阶段
    1. Commit 阶段

Mount 阶段

当执行 ReactDOM.render 时会直接调用 legacyRenderSubtreeIntoContainer 方法

legacyRenderSubtreeIntoContainer 方法

会创建 reactRootContainer 对象(也就是挂载的容器对象), reactRootContainer 对象的 _internalRoot 会指向 fiberRoot (FiberRootNode 类),也就是根节点对象。

legacyRenderSubtreeIntoContainer 最终返回挂载组件( App组件 )的实例对象。

Mount 渲染过程

FiberRootNode对象的描述

在 fiberRoot 对象( FiberRootNode类 )中的 current 属性将指向 rootFiber 对象 (根节点Fiber,即 FiberNode 实例)

fiberRoot对象指向 rootFiber 根节点Fiber

挂载创建关系图

updateContainer 函数

updateContainer 函数主要有以下 3 件事:

    1. 获取当前节点的优先级 lane
    1. 结合 lane 创建当前 Fiber 节点 update 对象,并将其入队
    1. 调度当前节点 (rootFiber 节点)

updateContainer

scheduleUpdateOnFiber 函数

scheduleUpdateOnFiber 函数中会获取 Fiber 节点的mode属性判断是否走同步渲染还是异步渲染的逻辑,在 React17 中首次渲染走的是同步渲染的逻辑

scheduleUpdateOnFiber

这里可能有小伙伴会问,Fiber架构不就是异步渲染的么? 我想说的是,Fiber架构的设计初衷确实是为了异步渲染而设计的,但是 Fiber 架构并不能和异步渲染画上等号,我们不难发现,Fiber 架构同时兼容了同步渲染和异步渲染,如下图,决定同步还是异步取决于 mode

mode 决定同步异步

Render 阶段

performSyncWorkOnRoot 函数

核心逻辑在 renderRootSync 函数中

renderRootSync 函数

核心方法有俩个 prepareFreshStackworkLoopSync 函数

renderRootSync 逻辑

prepareFreshStack 函数

主要是有个方法 createWorkInProgress , 用来构建 workInProgress 双缓冲树,通过 alternate 相互指向

createWorkInProgress 构建 work-in-progress 树

当建立好双缓冲树的关系后,我们不难得到以下的关系图

双缓冲树关系图

workLoopSync 函数

当我们构建完 workInProgress Tree 的根节点时,建立 current tree 和 workInProgess Tree 的关联关系后,将进入 workLoopSync 调和阶段。

反复判断 workInProgress 是否为空,如果不为空,就执行 performUnitOfWork 方法 workLoopSync 逻辑

performUnitOfWork 函数

performUnitOfWork 函数的作用是 beginWork 优先创建子节点。 completeUnitOfWork 创建完子节点后判断是否有兄弟节点,有则创建兄弟节点,无则继续向上遍历父节点,直到遍历到根节点为止

performUnitOfWork 逻辑

beginWork 函数

参考文档

1 https://zhuanlan.zhihu.com/p/385319664 2

- +
Skip to content

React 是如何渲染的

概要

React 的渲染过程可以分成 2 大阶段, 分别是调和阶段和提交阶段。 调和阶段可以分成 beginWork 阶段、 completeWork 阶段。 在 beginWork 阶段中,React 会根据新生成的 ReactElement 对象和旧的 Fiber 节点进行对比,判断是否可以复用旧的 Fiber 节点并对 Fiber 进行标记。 在 completeWork 节点中,会自底向上构建副作用链表,用来记录需要更新的节点,生成的 DOM 节点会挂载在 Fiber 的 stateNode 属性上。

提交阶段主要分成:操作 DOM 前阶段、操作 DOM 阶段、操作 DOM 后阶段。

React 16 以前

在浏览器中 js 线程与渲染线程是互斥的,如果 js 线程长期占用着浏览器的主线程,那么界面将长时间不更新,在动画等一些场景下会造成卡顿效果。

因为 Stack Reconciler 是一个同步的递归过程,随着业务复杂度增加,Stack Reconciler 需要的调和时间会变长,

这意味着 js 将长时间占用浏览器,进而导致页面卡顿

Stack Reconciler

React 16 以后

将同步执行的 Stack Reconciler 替换成了异步可中断的 Fiber Reconciler

Fiber Reconciler

在更新时,每个任务会被赋予一个优先级,当任务抵达调度器时,高优先级的任务会更快抵达协调器,如有新的更高优先级的任务进入调度器时,当前协调器的任务就会被中断,更高优先级的任务将进入 reconciler

Fiber Reconciler

新的架构会导致部分生命周期重复执行:

  • componentWillMount
  • componentWillUpdate
  • showComponentUpdate
  • componentWillReceiveProps

Render Performance

从首次渲染的调用栈来看,React 的渲染过程主要分为以下几个步骤:

    1. Mount 阶段
    1. Render 阶段
    1. Commit 阶段

Mount 阶段

当执行 ReactDOM.render 时会直接调用 legacyRenderSubtreeIntoContainer 方法

legacyRenderSubtreeIntoContainer 方法

会创建 reactRootContainer 对象(也就是挂载的容器对象), reactRootContainer 对象的 _internalRoot 会指向 fiberRoot (FiberRootNode 类),也就是根节点对象。

legacyRenderSubtreeIntoContainer 最终返回挂载组件( App组件 )的实例对象。

Mount 渲染过程

FiberRootNode对象的描述

在 fiberRoot 对象( FiberRootNode类 )中的 current 属性将指向 rootFiber 对象 (根节点Fiber,即 FiberNode 实例)

fiberRoot对象指向 rootFiber 根节点Fiber

挂载创建关系图

updateContainer 函数

updateContainer 函数主要有以下 3 件事:

    1. 获取当前节点的优先级 lane
    1. 结合 lane 创建当前 Fiber 节点 update 对象,并将其入队
    1. 调度当前节点 (rootFiber 节点)

updateContainer

scheduleUpdateOnFiber 函数

scheduleUpdateOnFiber 函数中会获取 Fiber 节点的mode属性判断是否走同步渲染还是异步渲染的逻辑,在 React17 中首次渲染走的是同步渲染的逻辑

scheduleUpdateOnFiber

这里可能有小伙伴会问,Fiber架构不就是异步渲染的么? 我想说的是,Fiber架构的设计初衷确实是为了异步渲染而设计的,但是 Fiber 架构并不能和异步渲染画上等号,我们不难发现,Fiber 架构同时兼容了同步渲染和异步渲染,如下图,决定同步还是异步取决于 mode

mode 决定同步异步

Render 阶段

performSyncWorkOnRoot 函数

核心逻辑在 renderRootSync 函数中

renderRootSync 函数

核心方法有俩个 prepareFreshStackworkLoopSync 函数

renderRootSync 逻辑

prepareFreshStack 函数

主要是有个方法 createWorkInProgress , 用来构建 workInProgress 双缓冲树,通过 alternate 相互指向

createWorkInProgress 构建 work-in-progress 树

当建立好双缓冲树的关系后,我们不难得到以下的关系图

双缓冲树关系图

workLoopSync 函数

当我们构建完 workInProgress Tree 的根节点时,建立 current tree 和 workInProgess Tree 的关联关系后,将进入 workLoopSync 调和阶段。

反复判断 workInProgress 是否为空,如果不为空,就执行 performUnitOfWork 方法 workLoopSync 逻辑

performUnitOfWork 函数

performUnitOfWork 函数的作用是 beginWork 优先创建子节点。 completeUnitOfWork 创建完子节点后判断是否有兄弟节点,有则创建兄弟节点,无则继续向上遍历父节点,直到遍历到根节点为止

performUnitOfWork 逻辑

beginWork 函数

参考文档

1 https://zhuanlan.zhihu.com/p/385319664 2

+ \ No newline at end of file diff --git "a/guide/React/React\347\273\204\344\273\266\346\230\257\345\246\202\344\275\225\351\200\232\344\277\241\347\232\204.html" "b/guide/React/React\347\273\204\344\273\266\346\230\257\345\246\202\344\275\225\351\200\232\344\277\241\347\232\204.html" index b537d01e..9c772ad7 100644 --- "a/guide/React/React\347\273\204\344\273\266\346\230\257\345\246\202\344\275\225\351\200\232\344\277\241\347\232\204.html" +++ "b/guide/React/React\347\273\204\344\273\266\346\230\257\345\246\202\344\275\225\351\200\232\344\277\241\347\232\204.html" @@ -11,7 +11,7 @@ - + @@ -23,8 +23,8 @@ -
Skip to content

React 组件是如何通信的

- +
Skip to content

React 组件是如何通信的

+ \ No newline at end of file diff --git "a/guide/React/diff\347\256\227\346\263\225.html" "b/guide/React/diff\347\256\227\346\263\225.html" index 79676a0d..ecd8a97a 100644 --- "a/guide/React/diff\347\256\227\346\263\225.html" +++ "b/guide/React/diff\347\256\227\346\263\225.html" @@ -11,7 +11,7 @@ - + @@ -23,8 +23,8 @@ -
Skip to content

React 中的 Diff 算法

概要

React Diff 算法主要分单节点和多节点 Diff 算法 在单节点 Diff 算法中,会对比 key 和 tag 是否可以复用 如果 key 和 tag 都相同时,复用当前的 Fiber 节点,标记其他 Fiber 节点为删除 如果 key 不相同,标记删除当前的 Fiber 节点,对比下一个节点 如果 key 相同、tag 不同,则标记删除所有 Fiber 节点,生成新的 Fiber 节点

在多节点 Diff 中,有俩个 for 循环,第一个 for 循环判断可以复用的节点,记录最后可复用节点的 lastIndex 位置

通过 Map 建立节点和下标的对应关系,如果新节点的key可以在 Map 中找到,则复用旧节点,并判断新节点下标和 lastIndex 下标的关系, 如果新节点下标 > lastIndex 下标,说明只需要更新节点,不需要移动位置,更新 lastIndex。 如果新节点下标 < lastIndex,说明需要更新移动位置,不需要更新 lastIndex。

单节点diff算法 (render方法创建的element元素子节点只有一个)

1. 旧节点不存在

  1. 如果旧节点不存在,则直接新增节点

2. 旧节点存在

1 判断 key 和 tag 是否相同,相同则复用节点,更新属性 2 如果 key 相同但 tag 不相同,则删除所有节点 3 如果 key、tag 不同,则不需要复用,旧节点标记为删除

多节点diff算法 (render方法创建的element元素子节点有多个)

多节点diff有俩次 for 循环, 第一次 for 循环判断元素是否需要更新,第二次 for 循环判断元素是否需要移动位置

1 第一次 for 循环比较key和tag, 如果相同则复用, 并用 lastIndex 标记当前可以复用的节点位置

2 遇到不相同时, 跳出第一层 for 循环, 创建一个 Map 对象, 存储旧节点的 key 和 index

  • key不同导致不可复用,立即跳出整个遍历,第一轮遍历结束
  • key 相同 type 不同导致不可复用,会将 oldFiber 标记为 DELETION,并继续遍历

3 在 Map 对象中查找新节点的 key, 如果存在, 则说明新节点可以复用旧节点, 并且判断是否需要移动位置

4 如果 index > lastIndex, 则不需要移动位置, 更新 lastIndex

5 如果 index < lastIndex, 则需要移动位置, 不需要更新 lastIndex

- +
Skip to content

React 中的 Diff 算法

概要

React Diff 算法主要分单节点和多节点 Diff 算法 在单节点 Diff 算法中,会对比 key 和 tag 是否可以复用 如果 key 和 tag 都相同时,复用当前的 Fiber 节点,标记其他 Fiber 节点为删除 如果 key 不相同,标记删除当前的 Fiber 节点,对比下一个节点 如果 key 相同、tag 不同,则标记删除所有 Fiber 节点,生成新的 Fiber 节点

在多节点 Diff 中,有俩个 for 循环,第一个 for 循环判断可以复用的节点,记录最后可复用节点的 lastIndex 位置

通过 Map 建立节点和下标的对应关系,如果新节点的key可以在 Map 中找到,则复用旧节点,并判断新节点下标和 lastIndex 下标的关系, 如果新节点下标 > lastIndex 下标,说明只需要更新节点,不需要移动位置,更新 lastIndex。 如果新节点下标 < lastIndex,说明需要更新移动位置,不需要更新 lastIndex。

单节点diff算法 (render方法创建的element元素子节点只有一个)

1. 旧节点不存在

  1. 如果旧节点不存在,则直接新增节点

2. 旧节点存在

1 判断 key 和 tag 是否相同,相同则复用节点,更新属性 2 如果 key 相同但 tag 不相同,则删除所有节点 3 如果 key、tag 不同,则不需要复用,旧节点标记为删除

多节点diff算法 (render方法创建的element元素子节点有多个)

多节点diff有俩次 for 循环, 第一次 for 循环判断元素是否需要更新,第二次 for 循环判断元素是否需要移动位置

1 第一次 for 循环比较key和tag, 如果相同则复用, 并用 lastIndex 标记当前可以复用的节点位置

2 遇到不相同时, 跳出第一层 for 循环, 创建一个 Map 对象, 存储旧节点的 key 和 index

  • key不同导致不可复用,立即跳出整个遍历,第一轮遍历结束
  • key 相同 type 不同导致不可复用,会将 oldFiber 标记为 DELETION,并继续遍历

3 在 Map 对象中查找新节点的 key, 如果存在, 则说明新节点可以复用旧节点, 并且判断是否需要移动位置

4 如果 index > lastIndex, 则不需要移动位置, 更新 lastIndex

5 如果 index < lastIndex, 则需要移动位置, 不需要更新 lastIndex

+ \ No newline at end of file diff --git "a/guide/React/react\345\274\202\345\270\270\346\234\272\345\210\266.html" "b/guide/React/react\345\274\202\345\270\270\346\234\272\345\210\266.html" index 66a42587..b7cc0f15 100644 --- "a/guide/React/react\345\274\202\345\270\270\346\234\272\345\210\266.html" +++ "b/guide/React/react\345\274\202\345\270\270\346\234\272\345\210\266.html" @@ -11,7 +11,7 @@ - + @@ -23,8 +23,8 @@ -
Skip to content
- +
Skip to content
+ \ No newline at end of file diff --git "a/guide/React/setState\346\230\257\345\220\214\346\255\245\350\277\230\346\230\257\345\274\202\346\255\245\347\232\204.html" "b/guide/React/setState\346\230\257\345\220\214\346\255\245\350\277\230\346\230\257\345\274\202\346\255\245\347\232\204.html" index 6265949f..c1864a37 100644 --- "a/guide/React/setState\346\230\257\345\220\214\346\255\245\350\277\230\346\230\257\345\274\202\346\255\245\347\232\204.html" +++ "b/guide/React/setState\346\230\257\345\220\214\346\255\245\350\277\230\346\230\257\345\274\202\346\255\245\347\232\204.html" @@ -11,7 +11,7 @@ - + @@ -23,7 +23,7 @@ -
Skip to content

setState 是同步还是异步的?

概要

setState 用于状态变更,触发组件的重新渲染,更新视图。

在 React 18 以前,setState 同步还是异步取决于是否处于 isBatchUpdates 字段,true 的话就是异步,否则就是同步

在 React 18 版本所有的 setState 都是异步批量操作

setState

js
// React 15
+    
Skip to content

setState 是同步还是异步的?

概要

setState 用于状态变更,触发组件的重新渲染,更新视图。

在 React 18 以前,setState 同步还是异步取决于是否处于 isBatchUpdates 字段,true 的话就是异步,否则就是同步

在 React 18 版本所有的 setState 都是异步批量操作

setState

js
// React 15
 function enqueueUpdate (component) {
   // isBatchingUpdates 判断当前是否处理批量更新操作
   if (!batchingStrategy.isBatchingUpdates) { // 锁管理器
@@ -331,8 +331,8 @@
   }
 }

最终将输出

this.state.count0 0
 this.state.count1 1
this.state.count0 0
-this.state.count1 1

参考资料

- +this.state.count1 1

参考资料

+ \ No newline at end of file diff --git "a/guide/React/\344\273\200\344\271\210\346\230\257Fiber.html" "b/guide/React/\344\273\200\344\271\210\346\230\257Fiber.html" index 5ad9da68..e38ad6db 100644 --- "a/guide/React/\344\273\200\344\271\210\346\230\257Fiber.html" +++ "b/guide/React/\344\273\200\344\271\210\346\230\257Fiber.html" @@ -11,7 +11,7 @@ - + @@ -23,8 +23,8 @@ -
Skip to content

对 Fiber 的理解

在 React 15 中通过 递归 的形式进行对比,找到需要更新的节点,并同步更新它,在这段时间一直占据着浏览器主线程,可能会给用户带来卡顿的感受(在渲染进程中,js线程和渲染线程是互斥的

在 React 15 以后引入了 Fiber 架构,将对比的过程变成了异步可中断的过程,让出浏览器的使用权,让浏览器处理更高优先级的事情

Fiber 的调和过程(Reconciler)由分成了 beginWork 阶段 和 completeUnitOfWork 阶段。

beginWork 阶段自顶向下,根据当前工作的 Fiber 节点最新的 React Element 子元素与旧 Fiber 节点进行对比,决定是否需要复用旧 Fiber 节点并标记 Fiber 节点是否有副作用。

compeleteUnitOfWork 阶段自底向上构建副作用链表,生成的 DOM 节点挂在 Fiber 的 stateNode 属性

- +
Skip to content

对 Fiber 的理解

在 React 15 中通过 递归 的形式进行对比,找到需要更新的节点,并同步更新它,在这段时间一直占据着浏览器主线程,可能会给用户带来卡顿的感受(在渲染进程中,js线程和渲染线程是互斥的

在 React 15 以后引入了 Fiber 架构,将对比的过程变成了异步可中断的过程,让出浏览器的使用权,让浏览器处理更高优先级的事情

Fiber 的调和过程(Reconciler)由分成了 beginWork 阶段 和 completeUnitOfWork 阶段。

beginWork 阶段自顶向下,根据当前工作的 Fiber 节点最新的 React Element 子元素与旧 Fiber 节点进行对比,决定是否需要复用旧 Fiber 节点并标记 Fiber 节点是否有副作用。

compeleteUnitOfWork 阶段自底向上构建副作用链表,生成的 DOM 节点挂在 Fiber 的 stateNode 属性

+ \ No newline at end of file diff --git "a/guide/React/\345\246\202\344\275\225\350\256\276\350\256\241React\347\273\204\344\273\266.html" "b/guide/React/\345\246\202\344\275\225\350\256\276\350\256\241React\347\273\204\344\273\266.html" index 459ab64d..2b25d3a1 100644 --- "a/guide/React/\345\246\202\344\275\225\350\256\276\350\256\241React\347\273\204\344\273\266.html" +++ "b/guide/React/\345\246\202\344\275\225\350\256\276\350\256\241React\347\273\204\344\273\266.html" @@ -11,7 +11,7 @@ - + @@ -23,8 +23,8 @@ -
Skip to content

如何设计 React 组件

设计分类

  • 展示组件: 只负责 UI 展示,不涉及业务逻辑

  • 业务组件: 复用负责业务逻辑

展示组件

展示组件一般受制于 props, 具有通用性、复用性

业务组件

业务组件一般受制于 state, 具有复用性

组件分类

- +
Skip to content

如何设计 React 组件

设计分类

  • 展示组件: 只负责 UI 展示,不涉及业务逻辑

  • 业务组件: 复用负责业务逻辑

展示组件

展示组件一般受制于 props, 具有通用性、复用性

业务组件

业务组件一般受制于 state, 具有复用性

组件分类

+ \ No newline at end of file diff --git "a/guide/React/\345\270\270\350\247\201\347\232\204\351\227\256\351\242\230.html" "b/guide/React/\345\270\270\350\247\201\347\232\204\351\227\256\351\242\230.html" index 075bca34..766b5750 100644 --- "a/guide/React/\345\270\270\350\247\201\347\232\204\351\227\256\351\242\230.html" +++ "b/guide/React/\345\270\270\350\247\201\347\232\204\351\227\256\351\242\230.html" @@ -11,7 +11,7 @@ - + @@ -23,8 +23,8 @@ -
Skip to content
- +
Skip to content
+ \ No newline at end of file diff --git "a/guide/Redux/\346\272\220\347\240\201\350\247\243\350\257\273.html" "b/guide/Redux/\346\272\220\347\240\201\350\247\243\350\257\273.html" index c1723896..50377dbf 100644 --- "a/guide/Redux/\346\272\220\347\240\201\350\247\243\350\257\273.html" +++ "b/guide/Redux/\346\272\220\347\240\201\350\247\243\350\257\273.html" @@ -11,7 +11,7 @@ - + @@ -23,8 +23,8 @@ -
Skip to content
- +
Skip to content
+ \ No newline at end of file diff --git "a/guide/Redux/\350\256\276\350\256\241\347\220\206\345\277\265.html" "b/guide/Redux/\350\256\276\350\256\241\347\220\206\345\277\265.html" index eaf304e2..be9828e0 100644 --- "a/guide/Redux/\350\256\276\350\256\241\347\220\206\345\277\265.html" +++ "b/guide/Redux/\350\256\276\350\256\241\347\220\206\345\277\265.html" @@ -11,7 +11,7 @@ - + @@ -23,8 +23,8 @@ -
Skip to content
- +
Skip to content
+ \ No newline at end of file diff --git "a/guide/ai/RAG\344\271\213\346\213\206\345\210\206\346\225\260\346\215\256.html" "b/guide/ai/Embedding\344\271\213\346\213\206\345\210\206\346\225\260\346\215\256.html" similarity index 66% rename from "guide/ai/RAG\344\271\213\346\213\206\345\210\206\346\225\260\346\215\256.html" rename to "guide/ai/Embedding\344\271\213\346\213\206\345\210\206\346\225\260\346\215\256.html" index 68606130..23a74320 100644 --- "a/guide/ai/RAG\344\271\213\346\213\206\345\210\206\346\225\260\346\215\256.html" +++ "b/guide/ai/Embedding\344\271\213\346\213\206\345\210\206\346\225\260\346\215\256.html" @@ -11,7 +11,7 @@ - + @@ -23,8 +23,8 @@ -
Skip to content
- +
Skip to content
+ \ No newline at end of file diff --git "a/guide/ai/OutputParser\346\236\204\345\273\272\346\240\274\345\274\217\345\214\226\350\276\223\345\207\272.html" "b/guide/ai/OutputParser\346\236\204\345\273\272\346\240\274\345\274\217\345\214\226\350\276\223\345\207\272.html" index fdd6eff2..ab676e50 100644 --- "a/guide/ai/OutputParser\346\236\204\345\273\272\346\240\274\345\274\217\345\214\226\350\276\223\345\207\272.html" +++ "b/guide/ai/OutputParser\346\236\204\345\273\272\346\240\274\345\274\217\345\214\226\350\276\223\345\207\272.html" @@ -11,7 +11,7 @@ - + @@ -23,7 +23,7 @@ -
Skip to content

OutputParser

OutputParser是一个用于解析模型输出的工具类,它可以帮助用户将模型输出解析为用户需要的格式。

String Output Parser

StringOutputParser是OutputParser的一个实现类,它可以将模型输出解析为字符串。

前面的例子中,我们使用了StringOutputParser来解析模型输出,这里就不过多赘述了。

StructuredOutputParser (结构化的输出)

StructuredOutputParser是OutputParser的另一个实现类,它可以将模型输出解析为结构化的数据。

例如,我们可以将模型输出解析为JSON格式的数据,这样我们就可以更方便地处理模型输出。

下面是一个使用StructuredOutputParser的例子:

js
import { StructuredOutputParser } from "langchain/output_parsers";
+    
Skip to content

OutputParser

OutputParser是一个用于解析模型输出的工具类,它可以帮助用户将模型输出解析为用户需要的格式。

String Output Parser

StringOutputParser是OutputParser的一个实现类,它可以将模型输出解析为字符串。

前面的例子中,我们使用了StringOutputParser来解析模型输出,这里就不过多赘述了。

StructuredOutputParser (结构化的输出)

StructuredOutputParser是OutputParser的另一个实现类,它可以将模型输出解析为结构化的数据。

例如,我们可以将模型输出解析为JSON格式的数据,这样我们就可以更方便地处理模型输出。

下面是一个使用StructuredOutputParser的例子:

js
import { StructuredOutputParser } from "langchain/output_parsers";
 import { PromptTemplate } from "@langchain/core/prompts";
 
 const parser = StructuredOutputParser.fromNamesAndDescriptions({
@@ -215,8 +215,8 @@
 const fixParser = OutputFixingParser.fromLLM(model, parser);
 const output = await fixParser.parse(JSON.stringify(wrongOutput));
 
-console.log(output);

可能会有朋友问,如果我把用户的问题也给 fixParser,这样不就得到一个正确的答案和正确的格式了么? 在我们的 demo 中当然是可以的,但实际工程中,引导 llm 返回数据的 prompt 可能非常巨大,非常消耗 token,我们使用 fixParser 就是用较少的成本去修复这个输出,来节约重复调用的成本。所以把原文也给 fixParser 的话,就达不到成本节约的目的了。

在进一步节约成本的背景下,我们是可以用对 GPT4 的错误输出用 GPT3.5 的 fixer 来修复,甚至是用一些开源模型来进行修复,因为在这个场景下,并不需要模型具有太高的质量,通过多模型的协同来降低成本。

- +console.log(output);

可能会有朋友问,如果我把用户的问题也给 fixParser,这样不就得到一个正确的答案和正确的格式了么? 在我们的 demo 中当然是可以的,但实际工程中,引导 llm 返回数据的 prompt 可能非常巨大,非常消耗 token,我们使用 fixParser 就是用较少的成本去修复这个输出,来节约重复调用的成本。所以把原文也给 fixParser 的话,就达不到成本节约的目的了。

在进一步节约成本的背景下,我们是可以用对 GPT4 的错误输出用 GPT3.5 的 fixer 来修复,甚至是用一些开源模型来进行修复,因为在这个场景下,并不需要模型具有太高的质量,通过多模型的协同来降低成本。

+ \ No newline at end of file diff --git "a/guide/ai/RAG \346\243\200\347\264\242\345\242\236\345\274\272\347\224\237\346\210\220\347\232\204\346\265\201\347\250\213.html" "b/guide/ai/RAG \346\243\200\347\264\242\345\242\236\345\274\272\347\224\237\346\210\220\347\232\204\346\265\201\347\250\213.html" index 9a5c282b..97a3e92c 100644 --- "a/guide/ai/RAG \346\243\200\347\264\242\345\242\236\345\274\272\347\224\237\346\210\220\347\232\204\346\265\201\347\250\213.html" +++ "b/guide/ai/RAG \346\243\200\347\264\242\345\242\236\345\274\272\347\224\237\346\210\220\347\232\204\346\265\201\347\250\213.html" @@ -11,7 +11,7 @@ - + @@ -23,8 +23,8 @@ -
Skip to content

RAG 检索增强生成的流程

RAG 其全称是 Retrieval Augmented Generation,可以被翻译成 检索增强生成技术,从标题上也能了解其核心的流程 检索 => 增强 => 生成。

LLM 的局限

在介绍 RAG 之前,我们先来了解一下 LLM 的局限性。

首先是幻觉问题(hallucination),LLM 底层还不具备真正的逻辑推理能力,是根据大量的数据进行概率性预测,所以在某些情况下,LLM 会生成一些不合理的答案。

其次是对领域知识的欠缺,造成这个问题主要是俩个原因,第一个是对知识的更新慢,另一个是对专业领域的知识训练样本不足导致。

RAG 的优势

当我们了解了 LLM 的局限性后,RAG 会尽可能提供与答案相关的上下文,来增强它正确输出的可能性。

RAG 的优势主要体现在以下几个方面:

  1. 用户输入提问
  2. 检索:根据用户提问对 向量数据库 进行相似性检测,查找与回答用户问题最相关的内容
  3. 增强:根据检索的结果,生成 prompt。 一般都会涉及 “仅依赖下述信息源来回答问题” 这种限制 LLM 参考信息源的语句,来减少幻想,让回答更加聚焦
  4. 生成:将增强后的 prompt 传递给 LLM,返回数据给用户

所以 RAG 就是哪里有问题解决哪里,既然大模型无法获得最新和内部的数据集,那我们就使用外挂的向量数据库为 LLM 提供最新和内部的数据库。既然大模型有幻想问题,我们就将回答问题所需要的信息和知识编码到上下文中,强制大模型只参考这些内容进行回答。

注意:LLM 是逻辑推理引擎,而不是信息引擎。所以,由外挂的向量数据库提供最有效的知识,然后由 LLM 根据知识进行推理,提供有价值的回复。

RAG 流程

输出结果

后续章节,在下将针对 RAG 的各个流程做详细的介绍。

- +
Skip to content

RAG 检索增强生成的流程

RAG 其全称是 Retrieval Augmented Generation,可以被翻译成 检索增强生成技术,从标题上也能了解其核心的流程 检索 => 增强 => 生成。

LLM 的局限

在介绍 RAG 之前,我们先来了解一下 LLM 的局限性。

首先是幻觉问题(hallucination),LLM 底层还不具备真正的逻辑推理能力,是根据大量的数据进行概率性预测,所以在某些情况下,LLM 会生成一些不合理的答案。

其次是对领域知识的欠缺,造成这个问题主要是俩个原因,第一个是对知识的更新慢,另一个是对专业领域的知识训练样本不足导致。

RAG 的优势

当我们了解了 LLM 的局限性后,RAG 会尽可能提供与答案相关的上下文,来增强它正确输出的可能性。

RAG 的优势主要体现在以下几个方面:

  1. 用户输入提问
  2. 检索:根据用户提问对 向量数据库 进行相似性检测,查找与回答用户问题最相关的内容
  3. 增强:根据检索的结果,生成 prompt。 一般都会涉及 “仅依赖下述信息源来回答问题” 这种限制 LLM 参考信息源的语句,来减少幻想,让回答更加聚焦
  4. 生成:将增强后的 prompt 传递给 LLM,返回数据给用户

所以 RAG 就是哪里有问题解决哪里,既然大模型无法获得最新和内部的数据集,那我们就使用外挂的向量数据库为 LLM 提供最新和内部的数据库。既然大模型有幻想问题,我们就将回答问题所需要的信息和知识编码到上下文中,强制大模型只参考这些内容进行回答。

注意:LLM 是逻辑推理引擎,而不是信息引擎。所以,由外挂的向量数据库提供最有效的知识,然后由 LLM 根据知识进行推理,提供有价值的回复。

RAG 流程

输出结果

后续章节,在下将针对 RAG 的各个流程做详细的介绍。

+ \ No newline at end of file diff --git "a/guide/ai/RAG\344\271\213\345\212\240\350\275\275\346\225\260\346\215\256.html" "b/guide/ai/RAG\344\271\213\345\212\240\350\275\275\346\225\260\346\215\256.html" deleted file mode 100644 index 55e36abc..00000000 --- "a/guide/ai/RAG\344\271\213\345\212\240\350\275\275\346\225\260\346\215\256.html" +++ /dev/null @@ -1,110 +0,0 @@ - - - - - - RAG 之加载数据 | 个人知识库 - - - - - - - - - - - - - - - - - - - -
Skip to content

RAG 之加载数据

因为 RAG 本质是给 Chat Bot 额外挂在数据源,而数据源存在的形式是多种多样的,有可能是文件/网页/数据库/代码等等其情况。

针对这个情况,langchain 提供了一系列开箱即用的数据加载器 (loader),方便用户快速加载数据。

Document 对象

Document 对象你可以理解成 langchain 对所有类型的数据的一个统一抽象,其中包含

pageContent 文本内容,即文档对象对应的文本数据 metadata 元数据,文本数据对应的元数据,例如 原始文档的标题、页数等信息,可以用于后面 Retriever 基于此进行筛选。

TypeScript
// Document 对象的定义
-interface Document {
-  pageContent: string;
-  metadata: Record<string, any>;
-}
// Document 对象的定义
-interface Document {
-  pageContent: string;
-  metadata: Record<string, any>;
-}

Loader

RAG 的第一步就是加载数据,而加载数据的方式有很多种,langchain 提供了一系列的 loader,方便用户快速加载数据。

下面将简单举一俩个 loader 的例子,更多的 loader 可以查看 传送门

DirectoryLoader

根据目录加载不同的文件数据

js
// DirectoryLoader 加载文件夹内的文件内容
-
-import { DirectoryLoader } from "langchain/document_loaders/fs/directory";
-import { TextLoader } from "langchain/document_loaders/fs/text";
-import { PDFLoader } from "langchain/document_loaders/fs/pdf";
-
-const loader = new DirectoryLoader(
-    "./data",
-    {
-      // 通过文件后缀名来指定加载器
-      ".pdf": (path) => new PDFLoader(path, { splitPages: false }),
-      ".txt": (path) => new TextLoader(path),
-    }
-  );
-const docs = await loader.load();
-
-console.log(docs);
// DirectoryLoader 加载文件夹内的文件内容
-
-import { DirectoryLoader } from "langchain/document_loaders/fs/directory";
-import { TextLoader } from "langchain/document_loaders/fs/text";
-import { PDFLoader } from "langchain/document_loaders/fs/pdf";
-
-const loader = new DirectoryLoader(
-    "./data",
-    {
-      // 通过文件后缀名来指定加载器
-      ".pdf": (path) => new PDFLoader(path, { splitPages: false }),
-      ".txt": (path) => new TextLoader(path),
-    }
-  );
-const docs = await loader.load();
-
-console.log(docs);

输出结果如下:👇

输出结果

WebLoader

对于 LLM 所需要提取的信息是网页中静态的信息时,一般使用 Cheerio 用来提取和处理 html 内容,类似于 python 中的 BeautifulSoup。 这两者都是只能针对静态的 html,无法运行其中的 js, 对大部分场景都是够用的。

js
import { CheerioWebBaseLoader } from "@langchain/community/document_loaders/web/cheerio";
-import "cheerio";
-
-const loader = new CheerioWebBaseLoader(
-  "https://enson0131.github.io/vitePress-blob/",
-  {
-    selector: "h3",
-  }
-);
-
-const docs = await loader.load();
-
-console.log(`******爬取网页数据*********`);
-console.log(docs);
-console.log(`******爬取网页数据*********`);
import { CheerioWebBaseLoader } from "@langchain/community/document_loaders/web/cheerio";
-import "cheerio";
-
-const loader = new CheerioWebBaseLoader(
-  "https://enson0131.github.io/vitePress-blob/",
-  {
-    selector: "h3",
-  }
-);
-
-const docs = await loader.load();
-
-console.log(`******爬取网页数据*********`);
-console.log(docs);
-console.log(`******爬取网页数据*********`);

输出结果

Search API

在 langchain 中 SearchApiLoader 和 SerpAPILoader 这个两个提供的都是接入搜索的能力,免费计划都是每个月 100 次 search 能力,除了 google 外,也支持 baidu/bing 等常用的搜索引擎。

首先我们需要在 SearchAPI 注册一个账号,然后获取到 API Key,然后将 API Key 设置为环境变量 SEARCH_KEY

js
import { SearchApiLoader } from "@langchain/community/document_loaders/web/searchapi";
-import 'dotenv/config'
-// https://js.langchain.com/v0.2/docs/integrations/document_loaders/web_loaders/searchapi
-const apiKey = process.env["SEARCH_KEY"]
-const question = "什么 github copliot"
-const searchLoader = new SearchApiLoader({ q: question, apiKey, engine: "google" });
-const searchRes = await searchLoader.load();
import { SearchApiLoader } from "@langchain/community/document_loaders/web/searchapi";
-import 'dotenv/config'
-// https://js.langchain.com/v0.2/docs/integrations/document_loaders/web_loaders/searchapi
-const apiKey = process.env["SEARCH_KEY"]
-const question = "什么 github copliot"
-const searchLoader = new SearchApiLoader({ q: question, apiKey, engine: "google" });
-const searchRes = await searchLoader.load();

输出结果如下:👇

输出结果

参考文档

- - - - \ No newline at end of file diff --git "a/guide/ai/RAG\344\271\213\345\220\221\351\207\217\346\225\260\346\215\256\345\272\223.html" "b/guide/ai/RAG\344\271\213\345\220\221\351\207\217\346\225\260\346\215\256\345\272\223.html" deleted file mode 100644 index d4178640..00000000 --- "a/guide/ai/RAG\344\271\213\345\220\221\351\207\217\346\225\260\346\215\256\345\272\223.html" +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - 个人知识库 | 个人知识库 - - - - - - - - - - - - - - - - - - - -
Skip to content
- - - - \ No newline at end of file diff --git "a/guide/ai/Retriever \345\270\270\350\247\201\347\232\204\344\274\230\345\214\226\346\226\271\345\274\217.html" "b/guide/ai/Retriever \345\270\270\350\247\201\347\232\204\344\274\230\345\214\226\346\226\271\345\274\217.html" index 9435c658..ff1ce2ae 100644 --- "a/guide/ai/Retriever \345\270\270\350\247\201\347\232\204\344\274\230\345\214\226\346\226\271\345\274\217.html" +++ "b/guide/ai/Retriever \345\270\270\350\247\201\347\232\204\344\274\230\345\214\226\346\226\271\345\274\217.html" @@ -11,7 +11,7 @@ - + @@ -23,8 +23,8 @@ -
Skip to content
- +
Skip to content
+ \ No newline at end of file diff --git "a/guide/ai/RAG\344\271\213embeding.html" "b/guide/ai/Retriever\344\271\213\345\220\221\351\207\217\346\225\260\346\215\256\345\272\223.html" similarity index 66% rename from "guide/ai/RAG\344\271\213embeding.html" rename to "guide/ai/Retriever\344\271\213\345\220\221\351\207\217\346\225\260\346\215\256\345\272\223.html" index 36ff9011..7fe12c3b 100644 --- "a/guide/ai/RAG\344\271\213embeding.html" +++ "b/guide/ai/Retriever\344\271\213\345\220\221\351\207\217\346\225\260\346\215\256\345\272\223.html" @@ -11,7 +11,7 @@ - + @@ -23,8 +23,8 @@ -
Skip to content
- +
Skip to content
+ \ No newline at end of file diff --git "a/guide/ai/langchain\345\277\253\351\200\237\345\205\245\351\227\250.html" "b/guide/ai/langchain\345\277\253\351\200\237\345\205\245\351\227\250.html" index 7d9f5f03..7454771f 100644 --- "a/guide/ai/langchain\345\277\253\351\200\237\345\205\245\351\227\250.html" +++ "b/guide/ai/langchain\345\277\253\351\200\237\345\205\245\351\227\250.html" @@ -11,7 +11,7 @@ - + @@ -23,7 +23,7 @@ -
Skip to content

LangChain 快速入门

安装

要安装这个包,你可以使用 npm 或 yarn:

bash
yarn add langchain
yarn add langchain

安装环境

node >= 18.x

什么是 LCEL (LangChain Expression Language)

LangChain Expression Language is a way to create arbitrary custom chains. It is built on the Runnable protocol.

LCEL 无论是 python 还是 js 版本都在主推的新设计,能创建自定义的链,它是基于 Runnable 协议构建的。

通过 LangChain 加载大模型

本地大模型

在 mac 平台下,推荐用 ollama,使用简单,下载好模型后,点击这个 app,就会自动在 http://localhost:11434 起一个 llm 的服务。

安装 llama3 模型

可以通过 ollama list 查看所有的模型,然后通过 ollama pull 安装模型。

bash
# 模型列表参考:https://ollama.com/library
+    
Skip to content

LangChain 快速入门

安装

要安装这个包,你可以使用 npm 或 yarn:

bash
yarn add langchain
yarn add langchain

安装环境

node >= 18.x

什么是 LCEL (LangChain Expression Language)

LangChain Expression Language is a way to create arbitrary custom chains. It is built on the Runnable protocol.

LCEL 无论是 python 还是 js 版本都在主推的新设计,能创建自定义的链,它是基于 Runnable 协议构建的。

通过 LangChain 加载大模型

本地大模型

在 mac 平台下,推荐用 ollama,使用简单,下载好模型后,点击这个 app,就会自动在 http://localhost:11434 起一个 llm 的服务。

安装 llama3 模型

可以通过 ollama list 查看所有的模型,然后通过 ollama pull 安装模型。

bash
# 模型列表参考:https://ollama.com/library
 ollama pull [model]
# 模型列表参考:https://ollama.com/library
 ollama pull [model]

目前下载了一个 ollama3 的模型

初始状态图

当我们在本地启动了一个模型后,我们就可以通过 LangChain 来调用这个模型了。

js
import { Ollama } from '@langchain/community/llms/ollama';
 
@@ -93,8 +93,8 @@
 
 const res = await ernieTurbo.invoke(messages);
 
-console.log(res);

输出结果

⚠️注意: 如果出现 API 调用次数有所限制,需要在 https://console.bce.baidu.com/qianfan/ais/console/onlineService 开通对应的模型服务。

LCEL 有什么优势

LCEL 从底层设计的目标就是支持 从原型到生产 完整流程不需要修改任何代码,也就是我们在写的任何原型代码不需要太多的改变就能支持生产级别的各种特性(比如并行、steaming 等),具体来说会有这些优势:

  • 并行: 只要是整个 chain 中有可以并行的步骤就会自动的并行,来减少使用时的延迟。
  • 自动的重试和 fallback: 大部分 chain 的组成部分都有自动的重试(比如因为网络原因的失败)和回退机制,来解决很多请求的出错问题。
  • 对 chain 中间结果的访问,在旧的写法中很难访问中间的结果,而 LCEL 中可以方便的通过访问中间结果来进行调试和记录。
  • LCEL 会自动支持 LangSimith 进行可视化和记录。

一条 Chain 组成的每个模块都是继承自 Runnable 这个接口,而一条 Chain 也是继承自这个接口,所以一条 Chain 也可以很自然的成为另一个 Chain 的一个模块。

任意的 Runnable 对象,都有几个常用的标准调用接口:

  • invoke 基础调用
  • batch 批量调用
  • stream 流式返回结果
  • streamLog 流式返回结果,并返回中间的运行结果

参考文章

- +console.log(res);

输出结果

⚠️注意: 如果出现 API 调用次数有所限制,需要在 https://console.bce.baidu.com/qianfan/ais/console/onlineService 开通对应的模型服务。

LCEL 有什么优势

LCEL 从底层设计的目标就是支持 从原型到生产 完整流程不需要修改任何代码,也就是我们在写的任何原型代码不需要太多的改变就能支持生产级别的各种特性(比如并行、steaming 等),具体来说会有这些优势:

  • 并行: 只要是整个 chain 中有可以并行的步骤就会自动的并行,来减少使用时的延迟。
  • 自动的重试和 fallback: 大部分 chain 的组成部分都有自动的重试(比如因为网络原因的失败)和回退机制,来解决很多请求的出错问题。
  • 对 chain 中间结果的访问,在旧的写法中很难访问中间的结果,而 LCEL 中可以方便的通过访问中间结果来进行调试和记录。
  • LCEL 会自动支持 LangSimith 进行可视化和记录。

一条 Chain 组成的每个模块都是继承自 Runnable 这个接口,而一条 Chain 也是继承自这个接口,所以一条 Chain 也可以很自然的成为另一个 Chain 的一个模块。

任意的 Runnable 对象,都有几个常用的标准调用接口:

  • invoke 基础调用
  • batch 批量调用
  • stream 流式返回结果
  • streamLog 流式返回结果,并返回中间的运行结果

参考文章

+ \ No newline at end of file diff --git "a/guide/ai/\344\273\200\344\271\210\346\230\257langchain.html" "b/guide/ai/\344\273\200\344\271\210\346\230\257langchain.html" index 3ad3ec57..5af0bcdb 100644 --- "a/guide/ai/\344\273\200\344\271\210\346\230\257langchain.html" +++ "b/guide/ai/\344\273\200\344\271\210\346\230\257langchain.html" @@ -11,7 +11,7 @@ - + @@ -23,8 +23,8 @@ -
Skip to content

什么是 LangChain

LangChain 是一个用于开发由大型语言模型 (LLMs) 驱动的应用程序的框架。

为什么是 LangChain

因为 LLM 的 API 只是提供了一个非常基础的调用方式,当我们需要构建一个复杂的 Chat Bot 时,就需要考虑如何保存聊天的上下文、网络搜索、加载 PDF 等工程问题, 而LangChain 提供了一种解决方案,让开发者可以专注于业务逻辑的开发。

足够的流行度和认可度,目前已经在 Github 获得 83k star,并且其上升速度非常恐怖:

Star History Chart

而 LangChain.js 并不是 Python 版本的套壳,而是一个完整的团队从 0 开始构建的生态,足以看出官方对 JavaScript 生态的重视:

Star History Chart

基于此,在下将以 LangChain.js 为例,去使用大模型领域最流行的框架去构建应用,感受大模型的魅力。

支持的环境

  • Node.js (ESM and CommonJS) - 18.x, 19.x, 20.x
  • Cloudflare Workers Cloudflare
  • Vercel / Next.js (Browser, Serverless and Edge functions)
  • Supabase Edge Functions Supabase
  • Browser
  • Deno

相关文档

- +
Skip to content

什么是 LangChain

LangChain 是一个用于开发由大型语言模型 (LLMs) 驱动的应用程序的框架。

为什么是 LangChain

因为 LLM 的 API 只是提供了一个非常基础的调用方式,当我们需要构建一个复杂的 Chat Bot 时,就需要考虑如何保存聊天的上下文、网络搜索、加载 PDF 等工程问题, 而LangChain 提供了一种解决方案,让开发者可以专注于业务逻辑的开发。

足够的流行度和认可度,目前已经在 Github 获得 83k star,并且其上升速度非常恐怖:

Star History Chart

而 LangChain.js 并不是 Python 版本的套壳,而是一个完整的团队从 0 开始构建的生态,足以看出官方对 JavaScript 生态的重视:

Star History Chart

基于此,在下将以 LangChain.js 为例,去使用大模型领域最流行的框架去构建应用,感受大模型的魅力。

支持的环境

  • Node.js (ESM and CommonJS) - 18.x, 19.x, 20.x
  • Cloudflare Workers Cloudflare
  • Vercel / Next.js (Browser, Serverless and Edge functions)
  • Supabase Edge Functions Supabase
  • Browser
  • Deno

相关文档

+ \ No newline at end of file diff --git "a/guide/ai/\346\236\204\345\273\272\345\217\257\345\244\215\347\224\250\347\232\204PromptTemplate.html" "b/guide/ai/\346\236\204\345\273\272\345\217\257\345\244\215\347\224\250\347\232\204PromptTemplate.html" index 6a3c03d5..fa0a8472 100644 --- "a/guide/ai/\346\236\204\345\273\272\345\217\257\345\244\215\347\224\250\347\232\204PromptTemplate.html" +++ "b/guide/ai/\346\236\204\345\273\272\345\217\257\345\244\215\347\224\250\347\232\204PromptTemplate.html" @@ -11,7 +11,7 @@ - + @@ -23,7 +23,7 @@ -
Skip to content

构建可复用的 PromptTemplate

Prompt 是大模型的核心,传统的方式一般是通过字符串或者字符串模版来构建 Prompt,但是这种方式不够灵活,也不够易用。为了解决这个问题,LangChain 引入了 PromptTemplate,它是一个可以复用的 Prompt 模版,可以通过参数化的方式来构建 Prompt。

基础的 Prompt 模版使用

js
// 基础的 Prompt 模版使用
+    
Skip to content

构建可复用的 PromptTemplate

Prompt 是大模型的核心,传统的方式一般是通过字符串或者字符串模版来构建 Prompt,但是这种方式不够灵活,也不够易用。为了解决这个问题,LangChain 引入了 PromptTemplate,它是一个可以复用的 Prompt 模版,可以通过参数化的方式来构建 Prompt。

基础的 Prompt 模版使用

js
// 基础的 Prompt 模版使用
 import { PromptTemplate } from "@langchain/core/prompts";
 
 const greetingPrompt = new PromptTemplate({
@@ -147,8 +147,8 @@
     text: "你好,世界",
 })
 
-console.log(res);

组合多个 Prompt 模版

可以通过 PipelinePromptTemplate 组合多个 Prompt 模版,这样可以更好的复用和管理 Prompt 模版。

在 PipelinePromptTemplate 有两个核心的概念:

  • pipelinePrompts,一组 object,每个 object 表示 prompt 运行后赋值给 name 变量
  • finalPrompt,表示最终输出的 prompt
- +console.log(res);

组合多个 Prompt 模版

可以通过 PipelinePromptTemplate 组合多个 Prompt 模版,这样可以更好的复用和管理 Prompt 模版。

在 PipelinePromptTemplate 有两个核心的概念:

  • pipelinePrompts,一组 object,每个 object 表示 prompt 运行后赋值给 name 变量
  • finalPrompt,表示最终输出的 prompt
+ \ No newline at end of file diff --git "a/guide/canvas/Canvas\345\260\272\345\257\270\345\217\212\345\210\206\350\276\250\347\216\207\347\237\253\346\255\243.html" "b/guide/canvas/Canvas\345\260\272\345\257\270\345\217\212\345\210\206\350\276\250\347\216\207\347\237\253\346\255\243.html" index 8f4c0790..939c789b 100644 --- "a/guide/canvas/Canvas\345\260\272\345\257\270\345\217\212\345\210\206\350\276\250\347\216\207\347\237\253\346\255\243.html" +++ "b/guide/canvas/Canvas\345\260\272\345\257\270\345\217\212\345\210\206\350\276\250\347\216\207\347\237\253\346\255\243.html" @@ -11,7 +11,7 @@ - + @@ -23,7 +23,7 @@ -
Skip to content

Canvas 尺寸与分辨率矫正

前言

Canvas 的默认大小为 300 像素 ×150 像素(宽 × 高,像素的单位是 px)

html
<canvas id="tutorial" width="150" height="150"></canvas>
<canvas id="tutorial" width="150" height="150"></canvas>

canvas 看起来和 img 元素很相像,唯一的不同就是它并没有 src 和 alt 属性。实际上,canvas 标签只有两个属性: width 和 height。

正文

设置画布的 css 大小

canvas 可以使用CSS来定义大小,但在绘制时图像会伸缩以适应它的框架尺寸:如果 CSS 的尺寸与初始画布的比例不一致,它会出现扭曲。

假设一个场景,当我们给 canvas 设置了 css 的宽高 500px * 500px, 但是我们在 canvas 中绘制的图形是 100px * 100px, 那么最终的图形会被拉伸,如下图所示:

html
<canvas id="test-canvas"></canvas>
+    
Skip to content

Canvas 尺寸与分辨率矫正

前言

Canvas 的默认大小为 300 像素 ×150 像素(宽 × 高,像素的单位是 px)

html
<canvas id="tutorial" width="150" height="150"></canvas>
<canvas id="tutorial" width="150" height="150"></canvas>

canvas 看起来和 img 元素很相像,唯一的不同就是它并没有 src 和 alt 属性。实际上,canvas 标签只有两个属性: width 和 height。

正文

设置画布的 css 大小

canvas 可以使用CSS来定义大小,但在绘制时图像会伸缩以适应它的框架尺寸:如果 CSS 的尺寸与初始画布的比例不一致,它会出现扭曲。

假设一个场景,当我们给 canvas 设置了 css 的宽高 500px * 500px, 但是我们在 canvas 中绘制的图形是 100px * 100px, 那么最终的图形会被拉伸,如下图所示:

html
<canvas id="test-canvas"></canvas>
 <script>
     const canvas = document.getElementById('test-canvas');
     const ctx = canvas.getContext('2d');
@@ -163,8 +163,8 @@
 // 这时候我们还需要重新缩放 ctx
 const ctx = canvas.getContext('2d');
 ctx.setTransform(1, 0, 0, 1, 0, 0); // scale 前先恢复变换矩阵,不然会重复 scale
-ctx.scale(dpr, dpr);

参考文档

- +ctx.scale(dpr, dpr);

参考文档

+ \ No newline at end of file diff --git "a/guide/canvas/\345\217\257\350\247\206\345\214\272\345\237\237\345\206\205\346\270\262\346\237\223\346\217\220\351\253\230Canvas\344\271\246\345\206\231\346\200\247\350\203\275.html" "b/guide/canvas/\345\217\257\350\247\206\345\214\272\345\237\237\345\206\205\346\270\262\346\237\223\346\217\220\351\253\230Canvas\344\271\246\345\206\231\346\200\247\350\203\275.html" index ae6cc120..872cc020 100644 --- "a/guide/canvas/\345\217\257\350\247\206\345\214\272\345\237\237\345\206\205\346\270\262\346\237\223\346\217\220\351\253\230Canvas\344\271\246\345\206\231\346\200\247\350\203\275.html" +++ "b/guide/canvas/\345\217\257\350\247\206\345\214\272\345\237\237\345\206\205\346\270\262\346\237\223\346\217\220\351\253\230Canvas\344\271\246\345\206\231\346\200\247\350\203\275.html" @@ -11,7 +11,7 @@ - + @@ -23,7 +23,7 @@ -
Skip to content

可视区域内渲染提高 Canvas 的书写性能

前言

上一节我们通过离屏渲染提高了 Canvas 的渲染性能,但是离屏渲染也有一些缺点,比如会增加内存的使用,而且在某些场景下,离屏渲染的性能并不会比直接在 Canvas 上绘制要高。本节我们将介绍如何通过可视区域内渲染提高 Canvas 的书写性能。

前提

一般我们说的可视区域内渲染,是指在 Canvas 上只绘制可视区域内的内容,而不是绘制整个 Canvas 的内容。这样做的好处是可以减少 Canvas 的绘制区域,从而提高 Canvas 的渲染性能。

对于 Canvas 而言,无法无限制地扩大 Canvas 的面积,因此浏览器对 Canvas 的大小也有一定的限制。从 MDN 文档 可知, 在 Chrome 浏览器中,Canvas 的大小限制为 32767px * 32767px。由于 Canvas 的大小限制,因此我们在实现 无限画布 的功能时,不能无限拓展 Canvas 的大小,可以通过坐标的切换,来实现无限画布的功能。

实现无限画布

实现思路

记初始坐标A (x, y), 横向滚动距离为 scrollX, 纵向滚动距离为 scrollY

在初始状态下, scrollX、scrollY 均为 0

初始状态图

假设现在,我们在水平方向向右滚动了scrollX,垂直方向向下滚动scrollY。那么滚动后的坐标就是

x1 = x - scrollX

y1 = y - scrollY

这里大家可能会有疑惑,为什么是减法呢?因为向下滚动后,绘制的图形应该是往上移动的,因此我们需要减去滚动的距离。

滚动后的状态图

在代码中,我们可以通过监听 Canvas 的 WheelEvent 事件,来获取滚动的距离,然后根据上面的公式计算出滚动后的坐标,最后重新绘制 Canvas。

具体实现如下

jsx
ctx.clearRect(0, 0, window.innerWidth, window.innerHeight);
+    
Skip to content

可视区域内渲染提高 Canvas 的书写性能

前言

上一节我们通过离屏渲染提高了 Canvas 的渲染性能,但是离屏渲染也有一些缺点,比如会增加内存的使用,而且在某些场景下,离屏渲染的性能并不会比直接在 Canvas 上绘制要高。本节我们将介绍如何通过可视区域内渲染提高 Canvas 的书写性能。

前提

一般我们说的可视区域内渲染,是指在 Canvas 上只绘制可视区域内的内容,而不是绘制整个 Canvas 的内容。这样做的好处是可以减少 Canvas 的绘制区域,从而提高 Canvas 的渲染性能。

对于 Canvas 而言,无法无限制地扩大 Canvas 的面积,因此浏览器对 Canvas 的大小也有一定的限制。从 MDN 文档 可知, 在 Chrome 浏览器中,Canvas 的大小限制为 32767px * 32767px。由于 Canvas 的大小限制,因此我们在实现 无限画布 的功能时,不能无限拓展 Canvas 的大小,可以通过坐标的切换,来实现无限画布的功能。

实现无限画布

实现思路

记初始坐标A (x, y), 横向滚动距离为 scrollX, 纵向滚动距离为 scrollY

在初始状态下, scrollX、scrollY 均为 0

初始状态图

假设现在,我们在水平方向向右滚动了scrollX,垂直方向向下滚动scrollY。那么滚动后的坐标就是

x1 = x - scrollX

y1 = y - scrollY

这里大家可能会有疑惑,为什么是减法呢?因为向下滚动后,绘制的图形应该是往上移动的,因此我们需要减去滚动的距离。

滚动后的状态图

在代码中,我们可以通过监听 Canvas 的 WheelEvent 事件,来获取滚动的距离,然后根据上面的公式计算出滚动后的坐标,最后重新绘制 Canvas。

具体实现如下

jsx
ctx.clearRect(0, 0, window.innerWidth, window.innerHeight);
 ctx.save();
 ctx.translate(scrollX, scrollY);
 // 绘制相关的逻辑
@@ -225,8 +225,8 @@
       ctx.restore();
     },
     []
-);

实现效果

canvas

具体代码

参考文章

- +);

实现效果

canvas

具体代码

参考文章

+ \ No newline at end of file diff --git "a/guide/canvas/\345\246\202\344\275\225\345\234\250Canvas\347\224\273\346\235\277\344\270\212\350\207\252\347\224\261\344\271\246\345\206\231.html" "b/guide/canvas/\345\246\202\344\275\225\345\234\250Canvas\347\224\273\346\235\277\344\270\212\350\207\252\347\224\261\344\271\246\345\206\231.html" index 7582a96f..8bf218ee 100644 --- "a/guide/canvas/\345\246\202\344\275\225\345\234\250Canvas\347\224\273\346\235\277\344\270\212\350\207\252\347\224\261\344\271\246\345\206\231.html" +++ "b/guide/canvas/\345\246\202\344\275\225\345\234\250Canvas\347\224\273\346\235\277\344\270\212\350\207\252\347\224\261\344\271\246\345\206\231.html" @@ -11,7 +11,7 @@ - + @@ -23,7 +23,7 @@ -
Skip to content

如何实现一个自由绘制的 Canvas 画板

前言

承接上文,当我们了解了如何去设置一个 Canvas 尺寸,并通过分辨率对 Canvas 进行矫正后,我们就可以开始实现一个自由绘制的 Canvas 画板了。

正文

实现思路

自由画笔的实现可以通过:

    1. 监听鼠标事件
    1. 将鼠标移动的点记录下来
    1. 将这些点连成线,就可以实现自由画笔了。

实现代码

html
<!DOCTYPE html>
+    
Skip to content

如何实现一个自由绘制的 Canvas 画板

前言

承接上文,当我们了解了如何去设置一个 Canvas 尺寸,并通过分辨率对 Canvas 进行矫正后,我们就可以开始实现一个自由绘制的 Canvas 画板了。

正文

实现思路

自由画笔的实现可以通过:

    1. 监听鼠标事件
    1. 将鼠标移动的点记录下来
    1. 将这些点连成线,就可以实现自由画笔了。

实现代码

html
<!DOCTYPE html>
 <html lang="en">
 
 <head>
@@ -357,8 +357,8 @@
       addPoint(e); // 将鼠标移动的点添加到points数组中
       render(ctx, points); // 绘制
       updatePointCounter(points.length);
-  }));

之前绘制一条直线需要近 40 个点 canvas

通过点稀释,我们发现画一条直线只需要 8 个点就可以了,这样就大大提高了性能。 canvas

虽然点稀释可以减少绘制的点数,提高性能,但在绘制曲线的时候,我们会发现曲线的圆滑度不够,这是因为我们的点数太少了,我们可以通过贝塞尔曲线来优化我们的 Canvas 书写。

canvas

参考

- + }));

之前绘制一条直线需要近 40 个点 canvas

通过点稀释,我们发现画一条直线只需要 8 个点就可以了,这样就大大提高了性能。 canvas

虽然点稀释可以减少绘制的点数,提高性能,但在绘制曲线的时候,我们会发现曲线的圆滑度不够,这是因为我们的点数太少了,我们可以通过贝塞尔曲线来优化我们的 Canvas 书写。

canvas

参考

+ \ No newline at end of file diff --git "a/guide/canvas/\351\200\232\350\277\207 OffscreenCanvas + Worker \346\217\220\351\253\230\344\271\246\345\206\231\346\200\247\350\203\275.html" "b/guide/canvas/\351\200\232\350\277\207 OffscreenCanvas + Worker \346\217\220\351\253\230\344\271\246\345\206\231\346\200\247\350\203\275.html" index 9a5934bb..6d861610 100644 --- "a/guide/canvas/\351\200\232\350\277\207 OffscreenCanvas + Worker \346\217\220\351\253\230\344\271\246\345\206\231\346\200\247\350\203\275.html" +++ "b/guide/canvas/\351\200\232\350\277\207 OffscreenCanvas + Worker \346\217\220\351\253\230\344\271\246\345\206\231\346\200\247\350\203\275.html" @@ -11,7 +11,7 @@ - + @@ -23,7 +23,7 @@ -
Skip to content

通过 OffscreenCanvas + Worker 提高书写性能

前言

上一节我们通过离屏渲染提高了 Canvas 的渲染性能,但是在绘制的过程中,我们会发现,当绘制的图形越来越多时,Canvas 的渲染性能会越来越差,这是因为我们在绘制图形会阻塞主线程,如果主线程中还有其他的任务也会表现出卡顿的效果,Canvas 的渲染性能越来越差。

这节我们将通过 OffscreenCanvas + Worker 将绘制图形的任务放到 Worker 中进行,避免阻塞主线程,从而提高 Canvas 的渲染性能。

实现思路

在 worker 线程中是无法操作 DOM 的,但 OffscreenCanvas 可以在 worker 线程中进行操作,因此我们可以通过 OffscreenCanvas 将绘制图形的任务放到 worker 线程中进行。这样可以减少主线程的任务,从而提高书写性能。

具体实现

创建 OffscreenCanvas

js
const canvas = document.getElementById('draw');
+    
Skip to content

通过 OffscreenCanvas + Worker 提高书写性能

前言

上一节我们通过离屏渲染提高了 Canvas 的渲染性能,但是在绘制的过程中,我们会发现,当绘制的图形越来越多时,Canvas 的渲染性能会越来越差,这是因为我们在绘制图形会阻塞主线程,如果主线程中还有其他的任务也会表现出卡顿的效果,Canvas 的渲染性能越来越差。

这节我们将通过 OffscreenCanvas + Worker 将绘制图形的任务放到 Worker 中进行,避免阻塞主线程,从而提高 Canvas 的渲染性能。

实现思路

在 worker 线程中是无法操作 DOM 的,但 OffscreenCanvas 可以在 worker 线程中进行操作,因此我们可以通过 OffscreenCanvas 将绘制图形的任务放到 worker 线程中进行。这样可以减少主线程的任务,从而提高书写性能。

具体实现

创建 OffscreenCanvas

js
const canvas = document.getElementById('draw');
 const offScreenCanvas = canvas.transferControlToOffscreen(); // 将 canvas 转换为 offScreenCanvas
const canvas = document.getElementById('draw');
 const offScreenCanvas = canvas.transferControlToOffscreen(); // 将 canvas 转换为 offScreenCanvas

将 offScreenCanvas 传递给 worker 线程

js
const worker = new Worker('./worker.js'); // 创建一个 webWorker
 const offScreenCanvas = canvas.transferControlToOffscreen(); // 将 canvas 转换为 offScreenCanvas
@@ -145,8 +145,8 @@
         x,
         y,
     });
-}

实现效果

初始状态图

具体代码

参考文章

- +}

实现效果

初始状态图

具体代码

参考文章

+ \ No newline at end of file diff --git "a/guide/canvas/\351\200\232\350\277\207\344\270\212\344\270\213\345\210\206\345\261\202\344\274\230\345\214\226Canvas\344\271\246\345\206\231\346\200\247\350\203\275.html" "b/guide/canvas/\351\200\232\350\277\207\344\270\212\344\270\213\345\210\206\345\261\202\344\274\230\345\214\226Canvas\344\271\246\345\206\231\346\200\247\350\203\275.html" index 722a558b..e86a9f73 100644 --- "a/guide/canvas/\351\200\232\350\277\207\344\270\212\344\270\213\345\210\206\345\261\202\344\274\230\345\214\226Canvas\344\271\246\345\206\231\346\200\247\350\203\275.html" +++ "b/guide/canvas/\351\200\232\350\277\207\344\270\212\344\270\213\345\210\206\345\261\202\344\274\230\345\214\226Canvas\344\271\246\345\206\231\346\200\247\350\203\275.html" @@ -11,7 +11,7 @@ - + @@ -23,7 +23,7 @@ -
Skip to content

通过上下分层优化 Canvas 书写性能

前言

上一节,我们通过点稀疏的方式,优化了 Canvas 的绘制性能。但在书写的过程中,因为点的数量减少导致书写的效果不够理想,因此通过贝塞尔曲线的方式,将点连接起来,形成平滑的曲线,从而达到书写的效果。 这节,我们将通过上下分层的方式,优化 Canvas 的书写性能。

基本思路

这里我将 Canvas 分为上下两层,上层称之为动态层,下层称之为静态层,动态层用于书写,静态层用于显示书写的效果。当书写的时候,将书写的点绘制到上层,当书写完成后,将上层的内容绘制到下层,然后清空上层的内容,这样就可以达到书写的效果。

因为 Canvas 每次渲染都会将整个 Canvas 清空,所以我们需要将静态层的内容保存下来,然后在每次书写的时候,只需要渲染当前动态层的内容即可。

实现

创建 2 个 Canvas

首先创建 2 个 Canvas, 上层 Canvas 用于书写, 书写完成后将上层 Canvas 的内容绘制到下层 Canvas 中, 然后清空上层 Canvas 的内容, 这样就可以达到书写的效果。

这样的好处在于, 每次书写的时候, 只需要渲染上层 Canvas 的书写内容即可, 不需要每次都渲染整个 Canvas, 从而达到优化性能的目的。

html
<style>
+    
Skip to content

通过上下分层优化 Canvas 书写性能

前言

上一节,我们通过点稀疏的方式,优化了 Canvas 的绘制性能。但在书写的过程中,因为点的数量减少导致书写的效果不够理想,因此通过贝塞尔曲线的方式,将点连接起来,形成平滑的曲线,从而达到书写的效果。 这节,我们将通过上下分层的方式,优化 Canvas 的书写性能。

基本思路

这里我将 Canvas 分为上下两层,上层称之为动态层,下层称之为静态层,动态层用于书写,静态层用于显示书写的效果。当书写的时候,将书写的点绘制到上层,当书写完成后,将上层的内容绘制到下层,然后清空上层的内容,这样就可以达到书写的效果。

因为 Canvas 每次渲染都会将整个 Canvas 清空,所以我们需要将静态层的内容保存下来,然后在每次书写的时候,只需要渲染当前动态层的内容即可。

实现

创建 2 个 Canvas

首先创建 2 个 Canvas, 上层 Canvas 用于书写, 书写完成后将上层 Canvas 的内容绘制到下层 Canvas 中, 然后清空上层 Canvas 的内容, 这样就可以达到书写的效果。

这样的好处在于, 每次书写的时候, 只需要渲染上层 Canvas 的书写内容即可, 不需要每次都渲染整个 Canvas, 从而达到优化性能的目的。

html
<style>
     #draw {
         border: 1px solid black;
         position: absolute;
@@ -109,8 +109,8 @@
         points = []; // 绘制完毕后,清空points数组
         renderLowerCanvas(ctx, ctxContent);
     });
-</script>

演示效果

这里我将动静 Canvas 分成了左右 2 个部分,左边是动态层 Canvas,右边是静态层 Canvas,可以看到,当书写的时候,只有左边的 Canvas 会有书写的效果,右边的 Canvas 不会有书写的效果,当书写完成后,左边的 Canvas 会将书写的内容绘制到右边的 Canvas 中,然后清空左边的 Canvas 的内容,这样就可以达到书写的效果。

canvas

当我们把 2 个 Canvas 整合在一起后,具体的效果如下

canvas

具体代码

https://github.com/enson0131/learn/blob/main/Canvas/白板相关/上下分层绘制.html

- +</script>

演示效果

这里我将动静 Canvas 分成了左右 2 个部分,左边是动态层 Canvas,右边是静态层 Canvas,可以看到,当书写的时候,只有左边的 Canvas 会有书写的效果,右边的 Canvas 不会有书写的效果,当书写完成后,左边的 Canvas 会将书写的内容绘制到右边的 Canvas 中,然后清空左边的 Canvas 的内容,这样就可以达到书写的效果。

canvas

当我们把 2 个 Canvas 整合在一起后,具体的效果如下

canvas

具体代码

https://github.com/enson0131/learn/blob/main/Canvas/白板相关/上下分层绘制.html

+ \ No newline at end of file diff --git "a/guide/canvas/\351\200\232\350\277\207\347\246\273\345\261\217\346\270\262\346\237\223\346\217\220\351\253\230Canvas\344\271\246\345\206\231\346\200\247\350\203\275.html" "b/guide/canvas/\351\200\232\350\277\207\347\246\273\345\261\217\346\270\262\346\237\223\346\217\220\351\253\230Canvas\344\271\246\345\206\231\346\200\247\350\203\275.html" index e7033d07..c8c3af0f 100644 --- "a/guide/canvas/\351\200\232\350\277\207\347\246\273\345\261\217\346\270\262\346\237\223\346\217\220\351\253\230Canvas\344\271\246\345\206\231\346\200\247\350\203\275.html" +++ "b/guide/canvas/\351\200\232\350\277\207\347\246\273\345\261\217\346\270\262\346\237\223\346\217\220\351\253\230Canvas\344\271\246\345\206\231\346\200\247\350\203\275.html" @@ -11,7 +11,7 @@ - + @@ -23,7 +23,7 @@ -
Skip to content

通过离屏渲染提高 Canvas 书写性能

前言

前面我们通过上下分层的方式,优化了 Canvas 的书写性能,接下来我们通过离屏渲染的方式,进一步优化 Canvas 的书写性能。

基本思路

在书写的过程中,每绘制一笔都需要不断地调用 Canvas 的 API,重新渲染整个 Canvas,这样就会导致性能的浪费。 而离屏渲染则是将 绘制内容存储到离屏的 Canvas 中,相当于一个缓冲区,然后将需要绘制的画面在离屏的 Canvas 缓冲好,最后将离屏的 Canvas 转化成图片,渲染到屏幕上,这样就可以达到优化性能的目的。

实现

创建离屏 Canvas

思路如下: 基于上一节的基础,我们改写 render 函数,如果是离屏渲染的话,将绘制的内容存储到离屏的 Canvas 中,然后将离屏的 Canvas 缓存起来,下次绘制的时候,如果命中缓存的话,就直接使用缓存的 Canvas,从而达到优化性能的目的。

操作如下:

  • 1 在执行 render 函数之前,先判断是否存在缓存的 Canvas,如果存在的话,就直接使用缓存的 Canvas
  • 2 如果命中缓存,使用离屏 Canvas 转化成图片进行绘制
  • 3 如果不存在缓存的 Canvas,就创建一个离屏的 Canvas,然后将绘制的内容存储到离屏的 Canvas 中,最后将离屏的 Canvas 缓存起来
html
<script>
+    
Skip to content

通过离屏渲染提高 Canvas 书写性能

前言

前面我们通过上下分层的方式,优化了 Canvas 的书写性能,接下来我们通过离屏渲染的方式,进一步优化 Canvas 的书写性能。

基本思路

在书写的过程中,每绘制一笔都需要不断地调用 Canvas 的 API,重新渲染整个 Canvas,这样就会导致性能的浪费。 而离屏渲染则是将 绘制内容存储到离屏的 Canvas 中,相当于一个缓冲区,然后将需要绘制的画面在离屏的 Canvas 缓冲好,最后将离屏的 Canvas 转化成图片,渲染到屏幕上,这样就可以达到优化性能的目的。

实现

创建离屏 Canvas

思路如下: 基于上一节的基础,我们改写 render 函数,如果是离屏渲染的话,将绘制的内容存储到离屏的 Canvas 中,然后将离屏的 Canvas 缓存起来,下次绘制的时候,如果命中缓存的话,就直接使用缓存的 Canvas,从而达到优化性能的目的。

操作如下:

  • 1 在执行 render 函数之前,先判断是否存在缓存的 Canvas,如果存在的话,就直接使用缓存的 Canvas
  • 2 如果命中缓存,使用离屏 Canvas 转化成图片进行绘制
  • 3 如果不存在缓存的 Canvas,就创建一个离屏的 Canvas,然后将绘制的内容存储到离屏的 Canvas 中,最后将离屏的 Canvas 缓存起来
html
<script>
         const elementWithCanvasCache = new WeakMap(); // 用于存储离屏 Canvas 的缓存
         const generateOffScreenCanvas = (points) => {
             const padding = 20; // 避免笔记被 Canvas 
@@ -317,8 +317,8 @@
               y: minY * dpr - padding
           });
       }
-</script>

实现的效果

canvas

具体代码

https://github.com/enson0131/learn/blob/main/Canvas/白板相关/性能优化之离屏渲染及缓存.html

- +</script>

实现的效果

canvas

具体代码

https://github.com/enson0131/learn/blob/main/Canvas/白板相关/性能优化之离屏渲染及缓存.html

+ \ No newline at end of file diff --git "a/guide/canvas/\351\200\232\350\277\207\350\264\235\345\241\236\345\260\224\346\233\262\347\272\277\344\274\230\345\214\226Canvas\344\271\246\345\206\231\346\200\247\350\203\275.html" "b/guide/canvas/\351\200\232\350\277\207\350\264\235\345\241\236\345\260\224\346\233\262\347\272\277\344\274\230\345\214\226Canvas\344\271\246\345\206\231\346\200\247\350\203\275.html" index d4e0f607..f426c7a3 100644 --- "a/guide/canvas/\351\200\232\350\277\207\350\264\235\345\241\236\345\260\224\346\233\262\347\272\277\344\274\230\345\214\226Canvas\344\271\246\345\206\231\346\200\247\350\203\275.html" +++ "b/guide/canvas/\351\200\232\350\277\207\350\264\235\345\241\236\345\260\224\346\233\262\347\272\277\344\274\230\345\214\226Canvas\344\271\246\345\206\231\346\200\247\350\203\275.html" @@ -11,7 +11,7 @@ - + @@ -23,7 +23,7 @@ -
Skip to content

通过贝塞尔曲线解决 Canvas 书写的圆滑问题

前言

书接上回,当我们实现了一个自由书写的 Canvas 画板后,我们发现采集的点越少,画出来的圈圈越不圆润,这时候我们可以使用贝塞尔曲线来优化书写。

canvas

正文

贝塞尔曲线

贝塞尔曲线是一种数学曲线,常见的有: 线性贝塞尔曲线、二次·贝塞尔曲线、三次贝塞尔曲线等, 它可以用来实现平滑曲线,我们可以通过贝塞尔曲线以相对圆滑的方式来优化我们的 Canvas 书写。

优化思路

我们可以通过贝塞尔曲线来优化我们的 Canvas 书写性能,将笔直的线变的更加圆滑弯曲。

在 Canvas2D API 中有一个方法叫做 quadraticCurveTo 用于创建二次贝塞尔曲线。它需要两个点:一个控制点和一个终点。曲线从当前的绘图位置开始绘制,并以控制点为参考,向终点绘制曲线。

这个方法的语法是:context.quadraticCurveTo(cp1x, cp1y, x, y);

其中:

cp1x 和 cp1y 是控制点坐标。
+    
Skip to content

通过贝塞尔曲线解决 Canvas 书写的圆滑问题

前言

书接上回,当我们实现了一个自由书写的 Canvas 画板后,我们发现采集的点越少,画出来的圈圈越不圆润,这时候我们可以使用贝塞尔曲线来优化书写。

canvas

正文

贝塞尔曲线

贝塞尔曲线是一种数学曲线,常见的有: 线性贝塞尔曲线、二次·贝塞尔曲线、三次贝塞尔曲线等, 它可以用来实现平滑曲线,我们可以通过贝塞尔曲线以相对圆滑的方式来优化我们的 Canvas 书写。

优化思路

我们可以通过贝塞尔曲线来优化我们的 Canvas 书写性能,将笔直的线变的更加圆滑弯曲。

在 Canvas2D API 中有一个方法叫做 quadraticCurveTo 用于创建二次贝塞尔曲线。它需要两个点:一个控制点和一个终点。曲线从当前的绘图位置开始绘制,并以控制点为参考,向终点绘制曲线。

这个方法的语法是:context.quadraticCurveTo(cp1x, cp1y, x, y);

其中:

cp1x 和 cp1y 是控制点坐标。
 x 和 y 是终点坐标。
 

这个方法不会直接绘制曲线,而是将曲线添加到当前的路径中。要在画布上实际绘制曲线,你需要使用 stroke 或 fill 方法

优化实现

1 采集到所有的点集 2 前一个点作为控制点,当前点作为终点,绘制二次贝塞尔曲线

html
<!DOCTYPE html>
 <html lang="en">
@@ -367,8 +367,8 @@
         }
     </script>
 </body>
-</html>

将两个点的中点作为控制点的选择通常用于创建平滑的曲线,该方法可以确保曲线通过两个点并且在两个点之间有一个平滑的拐角。 方法的依据是曲线的切线在控制点处与曲线的切线在两个点的中点处平行,从而使曲线过渡更加平滑。

canvas

参考文章

- +</html>

将两个点的中点作为控制点的选择通常用于创建平滑的曲线,该方法可以确保曲线通过两个点并且在两个点之间有一个平滑的拐角。 方法的依据是曲线的切线在控制点处与曲线的切线在两个点的中点处平行,从而使曲线过渡更加平滑。

canvas

参考文章

+ \ No newline at end of file diff --git "a/guide/css\347\233\270\345\205\263/BFC.html" "b/guide/css\347\233\270\345\205\263/BFC.html" index 53d4169e..c8e48c73 100644 --- "a/guide/css\347\233\270\345\205\263/BFC.html" +++ "b/guide/css\347\233\270\345\205\263/BFC.html" @@ -11,7 +11,7 @@ - + @@ -23,8 +23,8 @@ -
Skip to content

BFC

块级格式化上下文

条件

  1. 根元素 (html)
  2. 浮动元素
  3. position 为绝对定位元素 (absolute/fixed)
  4. display: inline-block、inline-flex等
  5. overflow: auto/scroll/hidden (overflow 值不为 visible 或 clip 的块级元素)

特点

  1. BFC 内部元素不影响外部元素
  2. 计算高度需要计算浮动元素
  3. BFC 区域不会与浮动容器发生重叠
  4. 在 BFC 中上下相邻的俩个容器的 margin 会重叠
  5. 每个元素的左 margin 值和容器的左 border 相接触

作用

  1. 清除浮动带来的高度塌陷问题
  2. 解决俩个元素的 margin 重叠问题
  3. 创建自适应的俩栏布局
- +
Skip to content

BFC

块级格式化上下文

条件

  1. 根元素 (html)
  2. 浮动元素
  3. position 为绝对定位元素 (absolute/fixed)
  4. display: inline-block、inline-flex等
  5. overflow: auto/scroll/hidden (overflow 值不为 visible 或 clip 的块级元素)

特点

  1. BFC 内部元素不影响外部元素
  2. 计算高度需要计算浮动元素
  3. BFC 区域不会与浮动容器发生重叠
  4. 在 BFC 中上下相邻的俩个容器的 margin 会重叠
  5. 每个元素的左 margin 值和容器的左 border 相接触

作用

  1. 清除浮动带来的高度塌陷问题
  2. 解决俩个元素的 margin 重叠问题
  3. 创建自适应的俩栏布局
+ \ No newline at end of file diff --git "a/guide/css\347\233\270\345\205\263/display.html" "b/guide/css\347\233\270\345\205\263/display.html" index 7ff61473..7de1acac 100644 --- "a/guide/css\347\233\270\345\205\263/display.html" +++ "b/guide/css\347\233\270\345\205\263/display.html" @@ -11,7 +11,7 @@ - + @@ -23,7 +23,7 @@ -
Skip to content

display

none

不显示元素,脱离文档流

inline 行内元素

不能设置宽高、不换行

水平 padding、margin 有效

垂直方向 padding、margin 无效

line-block

可以设置宽高、不换行

block

块级元素,可以设置宽高,独占一行

flex

弹性布局

table

元素作为块级表格元素使用

inherit

继承父元素 display 值

常见的问题

line-block、inline 都会有空格问题

因为浏览器会将换行符当空格字符处理

解决方案:

  1. 使用 font-size 时,可通过设置 font-size: 0、letter-spacing、word-spacing 解决
  2. 使用弹性布局
  3. 使用 margin 负值

浏览器对于空格的默认表现

  1. 元素的头尾的空白符会直接忽略
  2. 内容中间有多个空格,会被合并成一个空格
js
<!DOCTYPE html>
+    
Skip to content

display

none

不显示元素,脱离文档流

inline 行内元素

不能设置宽高、不换行

水平 padding、margin 有效

垂直方向 padding、margin 无效

line-block

可以设置宽高、不换行

block

块级元素,可以设置宽高,独占一行

flex

弹性布局

table

元素作为块级表格元素使用

inherit

继承父元素 display 值

常见的问题

line-block、inline 都会有空格问题

因为浏览器会将换行符当空格字符处理

解决方案:

  1. 使用 font-size 时,可通过设置 font-size: 0、letter-spacing、word-spacing 解决
  2. 使用弹性布局
  3. 使用 margin 负值

浏览器对于空格的默认表现

  1. 元素的头尾的空白符会直接忽略
  2. 内容中间有多个空格,会被合并成一个空格
js
<!DOCTYPE html>
 <html lang="en">
 
 <head>
@@ -115,8 +115,8 @@
     <li>元素的头尾的空白符会直接忽略</li>
     <li>内容中间有多个空格,会被合并成一个空格</li>
   </ul>
-</body>
- +</body>
+ \ No newline at end of file diff --git "a/guide/css\347\233\270\345\205\263/display\343\200\201float\343\200\201position\347\232\204\345\205\263\347\263\273.html" "b/guide/css\347\233\270\345\205\263/display\343\200\201float\343\200\201position\347\232\204\345\205\263\347\263\273.html" index b6326eba..3ebfed05 100644 --- "a/guide/css\347\233\270\345\205\263/display\343\200\201float\343\200\201position\347\232\204\345\205\263\347\263\273.html" +++ "b/guide/css\347\233\270\345\205\263/display\343\200\201float\343\200\201position\347\232\204\345\205\263\347\263\273.html" @@ -11,7 +11,7 @@ - + @@ -23,7 +23,7 @@ -
Skip to content

display、float、position的关系

  • 如果元素的 display 为 none 直接隐藏
  • 如果元素的 position 为 absolute 或者 fixed 时,float 失效,display 会提升块级元素
  • 如果元素的 position 为 relative, 会在浮动后的元素进行定位,display 会被提升成块级元素
  • 如果是根元素,display 会被提升为块级元素
  • 浮动元素会将 display 提升为块级元素
html
<!DOCTYPE html>
+    
Skip to content

display、float、position的关系

  • 如果元素的 display 为 none 直接隐藏
  • 如果元素的 position 为 absolute 或者 fixed 时,float 失效,display 会提升块级元素
  • 如果元素的 position 为 relative, 会在浮动后的元素进行定位,display 会被提升成块级元素
  • 如果是根元素,display 会被提升为块级元素
  • 浮动元素会将 display 提升为块级元素
html
<!DOCTYPE html>
 <html lang="en">
 
 <head>
@@ -87,8 +87,8 @@
     </div>
 </body>
 
-</html>
- +</html>
+ \ No newline at end of file diff --git "a/guide/css\347\233\270\345\205\263/display\343\200\201visibility\343\200\201opacity\345\214\272\345\210\253.html" "b/guide/css\347\233\270\345\205\263/display\343\200\201visibility\343\200\201opacity\345\214\272\345\210\253.html" index 077e7b73..61b4a1c4 100644 --- "a/guide/css\347\233\270\345\205\263/display\343\200\201visibility\343\200\201opacity\345\214\272\345\210\253.html" +++ "b/guide/css\347\233\270\345\205\263/display\343\200\201visibility\343\200\201opacity\345\214\272\345\210\253.html" @@ -11,7 +11,7 @@ - + @@ -23,8 +23,8 @@ -
Skip to content

display、visibility、opacity区别

  • 占据空间

    • opacity、visibility 占据空间,不会引起回流,但是会重绘
    • display 不占据空间,但会引起页面的回流和重绘
  • 绑定事件

    • display、visibility 不会触发绑定事件
    • opacity 会触发绑定事件

display: none 和 visibility: hidden 的区别

  • 从渲染树上看
    • display: none 不存在渲染树中
    • visibility: hidden 的元素存在渲染树中,还会占据空间
  • 从继承上看
    • display 不会被继承
    • visibility 会被继承
  • 从渲染上看
    • display 会影响回流重绘
    • visibility 只会引起重绘
- +
Skip to content

display、visibility、opacity区别

  • 占据空间

    • opacity、visibility 占据空间,不会引起回流,但是会重绘
    • display 不占据空间,但会引起页面的回流和重绘
  • 绑定事件

    • display、visibility 不会触发绑定事件
    • opacity 会触发绑定事件

display: none 和 visibility: hidden 的区别

  • 从渲染树上看
    • display: none 不存在渲染树中
    • visibility: hidden 的元素存在渲染树中,还会占据空间
  • 从继承上看
    • display 不会被继承
    • visibility 会被继承
  • 从渲染上看
    • display 会影响回流重绘
    • visibility 只会引起重绘
+ \ No newline at end of file diff --git "a/guide/css\347\233\270\345\205\263/position.html" "b/guide/css\347\233\270\345\205\263/position.html" index 3ff65be0..df9b1887 100644 --- "a/guide/css\347\233\270\345\205\263/position.html" +++ "b/guide/css\347\233\270\345\205\263/position.html" @@ -11,7 +11,7 @@ - + @@ -23,7 +23,7 @@ -
Skip to content

Position

static [ˈstætɪk]

默认值,没有定位,元素出现在正常的文档流中,会忽略 top,bottom,left,right 或者 z-index 声明

relative

生成相对定位元素,相对于其原来位置进行定位,元素的位置通过 left、top、right、bottom 属性规定

relative

元素定位永远相对于元素自身位置,和其他元素没有关系,也不会影响其他元素。

absolute

生成绝对定位的元素,相对于 static 定位以外的一个父元素进行定位

元素位置通过 left、top、right、bottom 属性规定

relative

浏览器会递归查找该元素的所有父元素,如果找到一个设置了非 static 的定位元素,就以该元素为基准定位,如果没有找到,就以浏览器边界定位

但是它具有破坏性,会导致其他元素位置的变化

fixed

生成绝对定位的元素,指定元素相对于屏幕视口的位置来制定元素位置。

relative

但是它具有破坏性,会导致其他元素位置的变化

sticky [ˈstɪki]

相对它的最近滚动祖先(nearest scrolling ancestor)和 containing block (最近块级祖先 nearest block-level ancestor),包括table-related元素,基于top, right, bottom, 和 left的值进行偏移。偏移值不会影响任何其他元素的位置。

inherit

规定从父元素继承 position 属性的值

js
<!DOCTYPE html>
+    
Skip to content

Position

static [ˈstætɪk]

默认值,没有定位,元素出现在正常的文档流中,会忽略 top,bottom,left,right 或者 z-index 声明

relative

生成相对定位元素,相对于其原来位置进行定位,元素的位置通过 left、top、right、bottom 属性规定

relative

元素定位永远相对于元素自身位置,和其他元素没有关系,也不会影响其他元素。

absolute

生成绝对定位的元素,相对于 static 定位以外的一个父元素进行定位

元素位置通过 left、top、right、bottom 属性规定

relative

浏览器会递归查找该元素的所有父元素,如果找到一个设置了非 static 的定位元素,就以该元素为基准定位,如果没有找到,就以浏览器边界定位

但是它具有破坏性,会导致其他元素位置的变化

fixed

生成绝对定位的元素,指定元素相对于屏幕视口的位置来制定元素位置。

relative

但是它具有破坏性,会导致其他元素位置的变化

sticky [ˈstɪki]

相对它的最近滚动祖先(nearest scrolling ancestor)和 containing block (最近块级祖先 nearest block-level ancestor),包括table-related元素,基于top, right, bottom, 和 left的值进行偏移。偏移值不会影响任何其他元素的位置。

inherit

规定从父元素继承 position 属性的值

js
<!DOCTYPE html>
 <html lang="en">
 
 <head>
@@ -135,8 +135,8 @@
     <div class="subbottom"></div>
   </div>
 </body>
-</html>
- +</html>
+ \ No newline at end of file diff --git "a/guide/css\347\233\270\345\205\263/\345\257\271 line-height \347\232\204\347\220\206\350\247\243\345\217\212\345\205\266\350\265\213\345\200\274\346\226\271\345\274\217.html" "b/guide/css\347\233\270\345\205\263/\345\257\271 line-height \347\232\204\347\220\206\350\247\243\345\217\212\345\205\266\350\265\213\345\200\274\346\226\271\345\274\217.html" index a11eed55..372a30f0 100644 --- "a/guide/css\347\233\270\345\205\263/\345\257\271 line-height \347\232\204\347\220\206\350\247\243\345\217\212\345\205\266\350\265\213\345\200\274\346\226\271\345\274\217.html" +++ "b/guide/css\347\233\270\345\205\263/\345\257\271 line-height \347\232\204\347\220\206\350\247\243\345\217\212\345\205\266\350\265\213\345\200\274\346\226\271\345\274\217.html" @@ -11,7 +11,7 @@ - + @@ -23,8 +23,8 @@ -
Skip to content

对 line-height 的理解及其赋值方式

概念

line-height 指一行文本的高度,包含了字间距,实际上是下一行基线到上一行基线的距离

line-height 和 height 都能撑开元素高度 (如果 line-height 和 height 一致时可以实现单行文字的垂直居中)

计算方式

带单位的px

line-height 为 固定值

纯数字

直接 line-height 会把比例传递给后代

例如,父级行高为 1.5,子元素字体为 18px,则子元素行高为 1.5 * 18 = 27px

百分比

父元素将计算后的值传递给后代

例如,父元素行高为 200%,父元素字体为 18px,那么子元素行高为 18 * 200% = 36px

- +
Skip to content

对 line-height 的理解及其赋值方式

概念

line-height 指一行文本的高度,包含了字间距,实际上是下一行基线到上一行基线的距离

line-height 和 height 都能撑开元素高度 (如果 line-height 和 height 一致时可以实现单行文字的垂直居中)

计算方式

带单位的px

line-height 为 固定值

纯数字

直接 line-height 会把比例传递给后代

例如,父级行高为 1.5,子元素字体为 18px,则子元素行高为 1.5 * 18 = 27px

百分比

父元素将计算后的值传递给后代

例如,父元素行高为 200%,父元素字体为 18px,那么子元素行高为 18 * 200% = 36px

+ \ No newline at end of file diff --git "a/guide/css\347\233\270\345\205\263/\346\246\202\350\246\201.html" "b/guide/css\347\233\270\345\205\263/\346\246\202\350\246\201.html" index 60887251..a8c0da9a 100644 --- "a/guide/css\347\233\270\345\205\263/\346\246\202\350\246\201.html" +++ "b/guide/css\347\233\270\345\205\263/\346\246\202\350\246\201.html" @@ -12,7 +12,7 @@ - + @@ -24,8 +24,8 @@ -
Skip to content
- +
Skip to content
+ \ No newline at end of file diff --git "a/guide/css\347\233\270\345\205\263/\351\232\220\350\227\217\345\205\203\347\264\240\347\232\204\346\226\271\346\263\225.html" "b/guide/css\347\233\270\345\205\263/\351\232\220\350\227\217\345\205\203\347\264\240\347\232\204\346\226\271\346\263\225.html" index 76d32d37..1f59b41e 100644 --- "a/guide/css\347\233\270\345\205\263/\351\232\220\350\227\217\345\205\203\347\264\240\347\232\204\346\226\271\346\263\225.html" +++ "b/guide/css\347\233\270\345\205\263/\351\232\220\350\227\217\345\205\203\347\264\240\347\232\204\346\226\271\346\263\225.html" @@ -11,7 +11,7 @@ - + @@ -23,8 +23,8 @@ -
Skip to content

隐藏元素的方法

    1. display: none - 不会显示在渲染树上,不占据空间,无法监听事件
    1. visibility: hidden - 占据空间,无法监听事件
    1. opacity: 0 - 占据空间,可以监听事件
    1. transform: scale(0, 0)
    1. 绝对定位
    1. z-index 为负数
- +
Skip to content

隐藏元素的方法

    1. display: none - 不会显示在渲染树上,不占据空间,无法监听事件
    1. visibility: hidden - 占据空间,无法监听事件
    1. opacity: 0 - 占据空间,可以监听事件
    1. transform: scale(0, 0)
    1. 绝对定位
    1. z-index 为负数
+ \ No newline at end of file diff --git "a/guide/javaScript\347\233\270\345\205\263/DOM\347\233\270\345\205\263.html" "b/guide/javaScript\347\233\270\345\205\263/DOM\347\233\270\345\205\263.html" index fe3ecb7f..f4c05a89 100644 --- "a/guide/javaScript\347\233\270\345\205\263/DOM\347\233\270\345\205\263.html" +++ "b/guide/javaScript\347\233\270\345\205\263/DOM\347\233\270\345\205\263.html" @@ -11,7 +11,7 @@ - + @@ -23,7 +23,7 @@ -
Skip to content

DOM 相关

如何阻止事件的冒泡和默认事件

js
event.stopPropagation(); // 阻止事件冒泡
+    
Skip to content

DOM 相关

如何阻止事件的冒泡和默认事件

js
event.stopPropagation(); // 阻止事件冒泡
 event.preventDefalut(); // 阻止默认事件
 event.stopImmediatePropagation(); // 阻止监听同一事件的其他事件监听器被调用
event.stopPropagation(); // 阻止事件冒泡
 event.preventDefalut(); // 阻止默认事件
@@ -39,8 +39,8 @@
 
 var imoocList = document.getElementByClassName('imooc'); // 查询类名 imooc 类名集合
 
-var imoocList = docuemnt.querySelectorAll('.imooc'); // 查询类名 imooc 的集合

高度相关

  • offsetHeight: 包含 padding、content、border 和 滚动条
  • clientHeight: 包含 padding 和 content
  • scrollHeight: 包含 padding 和 内容高度

判断是否有滚动条 scrollHeight >= clientHeight

顶部高度

  • offsetTop: 元素顶部到最近父元素顶部的距离,和有木有滚动条没有关系
  • scrollTop: 滚动条滚动的距离

鼠标事件

按下

  • click: 点击鼠标左键或按下回车键调用
  • dblclick: 双击鼠标左键调用
  • mousedown: 鼠标被按下(左键/右键)时触发,不能通过键盘触发。
  • mouseup: 鼠标按键被松开时触发,不能通过键盘触发。

移动

  • mouseover: 鼠标移入目标元素。鼠标移入子元素也会触发
  • mouseout: 鼠标移出目标元素。鼠标移出子元素也会触发
  • mouseenter: 鼠标移入目标元素。鼠标移入子元素不会触发
  • mouseleave: 鼠标移出目标元素。鼠标移出子元素不会触发
  • mousemove: 鼠标在目标元素内移动时触发,不能通过键盘触发。
- +var imoocList = docuemnt.querySelectorAll('.imooc'); // 查询类名 imooc 的集合

高度相关

  • offsetHeight: 包含 padding、content、border 和 滚动条
  • clientHeight: 包含 padding 和 content
  • scrollHeight: 包含 padding 和 内容高度

判断是否有滚动条 scrollHeight >= clientHeight

顶部高度

  • offsetTop: 元素顶部到最近父元素顶部的距离,和有木有滚动条没有关系
  • scrollTop: 滚动条滚动的距离

鼠标事件

按下

  • click: 点击鼠标左键或按下回车键调用
  • dblclick: 双击鼠标左键调用
  • mousedown: 鼠标被按下(左键/右键)时触发,不能通过键盘触发。
  • mouseup: 鼠标按键被松开时触发,不能通过键盘触发。

移动

  • mouseover: 鼠标移入目标元素。鼠标移入子元素也会触发
  • mouseout: 鼠标移出目标元素。鼠标移出子元素也会触发
  • mouseenter: 鼠标移入目标元素。鼠标移入子元素不会触发
  • mouseleave: 鼠标移出目标元素。鼠标移出子元素不会触发
  • mousemove: 鼠标在目标元素内移动时触发,不能通过键盘触发。
+ \ No newline at end of file diff --git "a/guide/javaScript\347\233\270\345\205\263/ES6\347\233\270\345\205\263.html" "b/guide/javaScript\347\233\270\345\205\263/ES6\347\233\270\345\205\263.html" index 537a4e2f..d3b81128 100644 --- "a/guide/javaScript\347\233\270\345\205\263/ES6\347\233\270\345\205\263.html" +++ "b/guide/javaScript\347\233\270\345\205\263/ES6\347\233\270\345\205\263.html" @@ -11,7 +11,7 @@ - + @@ -23,7 +23,7 @@ -
Skip to content

ES6相关

var、let、const 的区别

1 作用域 let、const 存在块级作用域 var 不存在块级作用域

2 const 常量 定义时赋值

3 变量提升 let/const 声明的变量需要声明后使用 var 声明的变量可以声明前使用

4 重复声明 let/const 不能重复声明 var 可以重复声明

5 暂时性死区 let/const 声明的变量不能在声明前使用

暂时性死区

箭头函数和普通函数的区别

1 箭头函数没有 arguments

2 箭头函数没有自己的 this this 由定义的所在父级上下文决定

3 箭头函数继承来的 this 不会改变 call、apply、bind 方法不能改变箭头函数的 this 指向

js
var id = 'global';
+    
Skip to content

ES6相关

var、let、const 的区别

1 作用域 let、const 存在块级作用域 var 不存在块级作用域

2 const 常量 定义时赋值

3 变量提升 let/const 声明的变量需要声明后使用 var 声明的变量可以声明前使用

4 重复声明 let/const 不能重复声明 var 可以重复声明

5 暂时性死区 let/const 声明的变量不能在声明前使用

暂时性死区

箭头函数和普通函数的区别

1 箭头函数没有 arguments

2 箭头函数没有自己的 this this 由定义的所在父级上下文决定

3 箭头函数继承来的 this 不会改变 call、apply、bind 方法不能改变箭头函数的 this 指向

js
var id = 'global';
 var obj = {
     id: 'obj',
     a: function () {
@@ -123,8 +123,8 @@
 let test = onWatch(obj);
 
 test.a // getting a!
-test.a = 2 // setting a!
- +test.a = 2 // setting a!
+ \ No newline at end of file diff --git "a/guide/javaScript\347\233\270\345\205\263/JS\345\274\202\345\270\270\346\215\225\350\216\267\346\234\272\345\210\266.html" "b/guide/javaScript\347\233\270\345\205\263/JS\345\274\202\345\270\270\346\215\225\350\216\267\346\234\272\345\210\266.html" index 915e9fdc..c41f10c3 100644 --- "a/guide/javaScript\347\233\270\345\205\263/JS\345\274\202\345\270\270\346\215\225\350\216\267\346\234\272\345\210\266.html" +++ "b/guide/javaScript\347\233\270\345\205\263/JS\345\274\202\345\270\270\346\215\225\350\216\267\346\234\272\345\210\266.html" @@ -11,7 +11,7 @@ - + @@ -23,8 +23,8 @@ -
Skip to content
- +
Skip to content
+ \ No newline at end of file diff --git "a/guide/javaScript\347\233\270\345\205\263/JavaScript\346\211\247\350\241\214\346\234\272\345\210\266.html" "b/guide/javaScript\347\233\270\345\205\263/JavaScript\346\211\247\350\241\214\346\234\272\345\210\266.html" index b39bf4eb..3d570de2 100644 --- "a/guide/javaScript\347\233\270\345\205\263/JavaScript\346\211\247\350\241\214\346\234\272\345\210\266.html" +++ "b/guide/javaScript\347\233\270\345\205\263/JavaScript\346\211\247\350\241\214\346\234\272\345\210\266.html" @@ -11,7 +11,7 @@ - + @@ -23,8 +23,8 @@ -
Skip to content

JavaScript 执行机制

先编译后执行

编译 -> 创建上下文、创建变量环境、创建词法环境 -> 将上下文压入执行调用栈执行代码

- +
Skip to content

JavaScript 执行机制

先编译后执行

编译 -> 创建上下文、创建变量环境、创建词法环境 -> 将上下文压入执行调用栈执行代码

+ \ No newline at end of file diff --git "a/guide/javaScript\347\233\270\345\205\263/JavaScript\347\274\226\350\257\221\346\234\272\345\210\266.html" "b/guide/javaScript\347\233\270\345\205\263/JavaScript\347\274\226\350\257\221\346\234\272\345\210\266.html" index f33ec6db..315d8a8a 100644 --- "a/guide/javaScript\347\233\270\345\205\263/JavaScript\347\274\226\350\257\221\346\234\272\345\210\266.html" +++ "b/guide/javaScript\347\233\270\345\205\263/JavaScript\347\274\226\350\257\221\346\234\272\345\210\266.html" @@ -11,7 +11,7 @@ - + @@ -23,8 +23,8 @@ -
Skip to content

JavaScript 编译机制

code -> 词法分析、语法分析 -> AST -> 生成字节码 -> 解释执行

- +
Skip to content

JavaScript 编译机制

code -> 词法分析、语法分析 -> AST -> 生成字节码 -> 解释执行

+ \ No newline at end of file diff --git "a/guide/javaScript\347\233\270\345\205\263/Promise.html" "b/guide/javaScript\347\233\270\345\205\263/Promise.html" index 2bdf616b..7d436094 100644 --- "a/guide/javaScript\347\233\270\345\205\263/Promise.html" +++ "b/guide/javaScript\347\233\270\345\205\263/Promise.html" @@ -11,7 +11,7 @@ - + @@ -23,7 +23,7 @@ -
Skip to content

Promise 相关

定义

Promise 有 3 种状态:

  • 等待状态 pending
  • 成功状态 resolved
  • 失败状态 rejected

当 Promise 状态是 Pending 时,可以转换为 Resolved 或者 Rejected 状态,一旦状态转换,就不会再改变。

resolved、rejected 是异步函数

then 默认返回一个 Promise 对象,第一个参数是 resolved 的回调函数,第二个参数是 rejected 的回调函数 catch 会返回一个 Promise 对象,catch 正常返回 resolved 状态,里面报错返回 rejected 状态

Promise.resolve

Promise.resolve(value) 返回一个成功状态的 promise 对象

js
/*
+    
Skip to content

Promise 相关

定义

Promise 有 3 种状态:

  • 等待状态 pending
  • 成功状态 resolved
  • 失败状态 rejected

当 Promise 状态是 Pending 时,可以转换为 Resolved 或者 Rejected 状态,一旦状态转换,就不会再改变。

resolved、rejected 是异步函数

then 默认返回一个 Promise 对象,第一个参数是 resolved 的回调函数,第二个参数是 rejected 的回调函数 catch 会返回一个 Promise 对象,catch 正常返回 resolved 状态,里面报错返回 rejected 状态

Promise.resolve

Promise.resolve(value) 返回一个成功状态的 promise 对象

js
/*
   如果 .then 函数参数不是一个函数,那么会将其封装成 v => v 函数, 这里的 v 是上一个 resolve 的返回值
 */
 
@@ -81,8 +81,8 @@
             })
         }
     })
-}

Promise.any

参数是一个数组,返回第一个成功的值

Promise.finally

不管 Promise 返回什么状态都会执行

常见的问题

Promise 解决了什么问题

  • 解决了回调地狱的问题
- +}

Promise.any

参数是一个数组,返回第一个成功的值

Promise.finally

不管 Promise 返回什么状态都会执行

常见的问题

Promise 解决了什么问题

  • 解决了回调地狱的问题
+ \ No newline at end of file diff --git "a/guide/javaScript\347\233\270\345\205\263/index.html" "b/guide/javaScript\347\233\270\345\205\263/index.html" index a2d2f645..59574dca 100644 --- "a/guide/javaScript\347\233\270\345\205\263/index.html" +++ "b/guide/javaScript\347\233\270\345\205\263/index.html" @@ -12,7 +12,7 @@ - + @@ -24,8 +24,8 @@ -
Skip to content
- +
Skip to content
+ \ No newline at end of file diff --git "a/guide/javaScript\347\233\270\345\205\263/\344\272\213\344\273\266\345\276\252\347\216\257\346\234\272\345\210\266.html" "b/guide/javaScript\347\233\270\345\205\263/\344\272\213\344\273\266\345\276\252\347\216\257\346\234\272\345\210\266.html" index 9f55f6f5..1c86672d 100644 --- "a/guide/javaScript\347\233\270\345\205\263/\344\272\213\344\273\266\345\276\252\347\216\257\346\234\272\345\210\266.html" +++ "b/guide/javaScript\347\233\270\345\205\263/\344\272\213\344\273\266\345\276\252\347\216\257\346\234\272\345\210\266.html" @@ -11,7 +11,7 @@ - + @@ -23,8 +23,8 @@ -
Skip to content

事件循环机制

执行 js 代码时,会将代码分成同步代码和异步代码, 同步任务会进入主线程执行,异步任务又分成宏任务和微任务 宏任务会进入宏任务队列,微任务会进入微任务队列 当主线程的代码执行完后,会查看是否有微任务队列,有则执行,无则进入下一个宏任务

- +
Skip to content

事件循环机制

执行 js 代码时,会将代码分成同步代码和异步代码, 同步任务会进入主线程执行,异步任务又分成宏任务和微任务 宏任务会进入宏任务队列,微任务会进入微任务队列 当主线程的代码执行完后,会查看是否有微任务队列,有则执行,无则进入下一个宏任务

+ \ No newline at end of file diff --git "a/guide/javaScript\347\233\270\345\205\263/\345\236\203\345\234\276\345\233\236\346\224\266\346\234\272\345\210\266.html" "b/guide/javaScript\347\233\270\345\205\263/\345\236\203\345\234\276\345\233\236\346\224\266\346\234\272\345\210\266.html" index 1b2d643f..951e5274 100644 --- "a/guide/javaScript\347\233\270\345\205\263/\345\236\203\345\234\276\345\233\236\346\224\266\346\234\272\345\210\266.html" +++ "b/guide/javaScript\347\233\270\345\205\263/\345\236\203\345\234\276\345\233\236\346\224\266\346\234\272\345\210\266.html" @@ -11,7 +11,7 @@ - + @@ -23,8 +23,8 @@ -
Skip to content

垃圾回收机制

在 JS 的垃圾回收机制中,分成新生代和老生代 新生代采用的是 GC 算法,将新生代划分成活动对象区域和空闲区域,例如声明的对象会被放入活动对象区域,当活动对象区域填满时, 会进行一次垃圾回收,将存活的对象移入空闲区域并进行碎片空间整理,完成后再将空闲区域和活动对象区域进行翻转,依次循环回收。

当进行 2次 垃圾回收后,存活的对象会被放入老生代中,

老生代采用的是标记清除和标记整理算法,递归遍历堆内存的变量,将不需要使用的变量标记为垃圾数据,将需要使用的变量标记成活动变量,清除掉垃圾,然后进行标记整理碎片空间。

- +
Skip to content

垃圾回收机制

在 JS 的垃圾回收机制中,分成新生代和老生代 新生代采用的是 GC 算法,将新生代划分成活动对象区域和空闲区域,例如声明的对象会被放入活动对象区域,当活动对象区域填满时, 会进行一次垃圾回收,将存活的对象移入空闲区域并进行碎片空间整理,完成后再将空闲区域和活动对象区域进行翻转,依次循环回收。

当进行 2次 垃圾回收后,存活的对象会被放入老生代中,

老生代采用的是标记清除和标记整理算法,递归遍历堆内存的变量,将不需要使用的变量标记为垃圾数据,将需要使用的变量标记成活动变量,清除掉垃圾,然后进行标记整理碎片空间。

+ \ No newline at end of file diff --git "a/guide/javaScript\347\233\270\345\205\263/\345\237\272\347\241\200\346\246\202\345\277\265.html" "b/guide/javaScript\347\233\270\345\205\263/\345\237\272\347\241\200\346\246\202\345\277\265.html" index 9679e916..25628b15 100644 --- "a/guide/javaScript\347\233\270\345\205\263/\345\237\272\347\241\200\346\246\202\345\277\265.html" +++ "b/guide/javaScript\347\233\270\345\205\263/\345\237\272\347\241\200\346\246\202\345\277\265.html" @@ -11,7 +11,7 @@ - + @@ -23,7 +23,7 @@ -
Skip to content

3 基础概念

3.1 闭包

执行外部函数返回内部函数后,虽然外部函数已经弹出调用栈了,但是内部函数对外部函数变量的引用依然保存在内存中,那么内部函数和这些变量的集合就叫做闭包。

闭包的好处: 1. 私有变量在内存中持久化

闭包的坏处: 1. 使用不当会造成内存泄漏

3.2 原型

在 js 中对象是由构造函数创建的,构造函数中会有一个 prototype 属性,指向一个对象,这个对象包含了由该构造函数创建的实例所共享的属性和方法, 由该构造函数创建的实例可以通过 proto 属性指向这个对象,这个对象就是我们所说的原型。

当想要访问对象的某个属性时,如果在当前对象查找不到,就会往该对象的原型查找,对象的原型也会有属于他的原型对象,如此循环,直到 null 停止,这就是我们所说的原型链

隐式原型: proto 显示原型: prototype

相关方法: 1. hasOwnProperty() 判断属性是否是实例自身的属性 2. Object.getPrototypeOf() 获取实例的原型

3.3 作用域

作用域分成全局作用域函数作用域块级作用域,它标识着一个变量是否合法 (编译过程中就已经确认了)

当查询一个变量时,如果当前作用域查询不到,会往上一级作用域查找,如此循环,直到全局作用域,这就是我们所说的作用域链

3.4 执行上下文

从类型上看

  1. 全局执行上下文
  2. 函数执行上下文
  3. eval 执行上下文

从生命周期上看

  1. 创建阶段
    • this 绑定
    • 创建词法环境 (let、const会被提升到词法环境)
    • 创建变量环境 (var 声明的变量会被提升到变量环境)
  2. 执行阶段
    • 对变量进行赋值,执行代码
  3. 回收阶段
    • 当执行上下文弹出调用站后,会对上下文进行回收

执行上下文栈: 当 JS 执行代码时,首先遇到全局代码,会创建一个全局执行上下文并压入执行栈中,当遇到函数调用时,就会为该函数创建一个新的函数执行上下文压入栈中, 引擎会执行位于执行上下文栈顶的函数,当函数执行完后,执行上下文会从栈中弹出,继续执行下一个上下文,当所有代码都执行完毕后,从栈中弹出全局执行上下文

执行上下文

3.5 类数组对象

一个拥有 length 属性和若干索引属性的对象就是类数组对象。

将类数组对象转化成数组的方法:

1 Array.from(arrayLike)
+    
Skip to content

3 基础概念

3.1 闭包

执行外部函数返回内部函数后,虽然外部函数已经弹出调用栈了,但是内部函数对外部函数变量的引用依然保存在内存中,那么内部函数和这些变量的集合就叫做闭包。

闭包的好处: 1. 私有变量在内存中持久化

闭包的坏处: 1. 使用不当会造成内存泄漏

3.2 原型

在 js 中对象是由构造函数创建的,构造函数中会有一个 prototype 属性,指向一个对象,这个对象包含了由该构造函数创建的实例所共享的属性和方法, 由该构造函数创建的实例可以通过 proto 属性指向这个对象,这个对象就是我们所说的原型。

当想要访问对象的某个属性时,如果在当前对象查找不到,就会往该对象的原型查找,对象的原型也会有属于他的原型对象,如此循环,直到 null 停止,这就是我们所说的原型链

隐式原型: proto 显示原型: prototype

相关方法: 1. hasOwnProperty() 判断属性是否是实例自身的属性 2. Object.getPrototypeOf() 获取实例的原型

3.3 作用域

作用域分成全局作用域函数作用域块级作用域,它标识着一个变量是否合法 (编译过程中就已经确认了)

当查询一个变量时,如果当前作用域查询不到,会往上一级作用域查找,如此循环,直到全局作用域,这就是我们所说的作用域链

3.4 执行上下文

从类型上看

  1. 全局执行上下文
  2. 函数执行上下文
  3. eval 执行上下文

从生命周期上看

  1. 创建阶段
    • this 绑定
    • 创建词法环境 (let、const会被提升到词法环境)
    • 创建变量环境 (var 声明的变量会被提升到变量环境)
  2. 执行阶段
    • 对变量进行赋值,执行代码
  3. 回收阶段
    • 当执行上下文弹出调用站后,会对上下文进行回收

执行上下文栈: 当 JS 执行代码时,首先遇到全局代码,会创建一个全局执行上下文并压入执行栈中,当遇到函数调用时,就会为该函数创建一个新的函数执行上下文压入栈中, 引擎会执行位于执行上下文栈顶的函数,当函数执行完后,执行上下文会从栈中弹出,继续执行下一个上下文,当所有代码都执行完毕后,从栈中弹出全局执行上下文

执行上下文

3.5 类数组对象

一个拥有 length 属性和若干索引属性的对象就是类数组对象。

将类数组对象转化成数组的方法:

1 Array.from(arrayLike)
 
 2 Array.prototype.slice.call(arrayLike)
 
@@ -60,8 +60,8 @@
     }
 }
 
-fn(); // undefined
- +fn(); // undefined
+ \ No newline at end of file diff --git "a/guide/javaScript\347\233\270\345\205\263/\345\255\227\347\254\246\344\270\262\345\270\270\350\247\201\347\232\204API.html" "b/guide/javaScript\347\233\270\345\205\263/\345\255\227\347\254\246\344\270\262\345\270\270\350\247\201\347\232\204API.html" index 857cc87e..4f29e10a 100644 --- "a/guide/javaScript\347\233\270\345\205\263/\345\255\227\347\254\246\344\270\262\345\270\270\350\247\201\347\232\204API.html" +++ "b/guide/javaScript\347\233\270\345\205\263/\345\255\227\347\254\246\344\270\262\345\270\270\350\247\201\347\232\204API.html" @@ -11,7 +11,7 @@ - + @@ -23,8 +23,8 @@ -
Skip to content
- +
Skip to content
+ \ No newline at end of file diff --git "a/guide/javaScript\347\233\270\345\205\263/\345\256\232\344\271\211.html" "b/guide/javaScript\347\233\270\345\205\263/\345\256\232\344\271\211.html" index 04ace4a7..81c0dffc 100644 --- "a/guide/javaScript\347\233\270\345\205\263/\345\256\232\344\271\211.html" +++ "b/guide/javaScript\347\233\270\345\205\263/\345\256\232\344\271\211.html" @@ -11,7 +11,7 @@ - + @@ -23,8 +23,8 @@ -
Skip to content

1 定义

JavaScript 是一门动态语言,可以不需要定义变量类型

JavaScript 是一门弱类型语言,存在隐式类型转化

JavaScript 是一门解释型语言,在运行程序时动态编译

解释型语言特点: 1 每次运行都需要将源代码转化成机器码并执行,效率低 2 只要平台提供相应的解析器,就可以运行源代码,跨平台

V8 执行一段代码的流程图 流程

- +
Skip to content

1 定义

JavaScript 是一门动态语言,可以不需要定义变量类型

JavaScript 是一门弱类型语言,存在隐式类型转化

JavaScript 是一门解释型语言,在运行程序时动态编译

解释型语言特点: 1 每次运行都需要将源代码转化成机器码并执行,效率低 2 只要平台提供相应的解析器,就可以运行源代码,跨平台

V8 执行一段代码的流程图 流程

+ \ No newline at end of file diff --git "a/guide/javaScript\347\233\270\345\205\263/\345\257\271\350\261\241\345\270\270\350\247\201\347\232\204API.html" "b/guide/javaScript\347\233\270\345\205\263/\345\257\271\350\261\241\345\270\270\350\247\201\347\232\204API.html" index 81ccb166..e6f8b28d 100644 --- "a/guide/javaScript\347\233\270\345\205\263/\345\257\271\350\261\241\345\270\270\350\247\201\347\232\204API.html" +++ "b/guide/javaScript\347\233\270\345\205\263/\345\257\271\350\261\241\345\270\270\350\247\201\347\232\204API.html" @@ -11,7 +11,7 @@ - + @@ -23,8 +23,8 @@ -
Skip to content
- +
Skip to content
+ \ No newline at end of file diff --git "a/guide/javaScript\347\233\270\345\205\263/\346\225\260\346\215\256\347\261\273\345\236\213.html" "b/guide/javaScript\347\233\270\345\205\263/\346\225\260\346\215\256\347\261\273\345\236\213.html" index 200fe831..58efa03c 100644 --- "a/guide/javaScript\347\233\270\345\205\263/\346\225\260\346\215\256\347\261\273\345\236\213.html" +++ "b/guide/javaScript\347\233\270\345\205\263/\346\225\260\346\215\256\347\261\273\345\236\213.html" @@ -11,7 +11,7 @@ - + @@ -23,7 +23,7 @@ -
Skip to content

2 数据类型

2.1 数据类型

一共有 7 种基本数据类型

  • 1 Number - 基于 IEEE 754 标准实现,采用双精度 64 位二进制格式, -(2 ^ 63 - 1) ~ 2 ^ 63 - 1
  • 2 Boolean - 只有 true 和 false
  • 3 Undefined - 没有定义的值
  • 4 Null - 空值
  • 5 String - 字符串
  • 6 Symbol - 唯一不可修改的值
  • 7 BigInt - 大整数类型

一种引用类型

  • Object - 引用类型,存储在堆中

2.2 类型检测

2.2.1 typeof

判断基础数据类型,除了 null 也可以判断 function

js
typeof (function() {}) // function
+    
Skip to content

2 数据类型

2.1 数据类型

一共有 7 种基本数据类型

  • 1 Number - 基于 IEEE 754 标准实现,采用双精度 64 位二进制格式, -(2 ^ 63 - 1) ~ 2 ^ 63 - 1
  • 2 Boolean - 只有 true 和 false
  • 3 Undefined - 没有定义的值
  • 4 Null - 空值
  • 5 String - 字符串
  • 6 Symbol - 唯一不可修改的值
  • 7 BigInt - 大整数类型

一种引用类型

  • Object - 引用类型,存储在堆中

2.2 类型检测

2.2.1 typeof

判断基础数据类型,除了 null 也可以判断 function

js
typeof (function() {}) // function
 typeof (() => {}) // function
typeof (function() {}) // function
 typeof (() => {}) // function

但数组、对象、null 都会返回 object

js
typeof [] // object
 typeof {} // object
@@ -117,8 +117,8 @@
 a.length; // 3
 a.toUpperCase(); // "ABC"

3 undefined 和 null 的区别

undefined 表示未定义,一般变量声明了但还没有定义的时候返回 undefined null 表示空值,常用在对象初始化的场景

区别如下:

  • typeof null 返回的是 ‘object’, 因为在早期 javaScript 设计时,类型通过 1~3位标识进行存储,对象和null一样都是 000
  • typeof undefined 返回的是 ‘undefined’
  • undefined 不是保留字,可以被赋值,通常我们会用 void 0 表示 undefined,null 是保留字,不能被赋值

4 isNaN 和 Number.isNaN 的区别

  • isNaN 不会判断是否为数字,会先将参数转化为数字,再判断是否为 NaN
  • Number.isNaN 会判断是否是数字,是数字后才会判断是否是 NaN
js
isNaN('a'); // true
 Number.isNaN('a'); // false
isNaN('a'); // true
-Number.isNaN('a'); // false
- +Number.isNaN('a'); // false
+ \ No newline at end of file diff --git "a/guide/javaScript\347\233\270\345\205\263/\346\225\260\347\273\204\345\270\270\350\247\201\347\232\204API.html" "b/guide/javaScript\347\233\270\345\205\263/\346\225\260\347\273\204\345\270\270\350\247\201\347\232\204API.html" index b2683ce4..b7022bd2 100644 --- "a/guide/javaScript\347\233\270\345\205\263/\346\225\260\347\273\204\345\270\270\350\247\201\347\232\204API.html" +++ "b/guide/javaScript\347\233\270\345\205\263/\346\225\260\347\273\204\345\270\270\350\247\201\347\232\204API.html" @@ -11,7 +11,7 @@ - + @@ -23,8 +23,8 @@ -
Skip to content
- +
Skip to content
+ \ No newline at end of file diff --git "a/guide/javaScript\347\233\270\345\205\263/\346\226\260\347\232\204\350\277\220\347\256\227\347\254\246.html" "b/guide/javaScript\347\233\270\345\205\263/\346\226\260\347\232\204\350\277\220\347\256\227\347\254\246.html" index 4574f3f9..c99f95af 100644 --- "a/guide/javaScript\347\233\270\345\205\263/\346\226\260\347\232\204\350\277\220\347\256\227\347\254\246.html" +++ "b/guide/javaScript\347\233\270\345\205\263/\346\226\260\347\232\204\350\277\220\347\256\227\347\254\246.html" @@ -11,7 +11,7 @@ - + @@ -23,8 +23,8 @@ -
Skip to content
- +
Skip to content
+ \ No newline at end of file diff --git "a/guide/javaScript\347\233\270\345\205\263/\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217.html" "b/guide/javaScript\347\233\270\345\205\263/\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217.html" index 1d9a74b9..10344da9 100644 --- "a/guide/javaScript\347\233\270\345\205\263/\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217.html" +++ "b/guide/javaScript\347\233\270\345\205\263/\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217.html" @@ -11,7 +11,7 @@ - + @@ -23,8 +23,8 @@ -
Skip to content
- +
Skip to content
+ \ No newline at end of file diff --git "a/guide/javaScript\347\233\270\345\205\263/\347\273\247\346\211\277\347\233\270\345\205\263.html" "b/guide/javaScript\347\233\270\345\205\263/\347\273\247\346\211\277\347\233\270\345\205\263.html" index 68ad3d93..fd8f346c 100644 --- "a/guide/javaScript\347\233\270\345\205\263/\347\273\247\346\211\277\347\233\270\345\205\263.html" +++ "b/guide/javaScript\347\233\270\345\205\263/\347\273\247\346\211\277\347\233\270\345\205\263.html" @@ -11,7 +11,7 @@ - + @@ -23,7 +23,7 @@ -
Skip to content

继承

原型链继承

子类的原型对象是父类的实例对象

优点:

  • 简单易懂 缺点:
  • 1 实例化子类时,没办法向父类的构造函数传值
  • 2 所有子类实例共享一个父类,当某个子类修改了父类的属性时,其他子类也会受到影响
js
function Parent() {
+    
Skip to content

继承

原型链继承

子类的原型对象是父类的实例对象

优点:

  • 简单易懂 缺点:
  • 1 实例化子类时,没办法向父类的构造函数传值
  • 2 所有子类实例共享一个父类,当某个子类修改了父类的属性时,其他子类也会受到影响
js
function Parent() {
     this.name = 'parent';
 }
 
@@ -163,8 +163,8 @@
 }
 
 const children = new Children();
-children.getName(); // parent
- +children.getName(); // parent
+ \ No newline at end of file diff --git a/guide/webpack/Loader.html b/guide/webpack/Loader.html index 85f78b6e..b26d0f06 100644 --- a/guide/webpack/Loader.html +++ b/guide/webpack/Loader.html @@ -11,7 +11,7 @@ - + @@ -23,7 +23,7 @@ -
Skip to content

Loader

loader 是一个加载器,让 webpack 拥有加载和解析非 JavaScript 文件的能力

类型

  1. pre - 前置
  2. normal - 普通
  3. inline - 行内
  4. post - 后置
js
// 定义在 require 请求内部的叫做行内 loader
+    
Skip to content

Loader

loader 是一个加载器,让 webpack 拥有加载和解析非 JavaScript 文件的能力

类型

  1. pre - 前置
  2. normal - 普通
  3. inline - 行内
  4. post - 后置
js
// 定义在 require 请求内部的叫做行内 loader
 const a = require('inline1-loader!inline2-loader!a.js');
// 定义在 require 请求内部的叫做行内 loader
 const a = require('inline1-loader!inline2-loader!a.js');
  • 如果是 ! 作为前缀,将禁用 normal loader,例如 !inline1-loader!inline2-loader!a.js
  • 如果是 !! 作为前缀,将禁用所有 loader,例如 !!inline1-loader!inline2-loader!a.js
  • 如果是 -! 作为前缀,将禁用所有 loader 但不包含 post loader,例如 -!inline1-loader!inline2-loader!a.js

pitch

一个 loader 中存在 normal (必须) 和 pitch (可选)

先从左往右执行 loader 的 pitch 方法,在从右往左执行 loader 的默认方法

js
function preLoader(source) {
   console.log("pre1");
@@ -97,8 +97,8 @@
   console.log(`post1 pitch`);
 };
 
-// post1 pitch -> inline1 pitch -> normal1 pitch -> pre1 pitch -> pre1 -> normal1 -> inline1 -> post1

pitch loader

⚠️注意: 某一个 loader 的 pitch 方法返回了值,那么直接跳到默认方法阶段

例如 loader2 的 pitch 返回了值,则直接跳过当前 loader 后续的阶段 pitch loader

- +// post1 pitch -> inline1 pitch -> normal1 pitch -> pre1 pitch -> pre1 -> normal1 -> inline1 -> post1

pitch loader

⚠️注意: 某一个 loader 的 pitch 方法返回了值,那么直接跳到默认方法阶段

例如 loader2 的 pitch 返回了值,则直接跳过当前 loader 后续的阶段 pitch loader

+ \ No newline at end of file diff --git a/guide/webpack/index.html b/guide/webpack/index.html index 9482c958..288f5a05 100644 --- a/guide/webpack/index.html +++ b/guide/webpack/index.html @@ -11,7 +11,7 @@ - + @@ -23,8 +23,8 @@ -
Skip to content
- +
Skip to content
+ \ No newline at end of file diff --git a/guide/webpack/mini-webpack.html b/guide/webpack/mini-webpack.html index 49903f37..937ed8c5 100644 --- a/guide/webpack/mini-webpack.html +++ b/guide/webpack/mini-webpack.html @@ -11,7 +11,7 @@ - + @@ -23,8 +23,8 @@ -
Skip to content
- +
Skip to content
+ \ No newline at end of file diff --git "a/guide/webpack/\346\236\204\345\273\272\346\265\201\347\250\213.html" "b/guide/webpack/\346\236\204\345\273\272\346\265\201\347\250\213.html" index c31a1b3f..d6329e5d 100644 --- "a/guide/webpack/\346\236\204\345\273\272\346\265\201\347\250\213.html" +++ "b/guide/webpack/\346\236\204\345\273\272\346\265\201\347\250\213.html" @@ -11,7 +11,7 @@ - + @@ -23,7 +23,7 @@ -
Skip to content

构建流程

工作流程

webpack 的工作流程是一个串行的过程,从启动到结束会依次执行以下流程:

  1. 初始化参数:从配置文件和 Shell 语句中读取与合并参数,得出最终的参数;
  2. 开始编译:用上一步得到的参数初始化 Compiler 对象,加载所有配置的插件,执行对象的 run 方法开始执行编译;
  3. 确定入口:根据配置中的 entry 确定入口文件;
  4. 编译模块:从入口文件出发,调用所有配置的 Loader 对模块进行编译,再找出该模块依赖的模块,得到了每个模块被编译后的 最终内容 以及他们之间的 依赖关系图
  5. 输出资源:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的 Chunk,再把每个 Chunk 转换成一个单独的文件加入到输出列表,这步是可以修改输出内容的最后机会;
  6. 输出完成:在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统。

常见的问题

Module、Chunk、Bundle 的区别

module: 模块,一个模块就是一个文件

chunk: 代码块,一个 chunk 可以由多个模块组合而成

bundle: webpack 打包出来的文件

Loader 和 Plugin

loader 是一个加载器,让 webpack 拥有加载和解析非 JavaScript 文件的能力

Plugin 是一个插件,是对 webpack 功能的扩展,让 webpack 具有更高的灵活性

Compiler 和 Compilation 的区别

Compiler 对象在 webpack 启动时候被实例化,可以访问当前运行的 webpack 配置,包括 entry、output、loader 等配置,它是全局唯一的。

Plugin 的 apply 方法会传入一个 Compiler 对象,通过这个 Compiler 对象可以注册各种钩子函数,执行插件任务,也可以通过该对象获取配置信息。

js
Compiler.plugin('emit', function(compilation, callback) {
+    
Skip to content

构建流程

工作流程

webpack 的工作流程是一个串行的过程,从启动到结束会依次执行以下流程:

  1. 初始化参数:从配置文件和 Shell 语句中读取与合并参数,得出最终的参数;
  2. 开始编译:用上一步得到的参数初始化 Compiler 对象,加载所有配置的插件,执行对象的 run 方法开始执行编译;
  3. 确定入口:根据配置中的 entry 确定入口文件;
  4. 编译模块:从入口文件出发,调用所有配置的 Loader 对模块进行编译,再找出该模块依赖的模块,得到了每个模块被编译后的 最终内容 以及他们之间的 依赖关系图
  5. 输出资源:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的 Chunk,再把每个 Chunk 转换成一个单独的文件加入到输出列表,这步是可以修改输出内容的最后机会;
  6. 输出完成:在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统。

常见的问题

Module、Chunk、Bundle 的区别

module: 模块,一个模块就是一个文件

chunk: 代码块,一个 chunk 可以由多个模块组合而成

bundle: webpack 打包出来的文件

Loader 和 Plugin

loader 是一个加载器,让 webpack 拥有加载和解析非 JavaScript 文件的能力

Plugin 是一个插件,是对 webpack 功能的扩展,让 webpack 具有更高的灵活性

Compiler 和 Compilation 的区别

Compiler 对象在 webpack 启动时候被实例化,可以访问当前运行的 webpack 配置,包括 entry、output、loader 等配置,它是全局唯一的。

Plugin 的 apply 方法会传入一个 Compiler 对象,通过这个 Compiler 对象可以注册各种钩子函数,执行插件任务,也可以通过该对象获取配置信息。

js
Compiler.plugin('emit', function(compilation, callback) {
     // emit 是异步 hook, 在生成之前输出到目录之前调用
  });
Compiler.plugin('emit', function(compilation, callback) {
     // emit 是异步 hook, 在生成之前输出到目录之前调用
@@ -47,8 +47,8 @@
       config: [__filename], // 当配置修改时,缓存失效
     },
   },
-};

4 sideEffects

  • webpack4 需要配置 sideEffects: false
  • webpack5 可以根据源代码静态分析,自动将模块标记成无副作用。

5 支持 import 加载异步模块

6 支持模块联邦

参考文章

- +};

4 sideEffects

  • webpack4 需要配置 sideEffects: false
  • webpack5 可以根据源代码静态分析,自动将模块标记成无副作用。

5 支持 import 加载异步模块

6 支持模块联邦

参考文章

+ \ No newline at end of file diff --git "a/guide/webpack/\346\250\241\345\235\227\350\201\224\351\202\246.html" "b/guide/webpack/\346\250\241\345\235\227\350\201\224\351\202\246.html" index 4c44ec24..dea4c6d9 100644 --- "a/guide/webpack/\346\250\241\345\235\227\350\201\224\351\202\246.html" +++ "b/guide/webpack/\346\250\241\345\235\227\350\201\224\351\202\246.html" @@ -11,7 +11,7 @@ - + @@ -23,7 +23,7 @@ -
Skip to content

模块联邦

目的

更好的复用应用块或者库

每个应用块都是独立构建,被称之为容器

Module Federation

一个被引用的容器被称之为 remote

引用者被称之为 host

配置参数

字段类型含义
namestring必传值,即输出的模块名,被远程引用时的路径为 ${name}/$
libraryobject声明全局变量的方式,name为 umd 的name
filenamestring构建输出的文件名称
remotesobject(host 使用)远程引用的应用名及其别名的映射,使用时以 key 值作为 name
exposesobject(remote 使用)被引用时可暴露的资源路径以其别名
sharedobject与其他应用之间可以共享的第三方依赖,使你的代码中不用重复加载同一份依赖

remote 配置

js
// webpack.config.js
+    
Skip to content

模块联邦

目的

更好的复用应用块或者库

每个应用块都是独立构建,被称之为容器

Module Federation

一个被引用的容器被称之为 remote

引用者被称之为 host

配置参数

字段类型含义
namestring必传值,即输出的模块名,被远程引用时的路径为 ${name}/$
libraryobject声明全局变量的方式,name为 umd 的name
filenamestring构建输出的文件名称
remotesobject(host 使用)远程引用的应用名及其别名的映射,使用时以 key 值作为 name
exposesobject(remote 使用)被引用时可暴露的资源路径以其别名
sharedobject与其他应用之间可以共享的第三方依赖,使你的代码中不用重复加载同一份依赖

remote 配置

js
// webpack.config.js
 const path = require("path");
 const webpack = require("webpack");
 const HtmlWebpackPlugin = require("html-webpack-plugin");
@@ -203,8 +203,8 @@
        */
     }),
   ],
-};

host 和 remote 的区别在于: host 通过 remotes 引入模块 remote 通过 exposes 导出模块

如果是存在 shared 共享代码块得通过 bootstrap 动态引入 - https://webpack.js.org/concepts/module-federation/

项目应用图

项目应用图

案例代码

案例代码

原理

项目应用图

remote 通过 exposes 导出模块 host 通过 remotes 引入远程模块

若存在共享依赖会存储到同一个变量中(require.S), 这个变量(require.S) 存放各个作用域下的共享模块, 可以通过 作用域名(scopeName)、包名(key)、版本 (version) 再去获取对应的共享模块合如 modules 中

案例代码

- +};

host 和 remote 的区别在于: host 通过 remotes 引入模块 remote 通过 exposes 导出模块

如果是存在 shared 共享代码块得通过 bootstrap 动态引入 - https://webpack.js.org/concepts/module-federation/

项目应用图

项目应用图

案例代码

案例代码

原理

项目应用图

remote 通过 exposes 导出模块 host 通过 remotes 引入远程模块

若存在共享依赖会存储到同一个变量中(require.S), 这个变量(require.S) 存放各个作用域下的共享模块, 可以通过 作用域名(scopeName)、包名(key)、版本 (version) 再去获取对应的共享模块合如 modules 中

案例代码

+ \ No newline at end of file diff --git "a/guide/webpack/\347\203\255\346\233\264\346\226\260\345\216\237\347\220\206.html" "b/guide/webpack/\347\203\255\346\233\264\346\226\260\345\216\237\347\220\206.html" index 7d750756..bf130bc7 100644 --- "a/guide/webpack/\347\203\255\346\233\264\346\226\260\345\216\237\347\220\206.html" +++ "b/guide/webpack/\347\203\255\346\233\264\346\226\260\345\216\237\347\220\206.html" @@ -11,7 +11,7 @@ - + @@ -23,8 +23,8 @@ -
Skip to content
- +
Skip to content
+ \ No newline at end of file diff --git "a/guide/\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263/\346\246\202\350\246\201.html" "b/guide/\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263/\346\246\202\350\246\201.html" index 1a827051..518076bd 100644 --- "a/guide/\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263/\346\246\202\350\246\201.html" +++ "b/guide/\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263/\346\246\202\350\246\201.html" @@ -12,7 +12,7 @@ - + @@ -24,8 +24,8 @@ -
Skip to content
- +
Skip to content
+ \ No newline at end of file diff --git "a/guide/\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263/\346\265\217\350\247\210\345\231\250\345\206\205\346\240\270.html" "b/guide/\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263/\346\265\217\350\247\210\345\231\250\345\206\205\346\240\270.html" index 9c5cb12b..aa510108 100644 --- "a/guide/\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263/\346\265\217\350\247\210\345\231\250\345\206\205\346\240\270.html" +++ "b/guide/\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263/\346\265\217\350\247\210\345\231\250\345\206\205\346\240\270.html" @@ -11,7 +11,7 @@ - + @@ -23,8 +23,8 @@ -
Skip to content

浏览器内核

  • Trident (IE)
  • Gecko (Firefox)
  • Webkit (Safari)
  • Blink (Chrome、Opera) Blink 是 Webkit 的一个分支
- +
Skip to content

浏览器内核

  • Trident (IE)
  • Gecko (Firefox)
  • Webkit (Safari)
  • Blink (Chrome、Opera) Blink 是 Webkit 的一个分支
+ \ No newline at end of file diff --git "a/guide/\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263/\346\265\217\350\247\210\345\231\250\345\256\211\345\205\250.html" "b/guide/\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263/\346\265\217\350\247\210\345\231\250\345\256\211\345\205\250.html" index dae4ab54..d0e57259 100644 --- "a/guide/\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263/\346\265\217\350\247\210\345\231\250\345\256\211\345\205\250.html" +++ "b/guide/\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263/\346\265\217\350\247\210\345\231\250\345\256\211\345\205\250.html" @@ -11,7 +11,7 @@ - + @@ -23,8 +23,8 @@ -
Skip to content

浏览器安全

页面安全

同源策略

协议、域名、端口号都相同,才是同源。

限制

  1. 无法进行 DOM 操作
  2. 无法获取 Cookie、LocalStorage 等数据
  3. 无法向不同源发请求

开放

  1. 默认页面中可以引用任意第三方资源

    引入 CSP (内容安全策略)

    渲染流程图

  2. 只能请求同源的接口

    引入 CORS (跨域资源共享)

    • 简单请求 (HEAD/POST/GET请求)

      1. 浏览器在请求头上添加 Oirgin 字段,该字段用来说明请求来自那个源,服务器可以根据这个值决定是否同意这次请求
      2. 当服务器收到请求后,根据 Origin 判断是否在许可范围内
      3. 如果不在范围内,服务器会返回一个正常的 HTTP 响应,浏览器发现该响应头没有包含 Access-Control-Allow-Origin 字段,就会抛出一个错误,被 XMLHttpRequest 的 onerror 回调函数捕获 (由于正常响应,其状态码是 200,所以该错误不能通过状态码识别)
      4. 如果 Origin 在指定范围内,服务器返回的响应会多几个头信息字段
        • Access-Control-Allow-Origin(必须) 判断源是否可以跨域,该值要么是请求的 Origin,要么是 *

        • Access-Control-Allow-Credentials 是否允许发送 Cookie,默认为 false 如果 Access-Control-Allow-Origin 的值为 *,则无法发送 Cookie

        • Access-Control-Expose-Headers 制定其他的头信息字段可以暴露给客户端 因为默认情况下,只有 6 个字段可以被暴露,其他的都会被过滤掉

          简单请求

    • 非简单请求 (PUT/DELETE 或者 Content-type字段类型是 application/json)

      1. 浏览器发起 Option 预检请求
      2. 服务器收到预检请求后,检查
        • Origin 发起请求的源信息
        • Access-Control-Request-Method 浏览器会发起请求的方法
        • Access-Control-Request-Headers 请求额外发送的头信息字段
      3. 如果服务器否定预检请求,会返回一个正常的 HTTP 响应,但是没有任何的 CORS 相关的头信息字段,这是浏览器会认定服务器不同意预检,触发错误
      4. 如果服务器同意预检请求,会返回一个正常的 HTTP 响应,但是会多几个 CORS 相关的头信息字段
        • Access-Control-Allow-Origin (必须)
        • Access-Control-Allow-Methods (必须)
        • Access-Control-Allow-Credentials
        • Access-Control-Expose-Headers
        • Access-Control-Max-Age - 预检请求的有效期, 单位秒
        • Access-Control-Allow-Headers

      非简单请求

  3. 只能操作同源的DOM

    引入了跨文档消息机制 postMessage

XSS 攻击

跨域脚本攻击。

类型

  1. 存储型

    脚本存储在服务器,用户访问时,脚本从服务器返回,浏览器执行脚本

  2. 反射型

    在文章链接参数上存放了一段恶意脚本,用户访问时,脚本从参数中取出,浏览器执行脚本

  3. DOM 型

    比如在搜索的时候,添加了一段脚本, 如果网站的搜索功能没有对用户输入进行适当的过滤和转义,搜索结果页面可能会将恶意的脚本代码直接插入到 HTML 中,并在用户浏览器中执行

    web 资源在传输或者用户在使用的过程中修改了 Web 页面的数据

预防

  1. 对输入的内容进行截取或者转义(encode)
  2. 限制输入的长度和类型
  3. 引入内容安全策略 (CSP)
  4. 对 Cookie 设置 HttpOnly 属性

CSRF 攻击

跨站请求伪造。

比如诱导用户点击链接,访问网址后,网址通过用户的登录信息伪造请求

必要条件

  1. 站点有 CSRF 漏洞
  2. 用户登录了
  3. 用户点击了诱导链接

预防

  1. 给 Cookie 新增 SameSite 属性
    • Strict: 第三方站点无法发送 Cookie
    • Lax (默认): 第三方站点如果是 GET 请求可以发送 Cookie
    • None 不做限制 Cookie的书写
  2. 通过请求的 Origin or Referer 字段判断请求合法性
  3. 在请求地址中添加 token 并验证

浏览器安全

将渲染进程放在沙箱中

  • 无法持久存储
  • 无法访问网络
  • 无法监听用户交互
  • 需要通过 IPC 与浏览器主进程通信,由浏览器进程处理后,再将结果传递给渲染进程

网络安全

HTTPS、重放攻击、验签

  • 基本属性:

    • name
    • value
  • 访问性:

    • expire
    • path
    • domain
  • 安全性:

    • secure
    • httpOnly
    • sameSite
- +
Skip to content

浏览器安全

页面安全

同源策略

协议、域名、端口号都相同,才是同源。

限制

  1. 无法进行 DOM 操作
  2. 无法获取 Cookie、LocalStorage 等数据
  3. 无法向不同源发请求

开放

  1. 默认页面中可以引用任意第三方资源

    引入 CSP (内容安全策略)

    渲染流程图

  2. 只能请求同源的接口

    引入 CORS (跨域资源共享)

    • 简单请求 (HEAD/POST/GET请求)

      1. 浏览器在请求头上添加 Oirgin 字段,该字段用来说明请求来自那个源,服务器可以根据这个值决定是否同意这次请求
      2. 当服务器收到请求后,根据 Origin 判断是否在许可范围内
      3. 如果不在范围内,服务器会返回一个正常的 HTTP 响应,浏览器发现该响应头没有包含 Access-Control-Allow-Origin 字段,就会抛出一个错误,被 XMLHttpRequest 的 onerror 回调函数捕获 (由于正常响应,其状态码是 200,所以该错误不能通过状态码识别)
      4. 如果 Origin 在指定范围内,服务器返回的响应会多几个头信息字段
        • Access-Control-Allow-Origin(必须) 判断源是否可以跨域,该值要么是请求的 Origin,要么是 *

        • Access-Control-Allow-Credentials 是否允许发送 Cookie,默认为 false 如果 Access-Control-Allow-Origin 的值为 *,则无法发送 Cookie

        • Access-Control-Expose-Headers 制定其他的头信息字段可以暴露给客户端 因为默认情况下,只有 6 个字段可以被暴露,其他的都会被过滤掉

          简单请求

    • 非简单请求 (PUT/DELETE 或者 Content-type字段类型是 application/json)

      1. 浏览器发起 Option 预检请求
      2. 服务器收到预检请求后,检查
        • Origin 发起请求的源信息
        • Access-Control-Request-Method 浏览器会发起请求的方法
        • Access-Control-Request-Headers 请求额外发送的头信息字段
      3. 如果服务器否定预检请求,会返回一个正常的 HTTP 响应,但是没有任何的 CORS 相关的头信息字段,这是浏览器会认定服务器不同意预检,触发错误
      4. 如果服务器同意预检请求,会返回一个正常的 HTTP 响应,但是会多几个 CORS 相关的头信息字段
        • Access-Control-Allow-Origin (必须)
        • Access-Control-Allow-Methods (必须)
        • Access-Control-Allow-Credentials
        • Access-Control-Expose-Headers
        • Access-Control-Max-Age - 预检请求的有效期, 单位秒
        • Access-Control-Allow-Headers

      非简单请求

  3. 只能操作同源的DOM

    引入了跨文档消息机制 postMessage

XSS 攻击

跨域脚本攻击。

类型

  1. 存储型

    脚本存储在服务器,用户访问时,脚本从服务器返回,浏览器执行脚本

  2. 反射型

    在文章链接参数上存放了一段恶意脚本,用户访问时,脚本从参数中取出,浏览器执行脚本

  3. DOM 型

    比如在搜索的时候,添加了一段脚本, 如果网站的搜索功能没有对用户输入进行适当的过滤和转义,搜索结果页面可能会将恶意的脚本代码直接插入到 HTML 中,并在用户浏览器中执行

    web 资源在传输或者用户在使用的过程中修改了 Web 页面的数据

预防

  1. 对输入的内容进行截取或者转义(encode)
  2. 限制输入的长度和类型
  3. 引入内容安全策略 (CSP)
  4. 对 Cookie 设置 HttpOnly 属性

CSRF 攻击

跨站请求伪造。

比如诱导用户点击链接,访问网址后,网址通过用户的登录信息伪造请求

必要条件

  1. 站点有 CSRF 漏洞
  2. 用户登录了
  3. 用户点击了诱导链接

预防

  1. 给 Cookie 新增 SameSite 属性
    • Strict: 第三方站点无法发送 Cookie
    • Lax (默认): 第三方站点如果是 GET 请求可以发送 Cookie
    • None 不做限制 Cookie的书写
  2. 通过请求的 Origin or Referer 字段判断请求合法性
  3. 在请求地址中添加 token 并验证

浏览器安全

将渲染进程放在沙箱中

  • 无法持久存储
  • 无法访问网络
  • 无法监听用户交互
  • 需要通过 IPC 与浏览器主进程通信,由浏览器进程处理后,再将结果传递给渲染进程

网络安全

HTTPS、重放攻击、验签

  • 基本属性:

    • name
    • value
  • 访问性:

    • expire
    • path
    • domain
  • 安全性:

    • secure
    • httpOnly
    • sameSite
+ \ No newline at end of file diff --git "a/guide/\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263/\346\265\217\350\247\210\345\231\250\346\270\262\346\237\223\346\265\201\347\250\213.html" "b/guide/\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263/\346\265\217\350\247\210\345\231\250\346\270\262\346\237\223\346\265\201\347\250\213.html" index 16c31d69..cda3c19d 100644 --- "a/guide/\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263/\346\265\217\350\247\210\345\231\250\346\270\262\346\237\223\346\265\201\347\250\213.html" +++ "b/guide/\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263/\346\265\217\350\247\210\345\231\250\346\270\262\346\237\223\346\265\201\347\250\213.html" @@ -11,7 +11,7 @@ - + @@ -23,8 +23,8 @@ -
Skip to content

浏览器渲染流程

浏览器渲染流程

  1. 发出请求到页面首次绘制

    • 第一阶段: 页面提交请求到服务器响应,这时候页面还是之前的页面
    • 第二阶段: 获取到响应数据提交到渲染进程,进行 HTML 解析、CSS 加载、JS 加载、JS 执行、CSSOM 解析、布局树生成、页面绘制
    • 第三阶段: 等首次加载完成后,页面一点点被渲染
  2. HTML 解析

  3. 生成 CSSOM 树

    CSS 不会阻塞 HTML 解析,但是会阻塞页面渲染,因为要生成渲染树

  4. 生成布局树

    去除不显示的节点,计算样式

  5. 分层和合成机制

    • 分层: 分层树在布局树之后,分层树的每一个节点都是图层,如没有,则和父节点同一个图层

    • 绘制阶段: 根据图层在绘制阶段生成绘制指令

    • 光栅化: 根据绘制指令,将每个图层都绘制成一张图片

    • 合成: 合成线程将多张图片合成一张图片,然后显示在屏幕上 (由合成线程完成,不影响主线程)

      • 优化操作1: 合成线程内会维护一个光栅化线程池,将绘制指令列表提交到 GPU 进行光栅化,生成位图,放在内存中
      • 优化操作2: 分块,合成线程将图层分块,优先渲染离屏幕最近的图块
      • 合成线程
  6. 页面显示

常见的问题

1 从输入 URL 到页面渲染完成,发生了什么?

  1. 浏览器会根据用户输入的内容判断是关键字还是URL
  2. 如果是关键字,会将其组成成带有搜索关键字的URL,通过IPC进程通信发送给网络进程
  3. 网络进程发起请求前,会判断是否命中强缓存,如命中直接返回存储资源
  4. 否则发起请求,根据 DNS 解析获取域名对应的 IP 地址,进行 TCP、HTTP 连接
  5. 服务端收到请求后,会判断是否命中协商缓存,如命中则返回304状态码
  6. 如返回的是301、302状态码,浏览器会根据响应头返回的location字段,进行重定向
  7. 如是正常返回资源类型,浏览器会根据 content-type 对资源做相对应的操作,如果是下载类型则进行下载,如果是html类型则会提交到渲染进程进行解析
  8. 解析 HTML,转换成浏览器能识别的 DOM 树
  9. 解析 CSS,转化成浏览器能识别的 CSS 样式树
  10. 根据 DOM 和 CSS 样式树,通过 布局计算生成 布局树
  11. 根据布局树上的分层属性(z-index),生成分层树
  12. 根据分层树,生成绘制指令列表
  13. 渲染主线程会将绘制指令列表提交给合成线程
  14. 合成线程会维护一个光栅化线程池,将绘制指令列表提交到 GPU 进行光栅化,生成位图,放在内存中
  15. 合成线程通信浏览器进程,浏览器进程将内存中的数据输出到显卡的后缓存区,在下一帧绘制之前,显卡的后缓冲区与前缓冲区对换,显示屏读取前缓冲区数据,显示到屏幕上

整体流程

2 回流和重绘有什么区别

回流:元素尺寸、定位改变,可能会影响到其他元素的位置

重绘:元素外观改变,如背景色、颜色,元素尺寸位置不改变且不影响其他元素

减少回流的方法:

  1. 集中修改
    • 修改样式,使用 class
    • 修改前将 DOM 改成 display: none,修改后再显示
    • 使用 DocumentFragment
    • resize、scroll 事件,使用防抖
  2. 使用 BFC
    • 隔离内部元素对外部元素的影响
  3. 脱离文档流
    • position: absolute、fixed
    • float
  4. 提升合成图层
    • CSS3 属性: will-change、transform: translate3d(0);
  5. 不是用 offsetHeight、getBoundingClientRect
    • 使用 intersectionObserver API - 判断元素是否在可视区域内

BFC: 块级格式化上下文 特点: BFC 内部元素不会影响到外部元素 形成条件:

  1. HTML 元素
  2. overflow: hidden、auto、scroll
  3. position: absolute、fixed
  4. float 元素
  5. display: inline-block、flex、inline-flex等

3 渲染流程图

渲染流程图

JS 会阻塞 HTML 的解析和渲染

CSS 不会阻塞 HTML 解析,但会阻塞 DOM 渲染,还会阻塞 JS 的执行

为什么 CSS 会阻塞 JS 的执行?

因为 JS 可能会操作 DOM 节点和 CSS 样式,因此浏览器为了获取到最新的 CSS 样式,样式表会在后面的 JS 执行前先加载执行完毕,所以 CSS 会阻塞 JS 的执行

- +
Skip to content

浏览器渲染流程

浏览器渲染流程

  1. 发出请求到页面首次绘制

    • 第一阶段: 页面提交请求到服务器响应,这时候页面还是之前的页面
    • 第二阶段: 获取到响应数据提交到渲染进程,进行 HTML 解析、CSS 加载、JS 加载、JS 执行、CSSOM 解析、布局树生成、页面绘制
    • 第三阶段: 等首次加载完成后,页面一点点被渲染
  2. HTML 解析

  3. 生成 CSSOM 树

    CSS 不会阻塞 HTML 解析,但是会阻塞页面渲染,因为要生成渲染树

  4. 生成布局树

    去除不显示的节点,计算样式

  5. 分层和合成机制

    • 分层: 分层树在布局树之后,分层树的每一个节点都是图层,如没有,则和父节点同一个图层

    • 绘制阶段: 根据图层在绘制阶段生成绘制指令

    • 光栅化: 根据绘制指令,将每个图层都绘制成一张图片

    • 合成: 合成线程将多张图片合成一张图片,然后显示在屏幕上 (由合成线程完成,不影响主线程)

      • 优化操作1: 合成线程内会维护一个光栅化线程池,将绘制指令列表提交到 GPU 进行光栅化,生成位图,放在内存中
      • 优化操作2: 分块,合成线程将图层分块,优先渲染离屏幕最近的图块
      • 合成线程
  6. 页面显示

常见的问题

1 从输入 URL 到页面渲染完成,发生了什么?

  1. 浏览器会根据用户输入的内容判断是关键字还是URL
  2. 如果是关键字,会将其组成成带有搜索关键字的URL,通过IPC进程通信发送给网络进程
  3. 网络进程发起请求前,会判断是否命中强缓存,如命中直接返回存储资源
  4. 否则发起请求,根据 DNS 解析获取域名对应的 IP 地址,进行 TCP、HTTP 连接
  5. 服务端收到请求后,会判断是否命中协商缓存,如命中则返回304状态码
  6. 如返回的是301、302状态码,浏览器会根据响应头返回的location字段,进行重定向
  7. 如是正常返回资源类型,浏览器会根据 content-type 对资源做相对应的操作,如果是下载类型则进行下载,如果是html类型则会提交到渲染进程进行解析
  8. 解析 HTML,转换成浏览器能识别的 DOM 树
  9. 解析 CSS,转化成浏览器能识别的 CSS 样式树
  10. 根据 DOM 和 CSS 样式树,通过 布局计算生成 布局树
  11. 根据布局树上的分层属性(z-index),生成分层树
  12. 根据分层树,生成绘制指令列表
  13. 渲染主线程会将绘制指令列表提交给合成线程
  14. 合成线程会维护一个光栅化线程池,将绘制指令列表提交到 GPU 进行光栅化,生成位图,放在内存中
  15. 合成线程通信浏览器进程,浏览器进程将内存中的数据输出到显卡的后缓存区,在下一帧绘制之前,显卡的后缓冲区与前缓冲区对换,显示屏读取前缓冲区数据,显示到屏幕上

整体流程

2 回流和重绘有什么区别

回流:元素尺寸、定位改变,可能会影响到其他元素的位置

重绘:元素外观改变,如背景色、颜色,元素尺寸位置不改变且不影响其他元素

减少回流的方法:

  1. 集中修改
    • 修改样式,使用 class
    • 修改前将 DOM 改成 display: none,修改后再显示
    • 使用 DocumentFragment
    • resize、scroll 事件,使用防抖
  2. 使用 BFC
    • 隔离内部元素对外部元素的影响
  3. 脱离文档流
    • position: absolute、fixed
    • float
  4. 提升合成图层
    • CSS3 属性: will-change、transform: translate3d(0);
  5. 不是用 offsetHeight、getBoundingClientRect
    • 使用 intersectionObserver API - 判断元素是否在可视区域内

BFC: 块级格式化上下文 特点: BFC 内部元素不会影响到外部元素 形成条件:

  1. HTML 元素
  2. overflow: hidden、auto、scroll
  3. position: absolute、fixed
  4. float 元素
  5. display: inline-block、flex、inline-flex等

3 渲染流程图

渲染流程图

JS 会阻塞 HTML 的解析和渲染

CSS 不会阻塞 HTML 解析,但会阻塞 DOM 渲染,还会阻塞 JS 的执行

为什么 CSS 会阻塞 JS 的执行?

因为 JS 可能会操作 DOM 节点和 CSS 样式,因此浏览器为了获取到最新的 CSS 样式,样式表会在后面的 JS 执行前先加载执行完毕,所以 CSS 会阻塞 JS 的执行

+ \ No newline at end of file diff --git "a/guide/\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263/\346\265\217\350\247\210\345\231\250\347\274\223\345\255\230.html" "b/guide/\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263/\346\265\217\350\247\210\345\231\250\347\274\223\345\255\230.html" index 2290240b..780ecf3e 100644 --- "a/guide/\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263/\346\265\217\350\247\210\345\231\250\347\274\223\345\255\230.html" +++ "b/guide/\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263/\346\265\217\350\247\210\345\231\250\347\274\223\345\255\230.html" @@ -11,7 +11,7 @@ - + @@ -23,7 +23,7 @@ -
Skip to content

浏览器缓存

缓存

从 HTTP 缓存策略来说

  • 强缓存
  • 协商缓存

从浏览器的缓存位置来说

  • Service Worker Cache (必须是 Https)
  • Memory Cache (内存缓存)
  • Disk Cache (硬盘缓存)
  • Push Cache (Http2.0)

本地存储

请求时携带,用于信息持久化

Local Storage 本地存储

用于长期不变化的数据,只能存储字符串

Session Storage 会话存储

用于存储当前会话的数据,只能存储字符串

indexedDB

非关系型数据库

Service Worker

运行在浏览器背后的独立线程(必须 HTTPS 才能使用)

js
// main.js
+    
Skip to content

浏览器缓存

缓存

从 HTTP 缓存策略来说

  • 强缓存
  • 协商缓存

从浏览器的缓存位置来说

  • Service Worker Cache (必须是 Https)
  • Memory Cache (内存缓存)
  • Disk Cache (硬盘缓存)
  • Push Cache (Http2.0)

本地存储

请求时携带,用于信息持久化

Local Storage 本地存储

用于长期不变化的数据,只能存储字符串

Session Storage 会话存储

用于存储当前会话的数据,只能存储字符串

indexedDB

非关系型数据库

Service Worker

运行在浏览器背后的独立线程(必须 HTTPS 才能使用)

js
// main.js
 /* 判断当前浏览器是否支持serviceWorker */
 if ('serviceWorker' in navigator) {
   /* 当页面加载完成就创建一个 serviceWorker */
@@ -115,8 +115,8 @@
       return response;
     })()
   );
-});
- +});
+ \ No newline at end of file diff --git "a/guide/\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263/\346\265\217\350\247\210\345\231\250\350\277\233\347\250\213\346\236\266\346\236\204.html" "b/guide/\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263/\346\265\217\350\247\210\345\231\250\350\277\233\347\250\213\346\236\266\346\236\204.html" index f74e839d..96c7fe7f 100644 --- "a/guide/\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263/\346\265\217\350\247\210\345\231\250\350\277\233\347\250\213\346\236\266\346\236\204.html" +++ "b/guide/\346\265\217\350\247\210\345\231\250\347\233\270\345\205\263/\346\265\217\350\247\210\345\231\250\350\277\233\347\250\213\346\236\266\346\236\204.html" @@ -11,7 +11,7 @@ - + @@ -23,8 +23,8 @@ -
Skip to content

浏览器进程架构

进程与线程

进程

进程是一个程序的实例

进程是系统进行资源调度和分配的最小单位

进程之间相互独立,通过 IPC 进行通信

线程

线程是 CPU 调度的最小单位

线程之间共享进程的数据

线程里面会有协程,但只能运行一个

浏览器架构

1 浏览器主进程

用户交互、文件存储、页面显示、子进程管理

2 渲染进程

解析资源、执行 js

渲染进程被浏览器放在安全沙箱里面,因此渲染进程的资源是通过网络获取

  • 渲染线程: 渲染页面
  • JS 线程:解析执行 js
  • 事件触发线程: 事件循环
  • 定时器线程:定时器相关
  • 异步 http 请求线程: 请求相关

3 GPU 进程

UI界面的绘制

4 网络进程

网络资源加载

5 插件进程

管理插件

- +
Skip to content

浏览器进程架构

进程与线程

进程

进程是一个程序的实例

进程是系统进行资源调度和分配的最小单位

进程之间相互独立,通过 IPC 进行通信

线程

线程是 CPU 调度的最小单位

线程之间共享进程的数据

线程里面会有协程,但只能运行一个

浏览器架构

1 浏览器主进程

用户交互、文件存储、页面显示、子进程管理

2 渲染进程

解析资源、执行 js

渲染进程被浏览器放在安全沙箱里面,因此渲染进程的资源是通过网络获取

  • 渲染线程: 渲染页面
  • JS 线程:解析执行 js
  • 事件触发线程: 事件循环
  • 定时器线程:定时器相关
  • 异步 http 请求线程: 请求相关

3 GPU 进程

UI界面的绘制

4 网络进程

网络资源加载

5 插件进程

管理插件

+ \ No newline at end of file diff --git "a/guide/\347\275\221\347\273\234\347\233\270\345\205\263/CDN.html" "b/guide/\347\275\221\347\273\234\347\233\270\345\205\263/CDN.html" index ed605667..34c7f656 100644 --- "a/guide/\347\275\221\347\273\234\347\233\270\345\205\263/CDN.html" +++ "b/guide/\347\275\221\347\273\234\347\233\270\345\205\263/CDN.html" @@ -11,7 +11,7 @@ - + @@ -23,8 +23,8 @@ -
Skip to content

CDN

定义

内容分发网络,利用最靠近用户的服务器,将资源更快更可靠的给到用户

组成

  1. 分发服务系统

    最小单位是 Cache 设备

    • 响应用户请求
    • 与源站点进行资源同步
  2. 负载均衡系统

    负责对用户的请求进行调度

  3. 运营管理系统

    负责业务层面与外界系统的交互所需要的收集、整理、交付等工作 (为了做闭环)

    运营管理子系统 网络管理子系统

作用

托管 web 资源,加速 web 资源的获取速度

性能方面

  1. 用户从最近的 CDN 站点获取资源,访问速度更快
  2. 突破 TCP 只有同域名下只有 6 个的限制
  3. 减少源服务器的负担

安全方面

  1. 针对 DDos: 通过监控分析异常流量,限制请求频率
  2. 针对 MITM: 从源服务器到 CDN 节点到 ISP (Internet Service Provider, 网络运营提供商),全链路 HTTPS 通信

工作原理

没有使用 CDN 过程

  1. 浏览器通过 DNS 对域名进行解析,得到此域名对应的 IP 地址
  2. 浏览器根据得到的 IP 地址,向域名的服务主机发送数据请求
  3. 服务器向浏览器返回响应数据

使用了 CDN 过程

  1. 获取负载均衡服务器 IP 地址 (自底向上)

      1. 数据的 URL 先进行 DNS 系统解析,发现该 URL 对应的是一个 CDN 专用的 DNS 服务器,DNS 系统就会将域名解析权交给 CNAME 指向的 CDN 专用的 DNS 服务器
      1. CDN 专用的 DNS 服务器将 CDN 全局负载均衡设备 IP 地址返回给用户
      1. 用户向 CDN 的全局负载均衡设备发起数据请求
  2. 获取目标缓存服务器 IP 地址 (自顶向下)

      1. CDN 全局负载均衡设备根据用户 IP 地址以及用户请求的 URL,选择一台用户所属区域的负载均衡设备
      1. 区域负责均衡设备选择一台适合的缓存服务器来提供服务,将该缓存服务器的 IP 地址返回给全局负载均衡设备
      1. 全局负载均衡设备把服务器 IP 地址返回给用户
  3. 用户发起请求获取

    • 用户向该缓存服务器发起请求,缓存服务器响应用户的请求,将用户所需内容发送支用户终端 (如果缓存服务器没有用户想要的内容,那么缓存服务器会穿透 CDN 集群往源服务器获取设备)

流程

使用场景

  1. 使用第三方 CDN 服务 (例如开源框架可以使用第三方 CDN 服务,如 React、Vue、JQuery)
  2. 使用 CDN 进行静态资源的缓存 (将网站的资源放在 CDN 上)
  3. 直播传送 (直播本质也是使用流媒体进行传送,CDN 也支持流媒体传送,所以直播完全可以使用 CDN 来提高访问速度)
- +
Skip to content

CDN

定义

内容分发网络,利用最靠近用户的服务器,将资源更快更可靠的给到用户

组成

  1. 分发服务系统

    最小单位是 Cache 设备

    • 响应用户请求
    • 与源站点进行资源同步
  2. 负载均衡系统

    负责对用户的请求进行调度

  3. 运营管理系统

    负责业务层面与外界系统的交互所需要的收集、整理、交付等工作 (为了做闭环)

    运营管理子系统 网络管理子系统

作用

托管 web 资源,加速 web 资源的获取速度

性能方面

  1. 用户从最近的 CDN 站点获取资源,访问速度更快
  2. 突破 TCP 只有同域名下只有 6 个的限制
  3. 减少源服务器的负担

安全方面

  1. 针对 DDos: 通过监控分析异常流量,限制请求频率
  2. 针对 MITM: 从源服务器到 CDN 节点到 ISP (Internet Service Provider, 网络运营提供商),全链路 HTTPS 通信

工作原理

没有使用 CDN 过程

  1. 浏览器通过 DNS 对域名进行解析,得到此域名对应的 IP 地址
  2. 浏览器根据得到的 IP 地址,向域名的服务主机发送数据请求
  3. 服务器向浏览器返回响应数据

使用了 CDN 过程

  1. 获取负载均衡服务器 IP 地址 (自底向上)

      1. 数据的 URL 先进行 DNS 系统解析,发现该 URL 对应的是一个 CDN 专用的 DNS 服务器,DNS 系统就会将域名解析权交给 CNAME 指向的 CDN 专用的 DNS 服务器
      1. CDN 专用的 DNS 服务器将 CDN 全局负载均衡设备 IP 地址返回给用户
      1. 用户向 CDN 的全局负载均衡设备发起数据请求
  2. 获取目标缓存服务器 IP 地址 (自顶向下)

      1. CDN 全局负载均衡设备根据用户 IP 地址以及用户请求的 URL,选择一台用户所属区域的负载均衡设备
      1. 区域负责均衡设备选择一台适合的缓存服务器来提供服务,将该缓存服务器的 IP 地址返回给全局负载均衡设备
      1. 全局负载均衡设备把服务器 IP 地址返回给用户
  3. 用户发起请求获取

    • 用户向该缓存服务器发起请求,缓存服务器响应用户的请求,将用户所需内容发送支用户终端 (如果缓存服务器没有用户想要的内容,那么缓存服务器会穿透 CDN 集群往源服务器获取设备)

流程

使用场景

  1. 使用第三方 CDN 服务 (例如开源框架可以使用第三方 CDN 服务,如 React、Vue、JQuery)
  2. 使用 CDN 进行静态资源的缓存 (将网站的资源放在 CDN 上)
  3. 直播传送 (直播本质也是使用流媒体进行传送,CDN 也支持流媒体传送,所以直播完全可以使用 CDN 来提高访问速度)
+ \ No newline at end of file diff --git "a/guide/\347\275\221\347\273\234\347\233\270\345\205\263/DNS.html" "b/guide/\347\275\221\347\273\234\347\233\270\345\205\263/DNS.html" index 2a37b770..f928ee90 100644 --- "a/guide/\347\275\221\347\273\234\347\233\270\345\205\263/DNS.html" +++ "b/guide/\347\275\221\347\273\234\347\233\270\345\205\263/DNS.html" @@ -11,7 +11,7 @@ - + @@ -23,8 +23,8 @@ -
Skip to content

DNS

定义

域名解析系统

工作原理 (自下而上)

例如查找 www.baidu.com 的 ip 地址

  1. 查找缓存
      1. 检查浏览器缓存
      1. 检查操作系统缓存 (常见的有 host 文件)
      1. 检查路由器缓存
  2. 如何缓存查找到,会向 ISP (网络服务提供商) 的本地 DNS 服务器查询
  3. 如果本地 DNS 服务器没有找到,会向根域名服务器请求解析,分为以下几步:(自顶向下)
      1. 根服务器返回顶级域名服务器(如.com、.cn、.org等)地址,例如该例子中的 .com 的地址
      1. 接着向顶级瑜域名服务器发送请求,然后会返回次级域名服务器的地址,例如该例子会返回 .baidu 的地址
      1. 接着向次级域名服务器发送请求,会返回通过三级域名地址的 IP,例如本例子返回的 www.baidu.com 的地址
    • 4.Local DNS Server会缓存结果,并返回给用户,缓存在系统中
- +
Skip to content

DNS

定义

域名解析系统

工作原理 (自下而上)

例如查找 www.baidu.com 的 ip 地址

  1. 查找缓存
      1. 检查浏览器缓存
      1. 检查操作系统缓存 (常见的有 host 文件)
      1. 检查路由器缓存
  2. 如何缓存查找到,会向 ISP (网络服务提供商) 的本地 DNS 服务器查询
  3. 如果本地 DNS 服务器没有找到,会向根域名服务器请求解析,分为以下几步:(自顶向下)
      1. 根服务器返回顶级域名服务器(如.com、.cn、.org等)地址,例如该例子中的 .com 的地址
      1. 接着向顶级瑜域名服务器发送请求,然后会返回次级域名服务器的地址,例如该例子会返回 .baidu 的地址
      1. 接着向次级域名服务器发送请求,会返回通过三级域名地址的 IP,例如本例子返回的 www.baidu.com 的地址
    • 4.Local DNS Server会缓存结果,并返回给用户,缓存在系统中
+ \ No newline at end of file diff --git "a/guide/\347\275\221\347\273\234\347\233\270\345\205\263/GET\350\257\267\346\261\202\345\222\214POST\350\257\267\346\261\202\347\232\204\345\214\272\345\210\253.html" "b/guide/\347\275\221\347\273\234\347\233\270\345\205\263/GET\350\257\267\346\261\202\345\222\214POST\350\257\267\346\261\202\347\232\204\345\214\272\345\210\253.html" index d0da2d63..d592602c 100644 --- "a/guide/\347\275\221\347\273\234\347\233\270\345\205\263/GET\350\257\267\346\261\202\345\222\214POST\350\257\267\346\261\202\347\232\204\345\214\272\345\210\253.html" +++ "b/guide/\347\275\221\347\273\234\347\233\270\345\205\263/GET\350\257\267\346\261\202\345\222\214POST\350\257\267\346\261\202\347\232\204\345\214\272\345\210\253.html" @@ -11,7 +11,7 @@ - + @@ -23,8 +23,8 @@ -
Skip to content

GET 请求和 POST 请求的区别

  1. 功能上: GET 请求常用于获取数据,POST 请求常用于提交数据
  2. 参数上: GET 请求参数放在 URL 上,POST 请求参数放在请求体上
  3. 参数类型上: POST 请求支持更多的参数类型
  4. 安全性上: POST 请求更加安全
  5. 是否有缓存上: GET 请求会被缓存
  6. 请求长度上: 由于浏览器存在 URL 长度限制,因此会影响 GET 请求的长度
- +
Skip to content

GET 请求和 POST 请求的区别

  1. 功能上: GET 请求常用于获取数据,POST 请求常用于提交数据
  2. 参数上: GET 请求参数放在 URL 上,POST 请求参数放在请求体上
  3. 参数类型上: POST 请求支持更多的参数类型
  4. 安全性上: POST 请求更加安全
  5. 是否有缓存上: GET 请求会被缓存
  6. 请求长度上: 由于浏览器存在 URL 长度限制,因此会影响 GET 请求的长度
+ \ No newline at end of file diff --git "a/guide/\347\275\221\347\273\234\347\233\270\345\205\263/HTTP.html" "b/guide/\347\275\221\347\273\234\347\233\270\345\205\263/HTTP.html" index a977d93a..8a2b8b0e 100644 --- "a/guide/\347\275\221\347\273\234\347\233\270\345\205\263/HTTP.html" +++ "b/guide/\347\275\221\347\273\234\347\233\270\345\205\263/HTTP.html" @@ -11,7 +11,7 @@ - + @@ -23,8 +23,8 @@ -
Skip to content

HTTP

HTTP 0.9

早期做学术研究使用,只是单纯的文本传输(只有请求行、没有请求头和请求体)

HTTP1.0

支持图片、视频传输,但传输效率太低

核心需求:支持多种类型的文件下载(引入了请求头和响应头)

HTTP1.1

持久连接 keep-alive

在此之前一个 HTTP 请求需要建立一个 TCP 连接

目前浏览器中对于 同一个域名,默认允许同时建立 6 个 TCP 连接

管道化连接

将串行请求改成并行请求

支持虚拟主机

HTTP 根据 Host 去区分同一 IP 物理机子上的不同虚拟主机

对动态生成的内容提供完美支持

Chunk transfer 机制

Cookie、完全机制

主要问题

    1. HTTP/1.1 对头阻塞问题 在 HTTP 中,因为前一条请求因某些原因没有及时返回,会导致后面的请求无法发起,容易导致对头阻塞(串行)。虽然 HTTP1.1 引入了管道化技术尝试解决队头阻塞问题,但服务端还是需要按顺序处理请求并返回,因此阻塞问题依然存在
    1. 带宽利用率不理想
    • 原因:
      • TCP 的慢启动: 传输数据的速度从慢到快
      • 同时开启多个 TCP 连接,那么这些连接会竞争固定的带宽(带宽不足时,TCP 传输速度会变慢)

HTTP/1.0 与 HTTP/1.1 的 区别?

1 连接方面

持久化连接: HTTP1.1 支持持久化连接,减少每次 HTTP 请求都需要建立 TCP 连接的耗时

管道化连接:提高请求效率

2 缓存方面

HTTP1.1 新增了协商缓存的字段 ETag 比 if-None-Match 更加紧准

3 新增 Host 字段

根据 Host 区分同一 IP 服务器上的不同网站

之前只能通过 IP 区分网站

4 请求资源方面

添加范围请求 (206 状态码)

5 新增了请求方法

PUT、HEAD、OPTIONS 等

HTTP/2.0

一个域名只有一个 TCP 长连接传输数据 (避规 HTTP 1.1 的 TCP 慢启动和多个 TCP 连接时竞争带宽资源)

多路复用机制

通过引入二进制分帧层,实现多路复用机制

整体流程整体流程

  1. 浏览器发起请求,经过二进制分帧层将请求拆分成一个个带请求id的帧,发送给服务端
  2. 服务端收到这些帧后,根据请求id组装成完整请求信息,服务端处理完请求后,将响应请求发送到二进制分帧层,经过二进制分帧层转化为一个个带有响应id的帧发送给浏览器
  3. 浏览器收到这些帧后,会组合成一个完整的响应请求

实现基础: HTTP2 是一个二进制协议,在 HTTP/1.1 版中,报文的头信息必须是文本(ASCII 编码),数据体可以是文本,也可以是二进制。HTTP/2 则是一个彻底的二进制协议,头信息和数据体都是二进制,并且统称为"帧",可以分为头信息帧和数据帧。 帧的概念是它实现多路复用的基础

头部压缩

HTTP/2 实现了头信息压缩,由于 HTTP 1.1 协议不带状态,每次请求都必须附上所有信息。所以,请求的很多字段都是重复的,比如 Cookie 和 User Agent ,一模一样的内容,每次请求都必须附带,这会浪费很多带宽,也影响速度。HTTP/2 对这一点做了优化,引入了头信息压缩机制。一方面,头信息使用 gzip 或 compress 压缩后再发送;另一方面,客户端和服务器同时维护一张头信息表,所有字段都会存入这个表,生成一个索引号,以后就不发送同样字段了,只发送索引号,这样就能提高速度了。

设置请求优先级

服务器推送

存在的问题

TCP 协议本身存在的问题:

    1. TCP 的队头阻塞 TCP 传输过程中把一份数据分成多个数据包进行传输,当某个数据包没有按顺序返回,接收端会一直保持连接等待数据包返回,这就阻塞了后续数据包的传输 整体流程
    1. TCP 建立连接需要耗时

优点

多路复用技术能有效利用带宽(只有一个TCP连接),缓解 TCP 慢启动带来的问题,解决了 HTTP 队头阻塞问题,同时还支持设置优先级、服务器推送、头部压缩极大的提高了 HTTP 的传输效率

http2 与 http1 的区别?

  1. 为了解决 HTTP1.1 的队头阻塞问题引入了二进制分帧层
  2. 只建立一个 TCP 连接,解决 HTTP1.1中 TCP 慢启动以及多个 TCP 之间相互竞争带宽问题
  3. 头部压缩,HTTP2 请求头部采用头部压缩,减少数据内容的大小,提高效率
  4. 服务端推送: 服务端可以向客户端推送资源

HTTP3.0

采用UDP + QUIC协议

  1. UDP 可以减少连接耗费的 RTT,加快数据传输
  2. 使用 QUIC 协议,可以使用多路复用、TLS、可靠性传输等 TCP 协议的特点

存在的问题:

  1. 规范的制定和落地有着较大的差异(比如官方的QUIC和谷歌的QUIC协议有较大差异)
  2. 是对底层协议的改造,落地成本高。

HTTP1.0/1.1/2.0有什么区别?

这道题应该从HTTP的发展历史的角度出发

  1. http1.0 在 http0.9 时代新增了图片、视频的传输,同时新增了请求、响应头,支持文件下载,但请求的效率低,因为每个http请求需要一次TCP连接
  2. HTTP1.1 引入了缓存策略、支持长连接keep-alive等,支持PUT/DELETE/OPTION方法,提高了HTTP的传输效率,但并发请求时会有一个HTTP的头部阻塞问题
  3. HTTP2 通过引入二进制分帧层、采用多路复用避规了HTTP的头部阻塞问题,还支持头部压缩,提高HTTP的传输效率,服务端推送

RTT

浏览器发送数据包到服务器 + 浏览器接收到服务器确认接收的数据包的往返时间,成为RTT

- +
Skip to content

HTTP

HTTP 0.9

早期做学术研究使用,只是单纯的文本传输(只有请求行、没有请求头和请求体)

HTTP1.0

支持图片、视频传输,但传输效率太低

核心需求:支持多种类型的文件下载(引入了请求头和响应头)

HTTP1.1

持久连接 keep-alive

在此之前一个 HTTP 请求需要建立一个 TCP 连接

目前浏览器中对于 同一个域名,默认允许同时建立 6 个 TCP 连接

管道化连接

将串行请求改成并行请求

支持虚拟主机

HTTP 根据 Host 去区分同一 IP 物理机子上的不同虚拟主机

对动态生成的内容提供完美支持

Chunk transfer 机制

Cookie、完全机制

主要问题

    1. HTTP/1.1 对头阻塞问题 在 HTTP 中,因为前一条请求因某些原因没有及时返回,会导致后面的请求无法发起,容易导致对头阻塞(串行)。虽然 HTTP1.1 引入了管道化技术尝试解决队头阻塞问题,但服务端还是需要按顺序处理请求并返回,因此阻塞问题依然存在
    1. 带宽利用率不理想
    • 原因:
      • TCP 的慢启动: 传输数据的速度从慢到快
      • 同时开启多个 TCP 连接,那么这些连接会竞争固定的带宽(带宽不足时,TCP 传输速度会变慢)

HTTP/1.0 与 HTTP/1.1 的 区别?

1 连接方面

持久化连接: HTTP1.1 支持持久化连接,减少每次 HTTP 请求都需要建立 TCP 连接的耗时

管道化连接:提高请求效率

2 缓存方面

HTTP1.1 新增了协商缓存的字段 ETag 比 if-None-Match 更加紧准

3 新增 Host 字段

根据 Host 区分同一 IP 服务器上的不同网站

之前只能通过 IP 区分网站

4 请求资源方面

添加范围请求 (206 状态码)

5 新增了请求方法

PUT、HEAD、OPTIONS 等

HTTP/2.0

一个域名只有一个 TCP 长连接传输数据 (避规 HTTP 1.1 的 TCP 慢启动和多个 TCP 连接时竞争带宽资源)

多路复用机制

通过引入二进制分帧层,实现多路复用机制

整体流程整体流程

  1. 浏览器发起请求,经过二进制分帧层将请求拆分成一个个带请求id的帧,发送给服务端
  2. 服务端收到这些帧后,根据请求id组装成完整请求信息,服务端处理完请求后,将响应请求发送到二进制分帧层,经过二进制分帧层转化为一个个带有响应id的帧发送给浏览器
  3. 浏览器收到这些帧后,会组合成一个完整的响应请求

实现基础: HTTP2 是一个二进制协议,在 HTTP/1.1 版中,报文的头信息必须是文本(ASCII 编码),数据体可以是文本,也可以是二进制。HTTP/2 则是一个彻底的二进制协议,头信息和数据体都是二进制,并且统称为"帧",可以分为头信息帧和数据帧。 帧的概念是它实现多路复用的基础

头部压缩

HTTP/2 实现了头信息压缩,由于 HTTP 1.1 协议不带状态,每次请求都必须附上所有信息。所以,请求的很多字段都是重复的,比如 Cookie 和 User Agent ,一模一样的内容,每次请求都必须附带,这会浪费很多带宽,也影响速度。HTTP/2 对这一点做了优化,引入了头信息压缩机制。一方面,头信息使用 gzip 或 compress 压缩后再发送;另一方面,客户端和服务器同时维护一张头信息表,所有字段都会存入这个表,生成一个索引号,以后就不发送同样字段了,只发送索引号,这样就能提高速度了。

设置请求优先级

服务器推送

存在的问题

TCP 协议本身存在的问题:

    1. TCP 的队头阻塞 TCP 传输过程中把一份数据分成多个数据包进行传输,当某个数据包没有按顺序返回,接收端会一直保持连接等待数据包返回,这就阻塞了后续数据包的传输 整体流程
    1. TCP 建立连接需要耗时

优点

多路复用技术能有效利用带宽(只有一个TCP连接),缓解 TCP 慢启动带来的问题,解决了 HTTP 队头阻塞问题,同时还支持设置优先级、服务器推送、头部压缩极大的提高了 HTTP 的传输效率

http2 与 http1 的区别?

  1. 为了解决 HTTP1.1 的队头阻塞问题引入了二进制分帧层
  2. 只建立一个 TCP 连接,解决 HTTP1.1中 TCP 慢启动以及多个 TCP 之间相互竞争带宽问题
  3. 头部压缩,HTTP2 请求头部采用头部压缩,减少数据内容的大小,提高效率
  4. 服务端推送: 服务端可以向客户端推送资源

HTTP3.0

采用UDP + QUIC协议

  1. UDP 可以减少连接耗费的 RTT,加快数据传输
  2. 使用 QUIC 协议,可以使用多路复用、TLS、可靠性传输等 TCP 协议的特点

存在的问题:

  1. 规范的制定和落地有着较大的差异(比如官方的QUIC和谷歌的QUIC协议有较大差异)
  2. 是对底层协议的改造,落地成本高。

HTTP1.0/1.1/2.0有什么区别?

这道题应该从HTTP的发展历史的角度出发

  1. http1.0 在 http0.9 时代新增了图片、视频的传输,同时新增了请求、响应头,支持文件下载,但请求的效率低,因为每个http请求需要一次TCP连接
  2. HTTP1.1 引入了缓存策略、支持长连接keep-alive等,支持PUT/DELETE/OPTION方法,提高了HTTP的传输效率,但并发请求时会有一个HTTP的头部阻塞问题
  3. HTTP2 通过引入二进制分帧层、采用多路复用避规了HTTP的头部阻塞问题,还支持头部压缩,提高HTTP的传输效率,服务端推送

RTT

浏览器发送数据包到服务器 + 浏览器接收到服务器确认接收的数据包的往返时间,成为RTT

+ \ No newline at end of file diff --git "a/guide/\347\275\221\347\273\234\347\233\270\345\205\263/HTTPS.html" "b/guide/\347\275\221\347\273\234\347\233\270\345\205\263/HTTPS.html" index 896e995a..dc9e0fa1 100644 --- "a/guide/\347\275\221\347\273\234\347\233\270\345\205\263/HTTPS.html" +++ "b/guide/\347\275\221\347\273\234\347\233\270\345\205\263/HTTPS.html" @@ -11,7 +11,7 @@ - + @@ -23,8 +23,8 @@ -
Skip to content

HTTPS

HTTP 和 HTTPS 的区别

  1. HTTP 是超文本传输协议,明文传输、简单、无状态,而 HTTPS 是在 HTTP 基础上增加了 SSL 协议,更加安全
  2. HTTP 协议默认端口是 80,HTTPS 协议默认端口是 443
  3. HTTPS 需要 CA 证书、相对于 HTTP 费用更高

HTTPS 演进过程

第一版对称加密 - 不安全

流程

非对称加密 - 传输效率低

流程

对称加密与非对称加密结合 - 存在中间人攻击

流程

通过数字证书校验网站的真实性和获取网站的公钥

之前传输的是密钥,这种方式传输的是装有密钥的保险箱,就算获取到了保险箱,也没有保险箱的钥匙🔑

流程

  1. 浏览器将对称加密方法列表、非对称加密方法列表、随机数 A 传输给服务端
  2. 服务器接受后,将对称加密、非对称加密方法、服务器生成的随机数 B 、数字证书发送给浏览器
  3. 浏览器接受后,验证证书的可靠性,并获取证书内的非对称加密的公钥
  4. 浏览器通过 2 个随机数生成新的随机数 C,并通过非对成加密的公钥对随机数 C 进行加密发送给服务器
  5. 服务器确认后,服务器与浏览器通过 3 个随机数生成对称加密密钥,进行数据传输

如何验证证书的可靠性

  1. 浏览器获取到证书后,通过 CA 相同的 Hash 算法对证书信息进行加密得到摘要 A
  2. 通过 CA 的公钥对证书内的数字签名进行解密,获取到摘要 B
  3. 如果 AB 相同,则证书可靠

什么是 HTTPS 中间人攻击?如何预防?

  1. 先说下 HTTPS 传输过程
  2. 客户端和服务端通信之间,新增一个中间人,伪造 CA 证书和加密数据,获取服务器和客户端的通信信息

流程

如何预防?

使用正规厂商的第三方证书

- +
Skip to content

HTTPS

HTTP 和 HTTPS 的区别

  1. HTTP 是超文本传输协议,明文传输、简单、无状态,而 HTTPS 是在 HTTP 基础上增加了 SSL 协议,更加安全
  2. HTTP 协议默认端口是 80,HTTPS 协议默认端口是 443
  3. HTTPS 需要 CA 证书、相对于 HTTP 费用更高

HTTPS 演进过程

第一版对称加密 - 不安全

流程

非对称加密 - 传输效率低

流程

对称加密与非对称加密结合 - 存在中间人攻击

流程

通过数字证书校验网站的真实性和获取网站的公钥

之前传输的是密钥,这种方式传输的是装有密钥的保险箱,就算获取到了保险箱,也没有保险箱的钥匙🔑

流程

  1. 浏览器将对称加密方法列表、非对称加密方法列表、随机数 A 传输给服务端
  2. 服务器接受后,将对称加密、非对称加密方法、服务器生成的随机数 B 、数字证书发送给浏览器
  3. 浏览器接受后,验证证书的可靠性,并获取证书内的非对称加密的公钥
  4. 浏览器通过 2 个随机数生成新的随机数 C,并通过非对成加密的公钥对随机数 C 进行加密发送给服务器
  5. 服务器确认后,服务器与浏览器通过 3 个随机数生成对称加密密钥,进行数据传输

如何验证证书的可靠性

  1. 浏览器获取到证书后,通过 CA 相同的 Hash 算法对证书信息进行加密得到摘要 A
  2. 通过 CA 的公钥对证书内的数字签名进行解密,获取到摘要 B
  3. 如果 AB 相同,则证书可靠

什么是 HTTPS 中间人攻击?如何预防?

  1. 先说下 HTTPS 传输过程
  2. 客户端和服务端通信之间,新增一个中间人,伪造 CA 证书和加密数据,获取服务器和客户端的通信信息

流程

如何预防?

使用正规厂商的第三方证书

+ \ No newline at end of file diff --git "a/guide/\347\275\221\347\273\234\347\233\270\345\205\263/\345\223\215\345\272\224\346\212\245\346\226\207.html" "b/guide/\347\275\221\347\273\234\347\233\270\345\205\263/\345\223\215\345\272\224\346\212\245\346\226\207.html" index 7b2c80a4..dc07705e 100644 --- "a/guide/\347\275\221\347\273\234\347\233\270\345\205\263/\345\223\215\345\272\224\346\212\245\346\226\207.html" +++ "b/guide/\347\275\221\347\273\234\347\233\270\345\205\263/\345\223\215\345\272\224\346\212\245\346\226\207.html" @@ -11,7 +11,7 @@ - + @@ -23,8 +23,8 @@ -
Skip to content

响应报文

由响应行、响应头、响应体组成

响应行

由版本、状态码、原因语句组成

状态码

  • 1xx: 请求已被接受,需要继续处理

  • 2xx: 请求已成功处理

    • 200 请求正常处理、命中强缓存
    • 204 请求处理成功,但没有资源返回
    • 206 客户端进行了范围请求,服务端成功执行了这部分 GET 请求
  • 3xx:客户端需要采取进一步操作才能完成

    • 301 永久重定向
    • 302 临时重定向
    • 304 命中协商缓存
  • 4xx: 客户端错误

    • 400 请求存在语法错误
    • 401 用户登录权限不通过
    • 403 用户登录了,但操作权限不通过
    • 404 资源不存在
    • 405 请求行中制定的方法不能被用于请求相应的资源
  • 5xx: 服务端错误

    • 500 服务端报错
    • 504 服务/网关超时

流程

响应头

响应内容相关

  • content-type 内容类型 Content-Type: text/plain;charset=UTF-8
    • 常见的有:
      • application/x-www-form-urlencoded: 浏览器的原生 form 表单,如果不设置 enctype 属性,那么最终就会以 application/x-www-form-urlencoded 方式提交数据。该种方式提交的数据放在 body 里面,数据按照 key1=val1&key2=val2 的方式进行编码,key 和 val 都进行了 URL转码
      • application/json: 服务器消息主体是序列化后的 JSON 字符串
      • multipart/form-data: 该种方式也是一个常见的 POST 提交方式,通常表单上传文件时使用该种方式。
  • content-length 内容长度

缓存相关

  • Cache-Control
  • Last-Modified
  • ETag

客户端相关

  • Set-Cookie: isGray=true;

跨域相关

  • 简单请求

    • Access-Control-Allow-Origin
  • 非简单请求

    • Access-Control-Allow-Methods
    • Access-Control-Allow-Headers
    • Access-Control-Max-Age
  • Cookie 相关

    • Access-Control-Allow-Credentials: true;

时间相关

Date: Mon, 21 Mar 2022 03:36:53 GMT

响应体

- +
Skip to content

响应报文

由响应行、响应头、响应体组成

响应行

由版本、状态码、原因语句组成

状态码

  • 1xx: 请求已被接受,需要继续处理

  • 2xx: 请求已成功处理

    • 200 请求正常处理、命中强缓存
    • 204 请求处理成功,但没有资源返回
    • 206 客户端进行了范围请求,服务端成功执行了这部分 GET 请求
  • 3xx:客户端需要采取进一步操作才能完成

    • 301 永久重定向
    • 302 临时重定向
    • 304 命中协商缓存
  • 4xx: 客户端错误

    • 400 请求存在语法错误
    • 401 用户登录权限不通过
    • 403 用户登录了,但操作权限不通过
    • 404 资源不存在
    • 405 请求行中制定的方法不能被用于请求相应的资源
  • 5xx: 服务端错误

    • 500 服务端报错
    • 504 服务/网关超时

流程

响应头

响应内容相关

  • content-type 内容类型 Content-Type: text/plain;charset=UTF-8
    • 常见的有:
      • application/x-www-form-urlencoded: 浏览器的原生 form 表单,如果不设置 enctype 属性,那么最终就会以 application/x-www-form-urlencoded 方式提交数据。该种方式提交的数据放在 body 里面,数据按照 key1=val1&key2=val2 的方式进行编码,key 和 val 都进行了 URL转码
      • application/json: 服务器消息主体是序列化后的 JSON 字符串
      • multipart/form-data: 该种方式也是一个常见的 POST 提交方式,通常表单上传文件时使用该种方式。
  • content-length 内容长度

缓存相关

  • Cache-Control
  • Last-Modified
  • ETag

客户端相关

  • Set-Cookie: isGray=true;

跨域相关

  • 简单请求

    • Access-Control-Allow-Origin
  • 非简单请求

    • Access-Control-Allow-Methods
    • Access-Control-Allow-Headers
    • Access-Control-Max-Age
  • Cookie 相关

    • Access-Control-Allow-Credentials: true;

时间相关

Date: Mon, 21 Mar 2022 03:36:53 GMT

响应体

+ \ No newline at end of file diff --git "a/guide/\347\275\221\347\273\234\347\233\270\345\205\263/\345\270\270\350\247\201\347\232\204\351\227\256\351\242\230.html" "b/guide/\347\275\221\347\273\234\347\233\270\345\205\263/\345\270\270\350\247\201\347\232\204\351\227\256\351\242\230.html" index e3def7b9..fcbdfcb6 100644 --- "a/guide/\347\275\221\347\273\234\347\233\270\345\205\263/\345\270\270\350\247\201\347\232\204\351\227\256\351\242\230.html" +++ "b/guide/\347\275\221\347\273\234\347\233\270\345\205\263/\345\270\270\350\247\201\347\232\204\351\227\256\351\242\230.html" @@ -11,7 +11,7 @@ - + @@ -23,8 +23,8 @@ -
Skip to content
- +
Skip to content
+ \ No newline at end of file diff --git "a/guide/\347\275\221\347\273\234\347\233\270\345\205\263/\346\246\202\350\246\201.html" "b/guide/\347\275\221\347\273\234\347\233\270\345\205\263/\346\246\202\350\246\201.html" index 4f3c0e8e..68913712 100644 --- "a/guide/\347\275\221\347\273\234\347\233\270\345\205\263/\346\246\202\350\246\201.html" +++ "b/guide/\347\275\221\347\273\234\347\233\270\345\205\263/\346\246\202\350\246\201.html" @@ -12,7 +12,7 @@ - + @@ -24,8 +24,8 @@ -
Skip to content
- +
Skip to content
+ \ No newline at end of file diff --git "a/guide/\347\275\221\347\273\234\347\233\270\345\205\263/\350\257\267\346\261\202\346\212\245\346\226\207.html" "b/guide/\347\275\221\347\273\234\347\233\270\345\205\263/\350\257\267\346\261\202\346\212\245\346\226\207.html" index 3ff53d4c..6b1bb34a 100644 --- "a/guide/\347\275\221\347\273\234\347\233\270\345\205\263/\350\257\267\346\261\202\346\212\245\346\226\207.html" +++ "b/guide/\347\275\221\347\273\234\347\233\270\345\205\263/\350\257\267\346\261\202\346\212\245\346\226\207.html" @@ -11,7 +11,7 @@ - + @@ -23,8 +23,8 @@ -
Skip to content

请求报文

由请求行、请求头、请求体组成

请求行

由请求方法、URI、协议版本组成

流程

请求方法

  1. GET 请求获取资源
  2. POST 提交数据
  3. PUT 更新资源
  4. DELETE 删除资源
  5. OPTIONS 查询针对请求 URL 指定的资源支持的方法(常用在非简单请求的预检上)
  6. HEAD 获取响应头
  7. CONNECT 要求用隧道协议链接代理
  8. TRACE 追踪请求经过的路径

URI 字段

协议版本

HTTP0.9、 HTTP1.0、HTTP1.1、HTTP2.0、HTTP3.0

请求头

接受内容相关

  1. Accept 浏览器接受的格式 Accept: application/json, text/plain, /
  2. Accept-Encoding 浏览器接受的压缩格式 Accept-Encoding: gzip, deflate, br
  3. Accept-Language 浏览器接受的语言 Accept-Language: zh-CN
  4. Accept-Charset 浏览器接受的字符集

强缓存相关

  1. Cache-Control

协商缓存相关

  1. If-Modified-Since 上一次访问时文件的更改时间 (存在校验问题,比如文件内容只是添加了空格,但是 Last-Modified 改变了)
  2. If-None-Match 上次访问的 ETag 信息 (如果 If-None-Match 和 ETag 一致,则命中 304 协商缓存)

请求域名相关

  1. HOST HTTP 请求的域名
  2. Origin 页面域名 (常用于防止 CSRF 攻击和跨域请求)
  3. Referer 发出请求的页面 URL

客户端相关

  • UA
  • COOKIE

连接相关

  • Connection Connection: keep-alive

流程

请求体

- +
Skip to content

请求报文

由请求行、请求头、请求体组成

请求行

由请求方法、URI、协议版本组成

流程

请求方法

  1. GET 请求获取资源
  2. POST 提交数据
  3. PUT 更新资源
  4. DELETE 删除资源
  5. OPTIONS 查询针对请求 URL 指定的资源支持的方法(常用在非简单请求的预检上)
  6. HEAD 获取响应头
  7. CONNECT 要求用隧道协议链接代理
  8. TRACE 追踪请求经过的路径

URI 字段

协议版本

HTTP0.9、 HTTP1.0、HTTP1.1、HTTP2.0、HTTP3.0

请求头

接受内容相关

  1. Accept 浏览器接受的格式 Accept: application/json, text/plain, /
  2. Accept-Encoding 浏览器接受的压缩格式 Accept-Encoding: gzip, deflate, br
  3. Accept-Language 浏览器接受的语言 Accept-Language: zh-CN
  4. Accept-Charset 浏览器接受的字符集

强缓存相关

  1. Cache-Control

协商缓存相关

  1. If-Modified-Since 上一次访问时文件的更改时间 (存在校验问题,比如文件内容只是添加了空格,但是 Last-Modified 改变了)
  2. If-None-Match 上次访问的 ETag 信息 (如果 If-None-Match 和 ETag 一致,则命中 304 协商缓存)

请求域名相关

  1. HOST HTTP 请求的域名
  2. Origin 页面域名 (常用于防止 CSRF 攻击和跨域请求)
  3. Referer 发出请求的页面 URL

客户端相关

  • UA
  • COOKIE

连接相关

  • Connection Connection: keep-alive

流程

请求体

+ \ No newline at end of file diff --git "a/guide/\347\275\221\347\273\234\347\233\270\345\205\263/\350\267\250\345\237\237\350\257\267\346\261\202.html" "b/guide/\347\275\221\347\273\234\347\233\270\345\205\263/\350\267\250\345\237\237\350\257\267\346\261\202.html" index 6ba37ff3..ea85a364 100644 --- "a/guide/\347\275\221\347\273\234\347\233\270\345\205\263/\350\267\250\345\237\237\350\257\267\346\261\202.html" +++ "b/guide/\347\275\221\347\273\234\347\233\270\345\205\263/\350\267\250\345\237\237\350\257\267\346\261\202.html" @@ -11,7 +11,7 @@ - + @@ -23,8 +23,8 @@ -
Skip to content

跨域请求

简单请求

若请求满足所有下述条件,则该请求可视为简单请求:

  1. HEAD/GET/POST 请求
  2. Content-Type: text/plain、multipart/form-data、application/x-www-form-urlencoded
  3. 除了被用户代理自动设置的标头字段,剩下的请求头是: Accept、Accept-Language、Content-Language、Content-Type、Range

请求过程

  1. 发起请求,请求头会带上 Origin 字段,该字段用来说明请求来自哪个源(协议 + 域名 + 端口),服务器根据这个值决定是否同意这次请求
  2. 当服务器接收到请求后,根据 Origin 判断是否在允许的范围内
  3. 如果不在范围内,服务器会返回一个正常的 HTTP 响应,浏览器发现响应头信息没有 Access-Control-Allow-Origin 字段,就知道出错了,从而抛出错误,被 XML 的 onerror 回调函数捕获。(注意:由于正常响应,其状态码为200,因此该错误不能通过状态码识别)
  4. 如果 Origin 指定的域名在范围内,服务器返回的响应会多出几个头信息字段(Access-Control-Allow-Origin、Access-Control-Allow-Credentials、Access-Control-Expose-Header 等)

流程

非简单请求

请求方法是 PUT、DELETE 或者 Content-Type 是 application/json 类型

请求过程 (源、请求头、方法、缓存、Cookie)

  1. 浏览器发起 Option 预检请求
  2. 服务器收到预检请求以后,检查了 Origin、Access-Control-Request-Method 和 Access-Control-Request-Headers 字段后,确认允许跨域请求,就可以做出回应
    • Origin (必须): 发起请求的源信息
    • Access-Control-Request-Method(必须): 用来列出浏览器的 CORS 请求会用到哪些 HTTP 方法
    • Access-Control-Request-Headers 跨域请求而外的请求头字段
  3. 如果服务器预检请求,会返回一个正常的 HTTP 回应,但没有任何的 CORS 相关的头信息字段,这时浏览器就会认定服务器不同意预检请求,触发错误。
  4. 如果服务器通过了预检请求,以后每次浏览器正常的 CORS 请求就跟简单请求一样
    • Access-Control-Allow-Origin(必须): 运行哪些源跨域,如果是 * 无法携带 Cookie
    • Access-Control-Allow-Method(必须): 服务器支持哪些请求
    • Access-Control-Allow-Header: 服务器支持的头信息字段
    • Access-Control-Max-Age: 预检请求的有效期,单位秒

流程

  1. 响应头设置 Access-Control-Allow-Credentials 等于 true
  2. Access-Control-Allow-Origin 不能设置成 * (Cookie 的 SameSite 属性如果是 Lax 可能也会导致带不上去)
  3. 前端设置 withCredentials: true

常见的问题

cookie 一般用于登录验证,存储用户信息,大小为 4KB,会随着网络请求携带给服务端

session 一般存储在服务端,常用于与 Cookie 配合做登录检验

  • cookie 是 HTTP 的内容,token 是自定义的数据
  • cookie 可以默认存储在浏览器中,token 需要自行存储
  • token 没有跨域限制,cookie 存在跨域限制
  • token 常用于 CSRF 或者 JWT(JSON WEB TOKEN)
  • Cookie 常于 Session 配合,做用户登录鉴权
  • 基本属性:

    • name
    • value
  • 访问性:

    • expire
    • path
    • domain
  • 安全性:

    • secure
    • httpOnly
    • sameSite

Session 和 JWT 哪个更合适?

  • Session

    • 优点:
      1. 易于学习
      2. 用户信息存储在服务器,可以快速封禁某个用户
    • 缺点:
      1. 占用服务器资源,硬件成本高
      2. 多进程、多服务器时,不好同步 (需要第三方缓存, Redis)
      3. Session 需要配合 Cookie 使用,cookie 有域名限制
  • Json Web Token

    • 优点:
      1. 存储在客户端,不占用服务端资源
      2. 易于同步
      3. 没有跨域限制
    • 缺点:
      1. 无法快速封禁用户
      2. Token 不安全,一但秘钥被泄漏,容易窃取用户信息
      3. Token很大,影响请求体积
  • 使用场景:

    • 用户信息安全 -> 使用 Session
    • 没有特殊要求 -> 使用 JWT

如何实现 SSO 单点登录

Cookie 默认跨域不共享

可以通过设置 Cookie 的 domain 为相同的主域名,即可共享 Cookie

比如 www.baidu.com、image.baidu.com 主域名是相同的,设置 cookie domain 为主域名,即可共享 cookie

流程

如果主域名不一致

  1. 使用 SSO 第三方登录, 获取 ticket 返回给 A、B 系统

流程

  1. OAuth2.0

第三方登录(例如微信扫码登录)

流程

- +
Skip to content

跨域请求

简单请求

若请求满足所有下述条件,则该请求可视为简单请求:

  1. HEAD/GET/POST 请求
  2. Content-Type: text/plain、multipart/form-data、application/x-www-form-urlencoded
  3. 除了被用户代理自动设置的标头字段,剩下的请求头是: Accept、Accept-Language、Content-Language、Content-Type、Range

请求过程

  1. 发起请求,请求头会带上 Origin 字段,该字段用来说明请求来自哪个源(协议 + 域名 + 端口),服务器根据这个值决定是否同意这次请求
  2. 当服务器接收到请求后,根据 Origin 判断是否在允许的范围内
  3. 如果不在范围内,服务器会返回一个正常的 HTTP 响应,浏览器发现响应头信息没有 Access-Control-Allow-Origin 字段,就知道出错了,从而抛出错误,被 XML 的 onerror 回调函数捕获。(注意:由于正常响应,其状态码为200,因此该错误不能通过状态码识别)
  4. 如果 Origin 指定的域名在范围内,服务器返回的响应会多出几个头信息字段(Access-Control-Allow-Origin、Access-Control-Allow-Credentials、Access-Control-Expose-Header 等)

流程

非简单请求

请求方法是 PUT、DELETE 或者 Content-Type 是 application/json 类型

请求过程 (源、请求头、方法、缓存、Cookie)

  1. 浏览器发起 Option 预检请求
  2. 服务器收到预检请求以后,检查了 Origin、Access-Control-Request-Method 和 Access-Control-Request-Headers 字段后,确认允许跨域请求,就可以做出回应
    • Origin (必须): 发起请求的源信息
    • Access-Control-Request-Method(必须): 用来列出浏览器的 CORS 请求会用到哪些 HTTP 方法
    • Access-Control-Request-Headers 跨域请求而外的请求头字段
  3. 如果服务器预检请求,会返回一个正常的 HTTP 回应,但没有任何的 CORS 相关的头信息字段,这时浏览器就会认定服务器不同意预检请求,触发错误。
  4. 如果服务器通过了预检请求,以后每次浏览器正常的 CORS 请求就跟简单请求一样
    • Access-Control-Allow-Origin(必须): 运行哪些源跨域,如果是 * 无法携带 Cookie
    • Access-Control-Allow-Method(必须): 服务器支持哪些请求
    • Access-Control-Allow-Header: 服务器支持的头信息字段
    • Access-Control-Max-Age: 预检请求的有效期,单位秒

流程

  1. 响应头设置 Access-Control-Allow-Credentials 等于 true
  2. Access-Control-Allow-Origin 不能设置成 * (Cookie 的 SameSite 属性如果是 Lax 可能也会导致带不上去)
  3. 前端设置 withCredentials: true

常见的问题

cookie 一般用于登录验证,存储用户信息,大小为 4KB,会随着网络请求携带给服务端

session 一般存储在服务端,常用于与 Cookie 配合做登录检验

  • cookie 是 HTTP 的内容,token 是自定义的数据
  • cookie 可以默认存储在浏览器中,token 需要自行存储
  • token 没有跨域限制,cookie 存在跨域限制
  • token 常用于 CSRF 或者 JWT(JSON WEB TOKEN)
  • Cookie 常于 Session 配合,做用户登录鉴权
  • 基本属性:

    • name
    • value
  • 访问性:

    • expire
    • path
    • domain
  • 安全性:

    • secure
    • httpOnly
    • sameSite

Session 和 JWT 哪个更合适?

  • Session

    • 优点:
      1. 易于学习
      2. 用户信息存储在服务器,可以快速封禁某个用户
    • 缺点:
      1. 占用服务器资源,硬件成本高
      2. 多进程、多服务器时,不好同步 (需要第三方缓存, Redis)
      3. Session 需要配合 Cookie 使用,cookie 有域名限制
  • Json Web Token

    • 优点:
      1. 存储在客户端,不占用服务端资源
      2. 易于同步
      3. 没有跨域限制
    • 缺点:
      1. 无法快速封禁用户
      2. Token 不安全,一但秘钥被泄漏,容易窃取用户信息
      3. Token很大,影响请求体积
  • 使用场景:

    • 用户信息安全 -> 使用 Session
    • 没有特殊要求 -> 使用 JWT

如何实现 SSO 单点登录

Cookie 默认跨域不共享

可以通过设置 Cookie 的 domain 为相同的主域名,即可共享 Cookie

比如 www.baidu.com、image.baidu.com 主域名是相同的,设置 cookie domain 为主域名,即可共享 cookie

流程

如果主域名不一致

  1. 使用 SSO 第三方登录, 获取 ticket 返回给 A、B 系统

流程

  1. OAuth2.0

第三方登录(例如微信扫码登录)

流程

+ \ No newline at end of file diff --git a/hashmap.json b/hashmap.json index 54740bbf..78771837 100644 --- a/hashmap.json +++ b/hashmap.json @@ -1 +1 @@ -{"guide_node相关_概要.md":"c177becf","guide_canvas_如何在canvas画板上自由书写.md":"3d7cf139","guide_react_react与vue的区别.md":"ee1c50b9","guide_react_react中的异常机制.md":"4e0a6832","guide_react_setstate是同步还是异步的.md":"6d744533","guide_react_react异常机制.md":"8d2560d6","guide_ai_rag之加载数据.md":"7787c157","guide_css相关_隐藏元素的方法.md":"5d09b97a","guide_css相关_对 line-height 的理解及其赋值方式.md":"ed9187dc","guide_css相关_概要.md":"caec95d5","guide_css相关_position.md":"066644ce","guide_react_react中的性能优化.md":"a8328e29","guide_javascript相关_index.md":"acb75e78","guide_react_react是如何渲染的.md":"4ea938c9","guide_ai_什么是langchain.md":"331802ff","guide_ai_构建可复用的prompttemplate.md":"ab8f853f","index.md":"7f4fdd92","guide_网络相关_常见的问题.md":"c84a65b7","shoot_实战技巧_暗调人像.md":"ff643be2","guide_javascript相关_javascript执行机制.md":"3cb02e76","guide_网络相关_请求报文.md":"0ba8148e","guide_ai_retriever 常见的优化方式.md":"77046314","guide_ai_rag之拆分数据.md":"c7dc2891","guide_javascript相关_dom相关.md":"14095a02","guide_webpack_模块联邦.md":"55fd1b70","guide_javascript相关_es6相关.md":"349f4c13","guide_javascript相关_javascript编译机制.md":"9d2ae649","guide_网络相关_https.md":"6d2b716a","guide_javascript相关_垃圾回收机制.md":"0fcbd9c4","guide_javascript相关_promise.md":"5354a1f7","guide_javascript相关_对象常见的api.md":"1305a407","guide_javascript相关_继承相关.md":"00da001d","guide_webpack_mini-webpack.md":"f3f154f9","guide_javascript相关_事件循环机制.md":"075e7fe9","guide_javascript相关_基础概念.md":"dc3d2e30","guide_webpack_loader.md":"65e3268d","guide_canvas_通过上下分层优化canvas书写性能.md":"94e516ad","guide_css相关_display、float、position的关系.md":"7a72077f","guide_css相关_display、visibility、opacity区别.md":"4c0532c6","guide_javascript相关_定义.md":"ef2262a8","guide_浏览器相关_浏览器进程架构.md":"3c2952bb","guide_浏览器相关_浏览器缓存.md":"6792cab4","guide_网络相关_cdn.md":"17c0b1ee","guide_网络相关_dns.md":"a848b96e","guide_网络相关_概要.md":"39eb6321","guide_网络相关_http.md":"272df02e","guide_网络相关_响应报文.md":"4e44105b","guide_canvas_通过 offscreencanvas _ worker 提高书写性能.md":"61b3946b","guide_react_react中的事件机制.md":"58783f25","shoot_实战技巧_亮调人像.md":"bfb2f833","shoot_实战技巧_冷暖对比人像.md":"9a713713","guide_网络相关_get请求和post请求的区别.md":"7fb12d4a","guide_浏览器相关_概要.md":"4c97d5fd","guide_浏览器相关_浏览器内核.md":"a4aefbe3","guide_浏览器相关_浏览器安全.md":"25196afe","guide_css相关_bfc.md":"52abcc52","guide_javascript相关_数组常见的api.md":"bbc62074","guide_浏览器相关_浏览器渲染流程.md":"144e6f8e","shoot_实战技巧_index.md":"cc1925d6","guide_canvas_可视区域内渲染提高canvas书写性能.md":"2bec03da","guide_ddd 领域驱动设计_index.md":"a954ac27","guide_javascript相关_新的运算符.md":"254d85e1","guide_canvas_canvas尺寸及分辨率矫正.md":"47adbdaf","shoot_实战技巧_逆光人像.md":"294aa0a7","guide_webpack_index.md":"db3bb590","guide_ai_rag之embeding.md":"9d57501d","shoot_实战技巧_拍摄梦幻光斑.md":"53b8014d","guide_fabric.js_如何调试fabric.md":"c1b3d722","guide_ai_langchain快速入门.md":"6e950c2e","shoot_自我实战总结_拍摄月亮.md":"fc1809ae","shoot_实战技巧_如何拍雨丝.md":"3892fb19","shoot_实战技巧_如何拍花的黑背景.md":"4e78f8b6","guide_react_react为什么要使用jsx.md":"46e1a94d","guide_webpack_构建流程.md":"18bf89d5","guide_javascript相关_正则表达式.md":"9d16e29a","shoot_构图形式_构图技巧.md":"d90509e0","guide_ai_rag 检索增强生成的流程.md":"a339dabc","guide_canvas_通过离屏渲染提高canvas书写性能.md":"95d73a61","guide_react_react组件是如何通信的.md":"05b07664","guide_css相关_display.md":"7b78972d","shoot_自我实战总结_延迟摄影.md":"46ca809f","shoot_基础概念_光圈.md":"ff2db10b","guide_网络相关_跨域请求.md":"d18aad93","guide_react_diff算法.md":"e6203201","guide_react_react是什么.md":"2a94b3c2","guide_webpack_热更新原理.md":"081bcae8","guide_react_常见的问题.md":"0a97b65b","guide_redux_设计理念.md":"53d3413a","guide_redux_源码解读.md":"a16d34cb","guide_react_什么是fiber.md":"ff48a654","guide_ai_rag之向量数据库.md":"6db527a5","guide_javascript相关_数据类型.md":"bf71558a","shoot_基础概念_快门速度.md":"1a25ab06","guide_javascript相关_字符串常见的api.md":"43fdbea0","guide_ai_outputparser构建格式化输出.md":"ace64382","shoot_自我实战总结_拍摄烟花.md":"fb21693e","shoot_基础概念_iso感光度.md":"9142d6ab","guide_react_如何设计react组件.md":"b55050d7","shoot_自我实战总结_拍摄星空.md":"2de1cbd8","guide_canvas_通过贝塞尔曲线优化canvas书写性能.md":"158a433c","guide_javascript相关_js异常捕获机制.md":"7fd96143"} +{"guide_react_react组件是如何通信的.md":"3b62799c","guide_react_diff算法.md":"0ae563f7","guide_fabric.js_如何调试fabric.md":"6b7c3634","guide_react_react与vue的区别.md":"672b0c8e","guide_react_react是什么.md":"d60b5e2d","guide_react_什么是fiber.md":"c7d34c1a","guide_ai_embedding之拆分数据.md":"dce10d49","guide_ai_构建可复用的prompttemplate.md":"ba95d8c7","guide_react_react异常机制.md":"c399b96d","guide_canvas_canvas尺寸及分辨率矫正.md":"be47a824","guide_redux_源码解读.md":"25f8a90e","guide_node相关_概要.md":"3c56ab35","guide_ddd 领域驱动设计_index.md":"7e53d5dd","guide_react_setstate是同步还是异步的.md":"cb4f6c10","guide_javascript相关_javascript编译机制.md":"e5a2c4f7","guide_css相关_概要.md":"1a81ce4c","guide_javascript相关_dom相关.md":"b979d5d3","guide_javascript相关_javascript执行机制.md":"9520882a","guide_css相关_隐藏元素的方法.md":"c310eeb1","guide_ai_outputparser构建格式化输出.md":"309cc9be","guide_react_react中的事件机制.md":"a3d99e5c","guide_react_react是如何渲染的.md":"ce1d2ec5","guide_ai_retriever之向量数据库.md":"877a77bf","shoot_实战技巧_拍摄梦幻光斑.md":"5cd55bb7","guide_canvas_如何在canvas画板上自由书写.md":"a5b8d602","shoot_实战技巧_冷暖对比人像.md":"c1cc2cbc","guide_javascript相关_垃圾回收机制.md":"e4fa0356","guide_ai_retriever 常见的优化方式.md":"a80c6c4a","guide_react_如何设计react组件.md":"a3612843","guide_ai_rag 检索增强生成的流程.md":"5f0d5880","guide_redux_设计理念.md":"67b7623f","guide_react_react中的异常机制.md":"07adea05","guide_css相关_position.md":"e15b98ea","guide_canvas_通过离屏渲染提高canvas书写性能.md":"c367c715","guide_canvas_通过 offscreencanvas _ worker 提高书写性能.md":"0f8f23b4","guide_ai_什么是langchain.md":"61520c2b","guide_css相关_display、visibility、opacity区别.md":"b7b1bec8","guide_react_react中的性能优化.md":"1a2d4379","guide_javascript相关_定义.md":"dcb774c1","guide_css相关_bfc.md":"9c93da99","guide_css相关_display.md":"1a4136c3","guide_webpack_loader.md":"efb3dbc7","guide_javascript相关_promise.md":"f290aa02","guide_webpack_mini-webpack.md":"408bd203","guide_webpack_构建流程.md":"75ec3b17","guide_webpack_热更新原理.md":"fa9979a3","guide_浏览器相关_浏览器内核.md":"68b358b7","guide_浏览器相关_浏览器安全.md":"377392a3","guide_浏览器相关_浏览器渲染流程.md":"12bb6e51","guide_浏览器相关_浏览器进程架构.md":"3ca88720","guide_浏览器相关_浏览器缓存.md":"763b5a0b","guide_网络相关_dns.md":"2f99cb22","guide_网络相关_cdn.md":"2fee8126","guide_canvas_可视区域内渲染提高canvas书写性能.md":"4ff663e0","guide_网络相关_概要.md":"b0fd3658","guide_webpack_index.md":"5f5b84e7","guide_网络相关_请求报文.md":"6db843bd","guide_ai_langchain快速入门.md":"e62e22b3","guide_javascript相关_基础概念.md":"64290002","guide_javascript相关_字符串常见的api.md":"17b4927c","guide_网络相关_跨域请求.md":"a6d45f4f","index.md":"6af0eea6","guide_javascript相关_es6相关.md":"d9bb55f1","guide_canvas_通过贝塞尔曲线优化canvas书写性能.md":"c60e183e","shoot_基础概念_光圈.md":"25a49ca0","shoot_基础概念_快门速度.md":"dc196df4","shoot_实战技巧_index.md":"a00862a6","shoot_基础概念_iso感光度.md":"bdf26bdf","guide_javascript相关_继承相关.md":"d7ab4f95","shoot_实战技巧_亮调人像.md":"c68e12f4","shoot_实战技巧_暗调人像.md":"da9ae4b2","shoot_实战技巧_如何拍花的黑背景.md":"1b7e842b","shoot_实战技巧_逆光人像.md":"8e2d1ea7","shoot_实战技巧_如何拍雨丝.md":"97a4b635","shoot_自我实战总结_延迟摄影.md":"7da692c4","guide_javascript相关_事件循环机制.md":"6b5cbf0d","shoot_自我实战总结_拍摄星空.md":"59c72bc3","shoot_自我实战总结_拍摄月亮.md":"bf540294","shoot_自我实战总结_拍摄烟花.md":"5d5410ff","guide_canvas_通过上下分层优化canvas书写性能.md":"0754eb3f","guide_css相关_display、float、position的关系.md":"446e1f0c","guide_react_react为什么要使用jsx.md":"446a2a3a","guide_javascript相关_index.md":"071c7151","guide_javascript相关_js异常捕获机制.md":"ce3f1203","guide_css相关_对 line-height 的理解及其赋值方式.md":"1574e386","guide_javascript相关_对象常见的api.md":"4f48158b","guide_javascript相关_新的运算符.md":"ebbfecce","guide_javascript相关_正则表达式.md":"acb1905e","guide_javascript相关_数组常见的api.md":"e4d7ce17","guide_react_常见的问题.md":"49923c54","guide_javascript相关_数据类型.md":"9fd8813a","shoot_构图形式_构图技巧.md":"78cc0528","guide_网络相关_get请求和post请求的区别.md":"f8c99ea3","guide_网络相关_常见的问题.md":"c094fe45","guide_网络相关_https.md":"c151d679","guide_网络相关_响应报文.md":"c005c655","guide_网络相关_http.md":"0eca7c23","guide_webpack_模块联邦.md":"74341cda","guide_浏览器相关_概要.md":"02c9983a"} diff --git a/index.html b/index.html index 81b17f5f..565ec9b5 100644 --- a/index.html +++ b/index.html @@ -11,7 +11,7 @@ - + @@ -23,8 +23,8 @@ -
Skip to content

个人知识库

👋 欢迎来到我的博客,这里是我记录学习和生活的地方,希望能帮助到你

采用 VitePress 进行构建,为了有更好的阅读体验,请使用新版本浏览器

- +
Skip to content

个人知识库

👋 欢迎来到我的博客,这里是我记录学习和生活的地方,希望能帮助到你

采用 VitePress 进行构建,为了有更好的阅读体验,请使用新版本浏览器

+ \ No newline at end of file diff --git "a/shoot/\345\237\272\347\241\200\346\246\202\345\277\265/ISO\346\204\237\345\205\211\345\272\246.html" "b/shoot/\345\237\272\347\241\200\346\246\202\345\277\265/ISO\346\204\237\345\205\211\345\272\246.html" index eaac3190..a9dae67d 100644 --- "a/shoot/\345\237\272\347\241\200\346\246\202\345\277\265/ISO\346\204\237\345\205\211\345\272\246.html" +++ "b/shoot/\345\237\272\347\241\200\346\246\202\345\277\265/ISO\346\204\237\345\205\211\345\272\246.html" @@ -11,7 +11,7 @@ - + @@ -23,8 +23,8 @@ -
Skip to content

ISO 感光度

传感器对光线的敏感程度

  • 感光度越大、图片越亮,但也容易出现噪点
- +
Skip to content

ISO 感光度

传感器对光线的敏感程度

  • 感光度越大、图片越亮,但也容易出现噪点
+ \ No newline at end of file diff --git "a/shoot/\345\237\272\347\241\200\346\246\202\345\277\265/\345\205\211\345\234\210.html" "b/shoot/\345\237\272\347\241\200\346\246\202\345\277\265/\345\205\211\345\234\210.html" index b68457d5..9fd7f385 100644 --- "a/shoot/\345\237\272\347\241\200\346\246\202\345\277\265/\345\205\211\345\234\210.html" +++ "b/shoot/\345\237\272\347\241\200\346\246\202\345\277\265/\345\205\211\345\234\210.html" @@ -11,7 +11,7 @@ - + @@ -23,8 +23,8 @@ -
Skip to content

光圈

控制光圈大小

  1. 数字越大、光圈越小就越暗 - 图像越清晰
  2. 数字越小、光圈越大就越亮 - 光圈过大虚化效果明显
- +
Skip to content

光圈

控制光圈大小

  1. 数字越大、光圈越小就越暗 - 图像越清晰
  2. 数字越小、光圈越大就越亮 - 光圈过大虚化效果明显
+ \ No newline at end of file diff --git "a/shoot/\345\237\272\347\241\200\346\246\202\345\277\265/\345\277\253\351\227\250\351\200\237\345\272\246.html" "b/shoot/\345\237\272\347\241\200\346\246\202\345\277\265/\345\277\253\351\227\250\351\200\237\345\272\246.html" index 7e4837fb..b4ec7fde 100644 --- "a/shoot/\345\237\272\347\241\200\346\246\202\345\277\265/\345\277\253\351\227\250\351\200\237\345\272\246.html" +++ "b/shoot/\345\237\272\347\241\200\346\246\202\345\277\265/\345\277\253\351\227\250\351\200\237\345\272\246.html" @@ -11,7 +11,7 @@ - + @@ -23,8 +23,8 @@ -
Skip to content

快门速度

控制开启传感器的时间

  • 快门速度越短,越能凝固物体,常用在抓拍
  • 快门速度越长,容易得到拖影的图
    • 快门速度
    • 拍静止的水面 (一般需要借助三脚架)
- +
Skip to content

快门速度

控制开启传感器的时间

  • 快门速度越短,越能凝固物体,常用在抓拍
  • 快门速度越长,容易得到拖影的图
    • 快门速度
    • 拍静止的水面 (一般需要借助三脚架)
+ \ No newline at end of file diff --git "a/shoot/\345\256\236\346\210\230\346\212\200\345\267\247/index.html" "b/shoot/\345\256\236\346\210\230\346\212\200\345\267\247/index.html" index 183792ba..734b94cb 100644 --- "a/shoot/\345\256\236\346\210\230\346\212\200\345\267\247/index.html" +++ "b/shoot/\345\256\236\346\210\230\346\212\200\345\267\247/index.html" @@ -11,7 +11,7 @@ - + @@ -23,8 +23,8 @@ - - + + \ No newline at end of file diff --git "a/shoot/\345\256\236\346\210\230\346\212\200\345\267\247/\344\272\256\350\260\203\344\272\272\345\203\217.html" "b/shoot/\345\256\236\346\210\230\346\212\200\345\267\247/\344\272\256\350\260\203\344\272\272\345\203\217.html" index bfe1293a..239bfac4 100644 --- "a/shoot/\345\256\236\346\210\230\346\212\200\345\267\247/\344\272\256\350\260\203\344\272\272\345\203\217.html" +++ "b/shoot/\345\256\236\346\210\230\346\212\200\345\267\247/\344\272\256\350\260\203\344\272\272\345\203\217.html" @@ -11,7 +11,7 @@ - + @@ -23,8 +23,8 @@ -
Skip to content

亮调人像

百分之 70 都是浅色系

前置

  1. 背景是浅色
  2. 人物衣服也是浅色

如何拍摄

  1. 评价测光
  2. 可适当增加曝光补偿
- +
Skip to content

亮调人像

百分之 70 都是浅色系

前置

  1. 背景是浅色
  2. 人物衣服也是浅色

如何拍摄

  1. 评价测光
  2. 可适当增加曝光补偿
+ \ No newline at end of file diff --git "a/shoot/\345\256\236\346\210\230\346\212\200\345\267\247/\345\206\267\346\232\226\345\257\271\346\257\224\344\272\272\345\203\217.html" "b/shoot/\345\256\236\346\210\230\346\212\200\345\267\247/\345\206\267\346\232\226\345\257\271\346\257\224\344\272\272\345\203\217.html" index 64b9737b..17528e12 100644 --- "a/shoot/\345\256\236\346\210\230\346\212\200\345\267\247/\345\206\267\346\232\226\345\257\271\346\257\224\344\272\272\345\203\217.html" +++ "b/shoot/\345\256\236\346\210\230\346\212\200\345\267\247/\345\206\267\346\232\226\345\257\271\346\257\224\344\272\272\345\203\217.html" @@ -11,7 +11,7 @@ - + @@ -23,8 +23,8 @@ -
Skip to content

冷暖对比人像

人物和背景冷暖色系不同

场景

  1. 蓝调时刻 - 太阳刚落山

如何拍摄

  1. 暖色 - 可以通过补光灯
  2. 色温 - 3500 - 4000k
  3. 白平衡 - b2m2
- +
Skip to content

冷暖对比人像

人物和背景冷暖色系不同

场景

  1. 蓝调时刻 - 太阳刚落山

如何拍摄

  1. 暖色 - 可以通过补光灯
  2. 色温 - 3500 - 4000k
  3. 白平衡 - b2m2
+ \ No newline at end of file diff --git "a/shoot/\345\256\236\346\210\230\346\212\200\345\267\247/\345\246\202\344\275\225\346\213\215\350\212\261\347\232\204\351\273\221\350\203\214\346\231\257.html" "b/shoot/\345\256\236\346\210\230\346\212\200\345\267\247/\345\246\202\344\275\225\346\213\215\350\212\261\347\232\204\351\273\221\350\203\214\346\231\257.html" index 6f8e01d2..8d56e7c0 100644 --- "a/shoot/\345\256\236\346\210\230\346\212\200\345\267\247/\345\246\202\344\275\225\346\213\215\350\212\261\347\232\204\351\273\221\350\203\214\346\231\257.html" +++ "b/shoot/\345\256\236\346\210\230\346\212\200\345\267\247/\345\246\202\344\275\225\346\213\215\350\212\261\347\232\204\351\273\221\350\203\214\346\231\257.html" @@ -11,7 +11,7 @@ - + @@ -23,8 +23,8 @@ -
Skip to content

如何拍花

如何拍摄

  1. 采用 点测光 突出花的亮度
  2. 背景采用 深色系 突出主体
- +
Skip to content

如何拍花

如何拍摄

  1. 采用 点测光 突出花的亮度
  2. 背景采用 深色系 突出主体
+ \ No newline at end of file diff --git "a/shoot/\345\256\236\346\210\230\346\212\200\345\267\247/\345\246\202\344\275\225\346\213\215\351\233\250\344\270\235.html" "b/shoot/\345\256\236\346\210\230\346\212\200\345\267\247/\345\246\202\344\275\225\346\213\215\351\233\250\344\270\235.html" index 9b1bd7e7..097a6af3 100644 --- "a/shoot/\345\256\236\346\210\230\346\212\200\345\267\247/\345\246\202\344\275\225\346\213\215\351\233\250\344\270\235.html" +++ "b/shoot/\345\256\236\346\210\230\346\212\200\345\267\247/\345\246\202\344\275\225\346\213\215\351\233\250\344\270\235.html" @@ -11,7 +11,7 @@ - + @@ -23,8 +23,8 @@ -
Skip to content

如何拍雨丝

如何拍摄

灯位要求

需要俩盏灯

  • 逆光灯: 在拍摄物体后方 (容易拍摄到雨丝,而且物体会有光边效果)
  • 正光灯:在拍摄物体前方(避免物体逆光,变黑)

逆光灯亮度 > 主光灯

灯位要求

白平衡

如果拍摄物体偏黄,可以调低白平衡,使物体变白

快门速度

  • 快门速度越慢,雨水成丝
  • 快门速度越快,雨水成点
- +
Skip to content

如何拍雨丝

如何拍摄

灯位要求

需要俩盏灯

  • 逆光灯: 在拍摄物体后方 (容易拍摄到雨丝,而且物体会有光边效果)
  • 正光灯:在拍摄物体前方(避免物体逆光,变黑)

逆光灯亮度 > 主光灯

灯位要求

白平衡

如果拍摄物体偏黄,可以调低白平衡,使物体变白

快门速度

  • 快门速度越慢,雨水成丝
  • 快门速度越快,雨水成点
+ \ No newline at end of file diff --git "a/shoot/\345\256\236\346\210\230\346\212\200\345\267\247/\346\213\215\346\221\204\346\242\246\345\271\273\345\205\211\346\226\221.html" "b/shoot/\345\256\236\346\210\230\346\212\200\345\267\247/\346\213\215\346\221\204\346\242\246\345\271\273\345\205\211\346\226\221.html" index e88a26f4..29f7e7bf 100644 --- "a/shoot/\345\256\236\346\210\230\346\212\200\345\267\247/\346\213\215\346\221\204\346\242\246\345\271\273\345\205\211\346\226\221.html" +++ "b/shoot/\345\256\236\346\210\230\346\212\200\345\267\247/\346\213\215\346\221\204\346\242\246\345\271\273\345\205\211\346\226\221.html" @@ -11,7 +11,7 @@ - + @@ -23,8 +23,8 @@ -
Skip to content

拍摄梦幻光斑

如何拍摄

  • 采用大光圈镜头,有很好的背景虚化效果
  • 需要一个补光灯,减少避免人物逆光导致过黑
    • 拍摄物体在光斑前面
    • 对焦到物体上(也可以通过精细对焦,即放大后手动对焦)
- +
Skip to content

拍摄梦幻光斑

如何拍摄

  • 采用大光圈镜头,有很好的背景虚化效果
  • 需要一个补光灯,减少避免人物逆光导致过黑
    • 拍摄物体在光斑前面
    • 对焦到物体上(也可以通过精细对焦,即放大后手动对焦)
+ \ No newline at end of file diff --git "a/shoot/\345\256\236\346\210\230\346\212\200\345\267\247/\346\232\227\350\260\203\344\272\272\345\203\217.html" "b/shoot/\345\256\236\346\210\230\346\212\200\345\267\247/\346\232\227\350\260\203\344\272\272\345\203\217.html" index 84e1b527..878bc757 100644 --- "a/shoot/\345\256\236\346\210\230\346\212\200\345\267\247/\346\232\227\350\260\203\344\272\272\345\203\217.html" +++ "b/shoot/\345\256\236\346\210\230\346\212\200\345\267\247/\346\232\227\350\260\203\344\272\272\345\203\217.html" @@ -11,7 +11,7 @@ - + @@ -23,8 +23,8 @@ -
Skip to content

暗调人像

百分之 70 都是黑色的

前置

  1. 背景是黑色
  2. 人物衣服也是黑色

如何拍摄

  1. 点测光人物面部,保证面部光亮
  2. 为了避免人物和背景重合,可以在人物背面打一束光
  3. 如果周围环境还是比较亮,可以减少一两档曝光补偿

参数参考

  • 光圈:f/2.8、曝光时间 1/125、ISO: 1600
- +
Skip to content

暗调人像

百分之 70 都是黑色的

前置

  1. 背景是黑色
  2. 人物衣服也是黑色

如何拍摄

  1. 点测光人物面部,保证面部光亮
  2. 为了避免人物和背景重合,可以在人物背面打一束光
  3. 如果周围环境还是比较亮,可以减少一两档曝光补偿

参数参考

  • 光圈:f/2.8、曝光时间 1/125、ISO: 1600
+ \ No newline at end of file diff --git "a/shoot/\345\256\236\346\210\230\346\212\200\345\267\247/\351\200\206\345\205\211\344\272\272\345\203\217.html" "b/shoot/\345\256\236\346\210\230\346\212\200\345\267\247/\351\200\206\345\205\211\344\272\272\345\203\217.html" index 97d84976..ca9c8681 100644 --- "a/shoot/\345\256\236\346\210\230\346\212\200\345\267\247/\351\200\206\345\205\211\344\272\272\345\203\217.html" +++ "b/shoot/\345\256\236\346\210\230\346\212\200\345\267\247/\351\200\206\345\205\211\344\272\272\345\203\217.html" @@ -11,7 +11,7 @@ - + @@ -23,8 +23,8 @@ -
Skip to content

逆光人像

前置

  1. 逆光,光线较好(如夕阳)
  2. 背景建议干净,突出人物

如何拍摄

  1. 采用手动对焦,避免对焦有偏差
  2. 使用点测光,对人物面部最亮部分测光
  3. 前景补光,避免人像面部过暗

灯位要求

- +
Skip to content

逆光人像

前置

  1. 逆光,光线较好(如夕阳)
  2. 背景建议干净,突出人物

如何拍摄

  1. 采用手动对焦,避免对焦有偏差
  2. 使用点测光,对人物面部最亮部分测光
  3. 前景补光,避免人像面部过暗

灯位要求

+ \ No newline at end of file diff --git "a/shoot/\346\236\204\345\233\276\345\275\242\345\274\217/\346\236\204\345\233\276\346\212\200\345\267\247.html" "b/shoot/\346\236\204\345\233\276\345\275\242\345\274\217/\346\236\204\345\233\276\346\212\200\345\267\247.html" index 53aefbd7..85bd4c29 100644 --- "a/shoot/\346\236\204\345\233\276\345\275\242\345\274\217/\346\236\204\345\233\276\346\212\200\345\267\247.html" +++ "b/shoot/\346\236\204\345\233\276\345\275\242\345\274\217/\346\236\204\345\233\276\346\212\200\345\267\247.html" @@ -11,7 +11,7 @@ - + @@ -23,8 +23,8 @@ -
Skip to content

构图技巧

点构图

中心点构图

将主题放在中心,突出主题

中心点构图

中心点构图

三分点构图

三分点构图

alt text

线构图

对称线构图

可以展示对称的秩序感,常用于风光、风光 + 人文 alt text

alt text

alt text

对角线构图

alt text

alt text

引导线构图

充分利用场景中的线条,用于引导观者的注意力落在主体上,并让画面产生深度和透视感 alt text

面构图

前景构图

例如通过树叶、花草、植物等做前景

alt text

框架构图

拍摄中利用框架将主体框起来,突出主体

alt text

alt text

留白构图

留有空白,让画面更加简洁,突出主题

alt text

alt text

- +
Skip to content

构图技巧

点构图

中心点构图

将主题放在中心,突出主题

中心点构图

中心点构图

三分点构图

三分点构图

alt text

线构图

对称线构图

可以展示对称的秩序感,常用于风光、风光 + 人文 alt text

alt text

alt text

对角线构图

alt text

alt text

引导线构图

充分利用场景中的线条,用于引导观者的注意力落在主体上,并让画面产生深度和透视感 alt text

面构图

前景构图

例如通过树叶、花草、植物等做前景

alt text

框架构图

拍摄中利用框架将主体框起来,突出主体

alt text

alt text

留白构图

留有空白,让画面更加简洁,突出主题

alt text

alt text

+ \ No newline at end of file diff --git "a/shoot/\350\207\252\346\210\221\345\256\236\346\210\230\346\200\273\347\273\223/\345\273\266\350\277\237\346\221\204\345\275\261.html" "b/shoot/\350\207\252\346\210\221\345\256\236\346\210\230\346\200\273\347\273\223/\345\273\266\350\277\237\346\221\204\345\275\261.html" index 99288bad..b2a18a33 100644 --- "a/shoot/\350\207\252\346\210\221\345\256\236\346\210\230\346\200\273\347\273\223/\345\273\266\350\277\237\346\221\204\345\275\261.html" +++ "b/shoot/\350\207\252\346\210\221\345\256\236\346\210\230\346\200\273\347\273\223/\345\273\266\350\277\237\346\221\204\345\275\261.html" @@ -11,7 +11,7 @@ - + @@ -23,8 +23,8 @@ -
Skip to content

延迟摄影

如何拍摄

  1. 调节到视频模式

  2. 打开 Menu 菜单,在第一大项的第4小项中找到延时短片,打开这一功能。之后,回到主屏幕,我们发现左上角摄影机图标旁多出了一个时针图案和一组4位数字,这代表延时摄影已打开成功,准备进入拍摄。 Menu 菜单

  3. 此时,主屏幕下方的三个参数均可手动调整,从左到右依次是快门、光圈、感光度ISO Menu 菜单

  4. 自动曝光设置 固定第一帧: 固定第一帧指的是延时短片将始终以第一帧曝光的参数拍摄下去,中途不会发生改变,适用于光源亮度变化不大的场景 每一帧: 延时短片将由相机依据环境光线的变化,自动测光来决定每一帧的曝光值,适用于光源有较大改变的场景,如日转夜或夜转日 (ISO 感光度要设置成 AUTO) 自动曝光

参考文章

  1. https://www.xiaohongshu.com/explore/651389a3000000001e023777
- +
Skip to content

延迟摄影

如何拍摄

  1. 调节到视频模式

  2. 打开 Menu 菜单,在第一大项的第4小项中找到延时短片,打开这一功能。之后,回到主屏幕,我们发现左上角摄影机图标旁多出了一个时针图案和一组4位数字,这代表延时摄影已打开成功,准备进入拍摄。 Menu 菜单

  3. 此时,主屏幕下方的三个参数均可手动调整,从左到右依次是快门、光圈、感光度ISO Menu 菜单

  4. 自动曝光设置 固定第一帧: 固定第一帧指的是延时短片将始终以第一帧曝光的参数拍摄下去,中途不会发生改变,适用于光源亮度变化不大的场景 每一帧: 延时短片将由相机依据环境光线的变化,自动测光来决定每一帧的曝光值,适用于光源有较大改变的场景,如日转夜或夜转日 (ISO 感光度要设置成 AUTO) 自动曝光

参考文章

  1. https://www.xiaohongshu.com/explore/651389a3000000001e023777
+ \ No newline at end of file diff --git "a/shoot/\350\207\252\346\210\221\345\256\236\346\210\230\346\200\273\347\273\223/\346\213\215\346\221\204\346\230\237\347\251\272.html" "b/shoot/\350\207\252\346\210\221\345\256\236\346\210\230\346\200\273\347\273\223/\346\213\215\346\221\204\346\230\237\347\251\272.html" index 0188a095..a6cfb79a 100644 --- "a/shoot/\350\207\252\346\210\221\345\256\236\346\210\230\346\200\273\347\273\223/\346\213\215\346\221\204\346\230\237\347\251\272.html" +++ "b/shoot/\350\207\252\346\210\221\345\256\236\346\210\230\346\200\273\347\273\223/\346\213\215\346\221\204\346\230\237\347\251\272.html" @@ -11,7 +11,7 @@ - + @@ -23,8 +23,8 @@ -
Skip to content

拍摄星空

大光圈、感光度、长曝光,这是拍摄星空的三大要素。

大光圈

f1.8

感光度

ISO:2000 以上(感光度越大、图片越亮,但也容易出现噪点)

手动对焦

手动对焦到某一颗星星上,然后锁定对焦

长曝光

快门速度 10秒以上, 连续拍10张以上后期堆栈(拍得多更好)

脚架

需要使用三脚架

星空

星空参数

参考文章

  1. https://www.xiaohongshu.com/explore/6507b277000000001e02de1a
- +
Skip to content

拍摄星空

大光圈、感光度、长曝光,这是拍摄星空的三大要素。

大光圈

f1.8

感光度

ISO:2000 以上(感光度越大、图片越亮,但也容易出现噪点)

手动对焦

手动对焦到某一颗星星上,然后锁定对焦

长曝光

快门速度 10秒以上, 连续拍10张以上后期堆栈(拍得多更好)

脚架

需要使用三脚架

星空

星空参数

参考文章

  1. https://www.xiaohongshu.com/explore/6507b277000000001e02de1a
+ \ No newline at end of file diff --git "a/shoot/\350\207\252\346\210\221\345\256\236\346\210\230\346\200\273\347\273\223/\346\213\215\346\221\204\346\234\210\344\272\256.html" "b/shoot/\350\207\252\346\210\221\345\256\236\346\210\230\346\200\273\347\273\223/\346\213\215\346\221\204\346\234\210\344\272\256.html" index af590501..f341482a 100644 --- "a/shoot/\350\207\252\346\210\221\345\256\236\346\210\230\346\200\273\347\273\223/\346\213\215\346\221\204\346\234\210\344\272\256.html" +++ "b/shoot/\350\207\252\346\210\221\345\256\236\346\210\230\346\200\273\347\273\223/\346\213\215\346\221\204\346\234\210\344\272\256.html" @@ -11,7 +11,7 @@ - + @@ -23,8 +23,8 @@ -
Skip to content

拍摄月亮

  • 光圈一般我喜欢小光圈 在 f8 - f10 之间
  • 需要使用长焦镜头,例如 70-200mm
- +
Skip to content

拍摄月亮

  • 光圈一般我喜欢小光圈 在 f8 - f10 之间
  • 需要使用长焦镜头,例如 70-200mm
+ \ No newline at end of file diff --git "a/shoot/\350\207\252\346\210\221\345\256\236\346\210\230\346\200\273\347\273\223/\346\213\215\346\221\204\347\203\237\350\212\261.html" "b/shoot/\350\207\252\346\210\221\345\256\236\346\210\230\346\200\273\347\273\223/\346\213\215\346\221\204\347\203\237\350\212\261.html" index 10fecbd9..a9c97e4a 100644 --- "a/shoot/\350\207\252\346\210\221\345\256\236\346\210\230\346\200\273\347\273\223/\346\213\215\346\221\204\347\203\237\350\212\261.html" +++ "b/shoot/\350\207\252\346\210\221\345\256\236\346\210\230\346\200\273\347\273\223/\346\213\215\346\221\204\347\203\237\350\212\261.html" @@ -11,7 +11,7 @@ - + @@ -23,8 +23,8 @@ -
Skip to content

拍摄烟花

  • 快门速度一般比较长可以出现拉线效果,例如 0.5s/1s
  • ISO 感光度一般在 500 以下,这样背景会黑一些
  • 光圈一般我喜欢小光圈 在 f10 以后

快门速度

- +
Skip to content

拍摄烟花

  • 快门速度一般比较长可以出现拉线效果,例如 0.5s/1s
  • ISO 感光度一般在 500 以下,这样背景会黑一些
  • 光圈一般我喜欢小光圈 在 f10 以后

快门速度

+ \ No newline at end of file