整合營銷服務(wù)商

          電腦端+手機端+微信端=數(shù)據(jù)同步管理

          免費咨詢熱線:

          前端面試進階之瀏覽器原理

          前端面試進階之瀏覽器原理


          、瀏覽器安全

          1. 什么是 XSS 攻擊?

          (1)概念

          XSS 攻擊指的是跨站腳本攻擊,是一種代碼注入攻擊。攻擊者通過在網(wǎng)站注入惡意腳本,使之在用戶的瀏覽器上運行,從而盜取用戶的信息如 cookie 等。

          XSS 的本質(zhì)是因為網(wǎng)站沒有對惡意代碼進行過濾,與正常的代碼混合在一起了,瀏覽器沒有辦法分辨哪些腳本是可信的,從而導(dǎo)致了惡意代碼的執(zhí)行。

          攻擊者可以通過這種攻擊方式可以進行以下操作:

          獲取頁面的數(shù)據(jù),如DOM、cookie、localStorage;

          DOS攻擊,發(fā)送合理請求,占用服務(wù)器資源,從而使用戶無法訪問服務(wù)器;

          破壞頁面結(jié)構(gòu);

          流量劫持(將鏈接指向某網(wǎng)站);

          (2)攻擊類型

          XSS 可以分為存儲型、反射型和 DOM 型:

          存儲型指的是惡意腳本會存儲在目標服務(wù)器上,當瀏覽器請求數(shù)據(jù)時,腳本從服務(wù)器傳回并執(zhí)行。

          反射型指的是攻擊者誘導(dǎo)用戶訪問一個帶有惡意代碼的 URL 后,服務(wù)器端接收數(shù)據(jù)后處理,然后把帶有惡意代碼的數(shù)據(jù)發(fā)送到瀏覽器端,瀏覽器端解析這段帶有 XSS 代碼的數(shù)據(jù)后當做腳本執(zhí)行,最終完成 XSS 攻擊。

          DOM 型指的通過修改頁面的 DOM 節(jié)點形成的 XSS。

          1)存儲型 XSS 的攻擊步驟:

          攻擊者將惡意代碼提交到?標?站的數(shù)據(jù)庫中。

          ?戶打開?標?站時,?站服務(wù)端將惡意代碼從數(shù)據(jù)庫取出,拼接在 HTML 中返回給瀏覽器。

          ?戶瀏覽器接收到響應(yīng)后解析執(zhí)?,混在其中的惡意代碼也被執(zhí)?。

          惡意代碼竊取?戶數(shù)據(jù)并發(fā)送到攻擊者的?站,或者冒充?戶的?為,調(diào)??標?站接?執(zhí)?攻擊者指定的操作。

          這種攻擊常?于帶有?戶保存數(shù)據(jù)的?站功能,如論壇發(fā)帖、商品評論、?戶私信等。

          2)反射型 XSS 的攻擊步驟:

          攻擊者構(gòu)造出特殊的 URL,其中包含惡意代碼。

          ?戶打開帶有惡意代碼的 URL 時,?站服務(wù)端將惡意代碼從 URL 中取出,拼接在 HTML 中返回給瀏覽器。

          ?戶瀏覽器接收到響應(yīng)后解析執(zhí)?,混在其中的惡意代碼也被執(zhí)?。

          惡意代碼竊取?戶數(shù)據(jù)并發(fā)送到攻擊者的?站,或者冒充?戶的?為,調(diào)??標?站接?執(zhí)?攻擊者指定的操作。

          反射型 XSS 跟存儲型 XSS 的區(qū)別是:存儲型 XSS 的惡意代碼存在數(shù)據(jù)庫?,反射型 XSS 的惡意代碼存在 URL ?。

          反射型 XSS 漏洞常?于通過 URL 傳遞參數(shù)的功能,如?站搜索、跳轉(zhuǎn)等。 由于需要?戶主動打開惡意的 URL 才能?效,攻擊者往往會結(jié)合多種?段誘導(dǎo)?戶點擊。

          3)DOM 型 XSS 的攻擊步驟:

          攻擊者構(gòu)造出特殊的 URL,其中包含惡意代碼。

          ?戶打開帶有惡意代碼的 URL。

          ?戶瀏覽器接收到響應(yīng)后解析執(zhí)?,前端 JavaScript 取出 URL 中的惡意代碼并執(zhí)?。

          惡意代碼竊取?戶數(shù)據(jù)并發(fā)送到攻擊者的?站,或者冒充?戶的?為,調(diào)??標?站接?執(zhí)?攻擊者指定的操作。

          DOM 型 XSS 跟前兩種 XSS 的區(qū)別:DOM 型 XSS 攻擊中,取出和執(zhí)?惡意代碼由瀏覽器端完成,屬于前端JavaScript ?身的安全漏洞,?其他兩種 XSS 都屬于服務(wù)端的安全漏洞。

          2. 如何防御 XSS 攻擊?

          可以看到XSS危害如此之大, 那么在開發(fā)網(wǎng)站時就要做好防御措施,具體措施如下:

          可以從瀏覽器的執(zhí)行來進行預(yù)防,一種是使用純前端的方式,不用服務(wù)器端拼接后返回(不使用服務(wù)端渲染)。另一種是對需要插入到 HTML 中的代碼做好充分的轉(zhuǎn)義。對于 DOM 型的攻擊,主要是前端腳本的不可靠而造成的,對于數(shù)據(jù)獲取渲染和字符串拼接的時候應(yīng)該對可能出現(xiàn)的惡意代碼情況進行判斷。

          使用 CSP ,CSP 的本質(zhì)是建立一個白名單,告訴瀏覽器哪些外部資源可以加載和執(zhí)行,從而防止惡意代碼的注入攻擊。

          CSP 指的是內(nèi)容安全策略,它的本質(zhì)是建立一個白名單,告訴瀏覽器哪些外部資源可以加載和執(zhí)行。我們只需要配置規(guī)則,如何攔截由瀏覽器自己來實現(xiàn)。

          通常有兩種方式來開啟 CSP,一種是設(shè)置 HTTP 首部中的 Content-Security-Policy,一種是設(shè)置 meta 標簽的方式

          對一些敏感信息進行保護,比如 cookie 使用 http-only,使得腳本無法獲取。也可以使用驗證碼,避免腳本偽裝成用戶執(zhí)行一些操作。

          3. 什么是 CSRF 攻擊?

          (1)概念

          CSRF 攻擊指的是跨站請求偽造攻擊,攻擊者誘導(dǎo)用戶進入一個第三方網(wǎng)站,然后該網(wǎng)站向被攻擊網(wǎng)站發(fā)送跨站請求。如果用戶在被攻擊網(wǎng)站中保存了登錄狀態(tài),那么攻擊者就可以利用這個登錄狀態(tài),繞過后臺的用戶驗證,冒充用戶向服務(wù)器執(zhí)行一些操作。

          CSRF 攻擊的本質(zhì)是****利用 cookie 會在同源請求中攜帶發(fā)送給服務(wù)器的特點,以此來實現(xiàn)用戶的冒充。

          (2)攻擊類型

          常見的 CSRF 攻擊有三種:

          GET 類型的 CSRF 攻擊,比如在網(wǎng)站中的一個 img 標簽里構(gòu)建一個請求,當用戶打開這個網(wǎng)站的時候就會自動發(fā)起提交。

          POST 類型的 CSRF 攻擊,比如構(gòu)建一個表單,然后隱藏它,當用戶進入頁面時,自動提交這個表單。

          鏈接類型的 CSRF 攻擊,比如在 a 標簽的 href 屬性里構(gòu)建一個請求,然后誘導(dǎo)用戶去點擊。

          4. 如何防御 CSRF 攻擊?

          CSRF 攻擊可以使用以下方法來防護:

          進行同源檢測,服務(wù)器根據(jù) http 請求頭中 origin 或者 referer 信息來判斷請求是否為允許訪問的站點,從而對請求進行過濾。當 origin 或者 referer 信息都不存在的時候,直接阻止請求。這種方式的缺點是有些情況下 referer 可以被偽造,同時還會把搜索引擎的鏈接也給屏蔽了。所以一般網(wǎng)站會允許搜索引擎的頁面請求,但是相應(yīng)的頁面請求這種請求方式也可能被攻擊者給利用。(Referer 字段會告訴服務(wù)器該網(wǎng)頁是從哪個頁面鏈接過來的)

          使用 CSRF Token 進行驗證,服務(wù)器向用戶返回一個隨機數(shù) Token ,當網(wǎng)站再次發(fā)起請求時,在請求參數(shù)中加入服務(wù)器端返回的 token ,然后服務(wù)器對這個 token 進行驗證。這種方法解決了使用 cookie 單一驗證方式時,可能會被冒用的問題,但是這種方法存在一個缺點就是,我們需要給網(wǎng)站中的所有請求都添加上這個 token,操作比較繁瑣。還有一個問題是一般不會只有一臺網(wǎng)站服務(wù)器,如果請求經(jīng)過負載平衡轉(zhuǎn)移到了其他的服務(wù)器,但是這個服務(wù)器的 session 中沒有保留這個 token 的話,就沒有辦法驗證了。這種情況可以通過改變 token 的構(gòu)建方式來解決。

          對 Cookie 進行****雙重驗證,服務(wù)器在用戶訪問網(wǎng)站頁面時,向請求域名注入一個Cookie,內(nèi)容為隨機字符串,然后當用戶再次向服務(wù)器發(fā)送請求的時候,從 cookie 中取出這個字符串,添加到 URL 參數(shù)中,然后服務(wù)器通過對 cookie 中的數(shù)據(jù)和參數(shù)中的數(shù)據(jù)進行比較,來進行驗證。使用這種方式是利用了攻擊者只能利用 cookie,但是不能訪問獲取 cookie 的特點。并且這種方法比 CSRF Token 的方法更加方便,并且不涉及到分布式訪問的問題。這種方法的缺點是如果網(wǎng)站存在 XSS 漏洞的,那么這種方式會失效。同時這種方式不能做到子域名的隔離。

          在設(shè)置 cookie 屬性的時候設(shè)置 Samesite ,限制 cookie 不能作為被第三方使用,從而可以避免被攻擊者利用。Samesite 一共有兩種模式,一種是嚴格模式,在嚴格模式下 cookie 在任何情況下都不可能作為第三方 Cookie 使用,在寬松模式下,cookie 可以被請求是 GET 請求,且會發(fā)生頁面跳轉(zhuǎn)的請求所使用。

          5. 什么是中間人攻擊?如何防范中間人攻擊?

          中間? (Man-in-the-middle attack, MITM) 是指攻擊者與通訊的兩端分別創(chuàng)建獨?的聯(lián)系, 并交換其所收到的數(shù)據(jù), 使通訊的兩端認為他們正在通過?個私密的連接與對?直接對話, 但事實上整個會話都被攻擊者完全控制。在中間?攻擊中,攻擊者可以攔截通訊雙?的通話并插?新的內(nèi)容。

          攻擊過程如下:

          客戶端發(fā)送請求到服務(wù)端,請求被中間?截獲

          服務(wù)器向客戶端發(fā)送公鑰

          中間?截獲公鑰,保留在???上。然后???成?個偽造的公鑰,發(fā)給客戶端

          客戶端收到偽造的公鑰后,?成加密hash值發(fā)給服務(wù)器

          中間?獲得加密hash值,???的私鑰解密獲得真秘鑰,同時?成假的加密hash值,發(fā)給服務(wù)器

          服務(wù)器?私鑰解密獲得假密鑰,然后加密數(shù)據(jù)傳輸給客戶端

          6. 有哪些可能引起前端安全的問題**?**

          跨站腳本 (Cross-Site Scripting, XSS): ?種代碼注??式, 為了與 CSS 區(qū)分所以被稱作 XSS。早期常?于?絡(luò)論壇, 起因是?站沒有對?戶的輸?進?嚴格的限制, 使得攻擊者可以將腳本上傳到帖?讓其他?瀏覽到有惡意腳本的??, 其注??式很簡單包括但不限于 JavaScript / CSS / Flash 等;

          iframe的濫?: iframe中的內(nèi)容是由第三?來提供的,默認情況下他們不受控制,他們可以在iframe中運?JavaScirpt腳本、Flash插件、彈出對話框等等,這可能會破壞前端?戶體驗;

          跨站點請求偽造(Cross-Site Request Forgeries,CSRF): 指攻擊者通過設(shè)置好的陷阱,強制對已完成認證的?戶進??預(yù)期的個?信息或設(shè)定信息等某些狀態(tài)更新,屬于被動攻擊

          惡意第三?庫: ?論是后端服務(wù)器應(yīng)?還是前端應(yīng)?開發(fā),絕?多數(shù)時候都是在借助開發(fā)框架和各種類庫進?快速開發(fā),?旦第三?庫被植?惡意代碼很容易引起安全問題。

          7. 網(wǎng)絡(luò)劫持有哪幾種,如何防范?

          ?絡(luò)劫持分為兩種:

          (1)DNS****劫持: (輸?京東被強制跳轉(zhuǎn)到淘寶這就屬于dns劫持)

          DNS強制解析: 通過修改運營商的本地DNS記錄,來引導(dǎo)?戶流量到緩存服務(wù)器

          302跳轉(zhuǎn)的?式: 通過監(jiān)控?絡(luò)出?的流量,分析判斷哪些內(nèi)容是可以進?劫持處理的,再對劫持的內(nèi)存發(fā)起302跳轉(zhuǎn)的回復(fù),引導(dǎo)?戶獲取內(nèi)容

          (2)HTTP****劫持: (訪問?歌但是?直有貪玩藍?的?告),由于http明?傳輸,運營商會修改你的http響應(yīng)內(nèi)容(即加?告)

          DNS劫持由于涉嫌違法,已經(jīng)被監(jiān)管起來,現(xiàn)在很少會有DNS劫持,?http劫持依然?常盛?,最有效的辦法就是全站HTTPS,將HTTP加密,這使得運營商?法獲取明?,就?法劫持你的響應(yīng)內(nèi)容。

          二、進程與線程

          1. 進程與線程的概念

          從本質(zhì)上說,進程和線程都是 CPU 工作時間片的一個描述:

          進程描述了 CPU 在運行指令及加載和保存上下文所需的時間,放在應(yīng)用上來說就代表了一個程序。

          線程是進程中的更小單位,描述了執(zhí)行一段指令所需的時間。

          進程是資源分配的最小單位,線程是CPU調(diào)度的最小單位。

          一個進程就是一個程序的運行實例。詳細解釋就是,啟動一個程序的時候,操作系統(tǒng)會為該程序創(chuàng)建一塊內(nèi)存,用來存放代碼、運行中的數(shù)據(jù)和一個執(zhí)行任務(wù)的主線程,我們把這樣的一個運行環(huán)境叫進程。進程是運行在虛擬內(nèi)存上的,虛擬內(nèi)存是用來解決用戶對硬件資源的無限需求和有限的硬件資源之間的矛盾的。從操作系統(tǒng)角度來看,虛擬內(nèi)存即交換文件;從處理器角度看,虛擬內(nèi)存即虛擬地址空間。

          如果程序很多時,內(nèi)存可能會不夠,操作系統(tǒng)為每個進程提供一套獨立的虛擬地址空間,從而使得同一塊物理內(nèi)存在不同的進程中可以對應(yīng)到不同或相同的虛擬地址,變相的增加了程序可以使用的內(nèi)存。

          進程和線程之間的關(guān)系有以下四個特點:

          (1)進程中的任意一線程執(zhí)行出錯,都會導(dǎo)致整個進程的崩潰。

          (2)線程之間共享進程中的數(shù)據(jù)。

          **(3)當一個進程關(guān)閉之后,操作系統(tǒng)會回收進程所占用的內(nèi)存,**當一個進程退出時,操作系統(tǒng)會回收該進程所申請的所有資源;即使其中任意線程因為操作不當導(dǎo)致內(nèi)存泄漏,當進程退出時,這些內(nèi)存也會被正確回收。

          **(4)進程之間的內(nèi)容相互隔離。**進程隔離就是為了使操作系統(tǒng)中的進程互不干擾,每一個進程只能訪問自己占有的數(shù)據(jù),也就避免出現(xiàn)進程 A 寫入數(shù)據(jù)到進程 B 的情況。正是因為進程之間的數(shù)據(jù)是嚴格隔離的,所以一個進程如果崩潰了,或者掛起了,是不會影響到其他進程的。如果進程之間需要進行數(shù)據(jù)的通信,這時候,就需要使用用于進程間通信的機制了。

          Chrome瀏覽器的架構(gòu)圖:

          image

          從圖中可以看出,最新的 Chrome 瀏覽器包括:

          1 個瀏覽器主進程

          1 個 GPU 進程

          1 個網(wǎng)絡(luò)進程

          多個渲染進程

          多個插件進程

          這些進程的功能:

          瀏覽器進程:主要負責(zé)界面顯示、用戶交互、子進程管理,同時提供存儲等功能。

          渲染進程:核心任務(wù)是將 HTML、CSS 和 JavaScript 轉(zhuǎn)換為用戶可以與之交互的網(wǎng)頁,排版引擎 Blink 和 JavaScript 引擎 V8 都是運行在該進程中,默認情況下,Chrome 會為每個 Tab 標簽創(chuàng)建一個渲染進程。出于安全考慮,渲染進程都是運行在沙箱模式下。

          GPU 進程:其實, GPU 的使用初衷是為了實現(xiàn) 3D CSS 的效果,只是隨后網(wǎng)頁、Chrome 的 UI 界面都選擇采用 GPU 來繪制,這使得 GPU 成為瀏覽器普遍的需求。最后,Chrome 在其多進程架構(gòu)上也引入了 GPU 進程。

          網(wǎng)絡(luò)進程:主要負責(zé)頁面的網(wǎng)絡(luò)資源加載,之前是作為一個模塊運行在瀏覽器進程里面的,直至最近才獨立出來,成為一個單獨的進程。

          插件進程:主要是負責(zé)插件的運行,因插件易崩潰,所以需要通過插件進程來隔離,以保證插件進程崩潰不會對瀏覽器和頁面造成影響。

          所以,打開一個網(wǎng)頁,最少需要四個進程:1 個網(wǎng)絡(luò)進程、1 個瀏覽器進程、1 個 GPU 進程以及 1 個渲染進程。如果打開的頁面有運行插件的話,還需要再加上 1 個插件進程。

          雖然多進程模型提升了瀏覽器的穩(wěn)定性、流暢性和安全性,但同樣不可避免地帶來了一些問題:

          更高的資源占用:因為每個進程都會包含公共基礎(chǔ)結(jié)構(gòu)的副本(如 JavaScript 運行環(huán)境),這就意味著瀏覽器會消耗更多的內(nèi)存資源。

          更復(fù)雜的體系架構(gòu):瀏覽器各模塊之間耦合性高、擴展性差等問題,會導(dǎo)致現(xiàn)在的架構(gòu)已經(jīng)很難適應(yīng)新的需求了。

          2. 進程和線程的區(qū)別

          進程可以看做獨立應(yīng)用,線程不能

          資源:進程是cpu資源分配的最小單位(是能擁有資源和獨立運行的最小單位);線程是cpu調(diào)度的最小單位(線程是建立在進程的基礎(chǔ)上的一次程序運行單位,一個進程中可以有多個線程)。

          通信方面:線程間可以通過直接共享同一進程中的資源,而進程通信需要借助 進程間通信。

          調(diào)度:進程切換比線程切換的開銷要大。線程是CPU調(diào)度的基本單位,線程的切換不會引起進程切換,但某個進程中的線程切換到另一個進程中的線程時,會引起進程切換。

          系統(tǒng)開銷:由于創(chuàng)建或撤銷進程時,系統(tǒng)都要為之分配或回收資源,如內(nèi)存、I/O 等,其開銷遠大于創(chuàng)建或撤銷線程時的開銷。同理,在進行進程切換時,涉及當前執(zhí)行進程 CPU 環(huán)境還有各種各樣狀態(tài)的保存及新調(diào)度進程狀態(tài)的設(shè)置,而線程切換時只需保存和設(shè)置少量寄存器內(nèi)容,開銷較小。

          3. 瀏覽器渲染進程的線程有哪些

          瀏覽器的渲染進程的線程總共有五種:

          image

          (1)GUI渲染線程

          負責(zé)渲染瀏覽器頁面,解析HTML、CSS,構(gòu)建DOM樹、構(gòu)建CSSOM樹、構(gòu)建渲染樹和繪制頁面;當界面需要重繪或由于某種操作引發(fā)回流時,該線程就會執(zhí)行。

          注意:GUI渲染線程和JS引擎線程是互斥的,當JS引擎執(zhí)行時GUI線程會被掛起,GUI更新會被保存在一個隊列中等到JS引擎空閑時立即被執(zhí)行。

          (2)JS引擎線程

          JS引擎線程也稱為JS內(nèi)核,負責(zé)處理Javascript腳本程序,解析Javascript腳本,運行代碼;JS引擎線程一直等待著任務(wù)隊列中任務(wù)的到來,然后加以處理,一個Tab頁中無論什么時候都只有一個JS引擎線程在運行JS程序;

          注意:GUI渲染線程與JS引擎線程的互斥關(guān)系,所以如果JS執(zhí)行的時間過長,會造成頁面的渲染不連貫,導(dǎo)致頁面渲染加載阻塞。

          (3)時間觸發(fā)線程

          時間觸發(fā)線程屬于瀏覽器而不是JS引擎,用來控制事件循環(huán);當JS引擎執(zhí)行代碼塊如setTimeOut時(也可是來自瀏覽器內(nèi)核的其他線程,如鼠標點擊、AJAX異步請求等),會將對應(yīng)任務(wù)添加到事件觸發(fā)線程中;當對應(yīng)的事件符合觸發(fā)條件被觸發(fā)時,該線程會把事件添加到待處理隊列的隊尾,等待JS引擎的處理;

          注意:由于JS的單線程關(guān)系,所以這些待處理隊列中的事件都得排隊等待JS引擎處理(當JS引擎空閑時才會去執(zhí)行);

          (4)定時器觸發(fā)進程

          定時器觸發(fā)進程即setInterval與setTimeout所在線程;瀏覽器定時計數(shù)器并不是由JS引擎計數(shù)的,因為JS引擎是單線程的,如果處于阻塞線程狀態(tài)就會影響記計時的準確性;因此使用單獨線程來計時并觸發(fā)定時器,計時完畢后,添加到事件隊列中,等待JS引擎空閑后執(zhí)行,所以定時器中的任務(wù)在設(shè)定的時間點不一定能夠準時執(zhí)行,定時器只是在指定時間點將任務(wù)添加到事件隊列中;

          注意:W3C在HTML標準中規(guī)定,定時器的定時時間不能小于4ms,如果是小于4ms,則默認為4ms。

          (5)異步http請求線程

          XMLHttpRequest連接后通過瀏覽器新開一個線程請求;

          檢測到狀態(tài)變更時,如果設(shè)置有回調(diào)函數(shù),異步線程就產(chǎn)生狀態(tài)變更事件,將回調(diào)函數(shù)放入事件隊列中,等待JS引擎空閑后執(zhí)行;

          4. 進程之前的通信方式---了解即可

          (1)管道通信

          管道是一種最基本的進程間通信機制。管道就是操作系統(tǒng)在內(nèi)核中開辟的一段緩沖區(qū),進程1可以將需要交互的數(shù)據(jù)拷貝到這段緩沖區(qū),進程2就可以讀取了。

          管道的特點:

          只能單向通信

          只能血緣關(guān)系的進程進行通信

          依賴于文件系統(tǒng)

          生命周期隨進程

          面向字節(jié)流的服務(wù)

          管道內(nèi)部提供了同步機制

          (2)消息隊列通信

          消息隊列就是一個消息的列表。用戶可以在消息隊列中添加消息、讀取消息等。消息隊列提供了一種從一個進程向另一個進程發(fā)送一個數(shù)據(jù)塊的方法。 每個數(shù)據(jù)塊都被認為含有一個類型,接收進程可以獨立地接收含有不同類型的數(shù)據(jù)結(jié)構(gòu)。可以通過發(fā)送消息來避免命名管道的同步和阻塞問題。但是消息隊列與命名管道一樣,每個數(shù)據(jù)塊都有一個最大長度的限制。

          使用消息隊列進行進程間通信,可能會收到數(shù)據(jù)塊最大長度的限制約束等,這也是這種通信方式的缺點。如果頻繁的發(fā)生進程間的通信行為,那么進程需要頻繁地讀取隊列中的數(shù)據(jù)到內(nèi)存,相當于間接地從一個進程拷貝到另一個進程,這需要花費時間。

          (3)信號量通信

          共享內(nèi)存最大的問題就是多進程競爭內(nèi)存的問題,就像類似于線程安全問題。我們可以使用信號量來解決這個問題。信號量的本質(zhì)就是一個計數(shù)器,用來實現(xiàn)進程之間的互斥與同步。例如信號量的初始值是 1,然后 a 進程來訪問內(nèi)存1的時候,我們就把信號量的值設(shè)為 0,然后進程b 也要來訪問內(nèi)存1的時候,看到信號量的值為 0 就知道已經(jīng)有進程在訪問內(nèi)存1了,這個時候進程 b 就會訪問不了內(nèi)存1。所以說,信號量也是進程之間的一種通信方式。

          (4)信號通信

          信號(Signals )是Unix系統(tǒng)中使用的最古老的進程間通信的方法之一。操作系統(tǒng)通過信號來通知進程系統(tǒng)中發(fā)生了某種預(yù)先規(guī)定好的事件(一組事件中的一個),它也是用戶進程之間通信和同步的一種原始機制。

          (5)共享內(nèi)存通信

          共享內(nèi)存就是映射一段能被其他進程所訪問的內(nèi)存,這段共享內(nèi)存由一個進程創(chuàng)建,但多個進程都可以訪問(使多個進程可以訪問同一塊內(nèi)存空間)。共享內(nèi)存是最快的 IPC 方式,它是針對其他進程間通信方式運行效率低而專門設(shè)計的。它往往與其他通信機制,如信號量,配合使用,來實現(xiàn)進程間的同步和通信。

          (6)套接字通信

          上面我們說的共享內(nèi)存、管道、信號量、消息隊列,他們都是多個進程在一臺主機之間的通信,那兩個相隔幾千里的進程能夠進行通信嗎?答是必須的,這個時候 Socket 這家伙就派上用場了,例如我們平時通過瀏覽器發(fā)起一個 http 請求,然后服務(wù)器給你返回對應(yīng)的數(shù)據(jù),這種就是采用 Socket 的通信方式了。

          5. 僵尸進程和孤兒進程是什么?---了解即可(或者不需要看)

          孤兒進程:父進程退出了,而它的一個或多個進程還在運行,那這些子進程都會成為孤兒進程。孤兒進程將被init進程(進程號為1)所收養(yǎng),并由init進程對它們完成狀態(tài)收集工作。

          僵尸進程:子進程比父進程先結(jié)束,而父進程又沒有釋放子進程占用的資源,那么子進程的進程描述符仍然保存在系統(tǒng)中,這種進程稱之為僵死進程。

          6. 死鎖產(chǎn)生的原因? 如果解決死鎖的問題?---了解即可(或者不需要看)

          所謂死鎖,是指多個進程在運行過程中因爭奪資源而造成的一種僵局,當進程處于這種僵持狀態(tài)時,若無外力作用,它們都將無法再向前推進。

          系統(tǒng)中的資源可以分為兩類:

          可剝奪資源,是指某進程在獲得這類資源后,該資源可以再被其他進程或系統(tǒng)剝奪,CPU和主存均屬于可剝奪性資源;

          不可剝奪資源,當系統(tǒng)把這類資源分配給某進程后,再不能強行收回,只能在進程用完后自行釋放,如磁帶機、打印機等。

          產(chǎn)生死鎖的原因:

          (1)競爭資源

          產(chǎn)生死鎖中的競爭資源之一指的是競爭不可剝奪資源(例如:系統(tǒng)中只有一臺打印機,可供進程P1使用,假定P1已占用了打印機,若P2繼續(xù)要求打印機打印將阻塞)

          產(chǎn)生死鎖中的競爭資源另外一種資源指的是競爭臨時資源(臨時資源包括硬件中斷、信號、消息、緩沖區(qū)內(nèi)的消息等),通常消息通信順序進行不當,則會產(chǎn)生死鎖

          (2)進程間推進順序非法

          若P1保持了資源R1,P2保持了資源R2,系統(tǒng)處于不安全狀態(tài),因為這兩個進程再向前推進,便可能發(fā)生死鎖。例如,當P1運行到P1:Request(R2)時,將因R2已被P2占用而阻塞;當P2運行到P2:Request(R1)時,也將因R1已被P1占用而阻塞,于是發(fā)生進程死鎖

          產(chǎn)生死鎖的必要條件:

          互斥條件:進程要求對所分配的資源進行排它性控制,即在一段時間內(nèi)某資源僅為一進程所占用。

          請求和保持條件:當進程因請求資源而阻塞時,對已獲得的資源保持不放。

          不剝奪條件:進程已獲得的資源在未使用完之前,不能剝奪,只能在使用完時由自己釋放。

          環(huán)路等待條件:在發(fā)生死鎖時,必然存在一個進程——資源的環(huán)形鏈。

          預(yù)防死鎖的方法:

          資源一次性分配:一次性分配所有資源,這樣就不會再有請求了(破壞請求條件)

          只要有一個資源得不到分配,也不給這個進程分配其他的資源(破壞請保持條件)

          可剝奪資源:即當某進程獲得了部分資源,但得不到其它資源,則釋放已占有的資源(破壞不可剝奪條件)

          資源有序分配法:系統(tǒng)給每類資源賦予一個編號,每一個進程按編號遞增的順序請求資源,釋放則相反(破壞環(huán)路等待條件)

          7. 如何實現(xiàn)瀏覽器內(nèi)多個標簽頁之間的通信?

          實現(xiàn)多個標簽頁之間的通信,本質(zhì)上都是通過中介者模式來實現(xiàn)的。因為標簽頁之間沒有辦法直接通信,因此我們可以找一個中介者,讓標簽頁和中介者進行通信,然后讓這個中介者來進行消息的轉(zhuǎn)發(fā)。通信方法如下:

          使用 websocket 協(xié)議,因為 websocket 協(xié)議可以實現(xiàn)服務(wù)器推送,所以服務(wù)器就可以用來當做這個中介者。標簽頁通過向服務(wù)器發(fā)送數(shù)據(jù),然后由服務(wù)器向其他標簽頁推送轉(zhuǎn)發(fā)。

          使用 ShareWorker 的方式,shareWorker 會在頁面存在的生命周期內(nèi)創(chuàng)建一個唯一的線程,并且開啟多個頁面也只會使用同一個線程。這個時候共享線程就可以充當中介者的角色。標簽頁間通過共享一個線程,然后通過這個共享的線程來實現(xiàn)數(shù)據(jù)的交換。

          使****用 localStorage 的方式,我們可以在一個標簽頁對 localStorage 的變化事件進行監(jiān)聽,然后當另一個標簽頁修改數(shù)據(jù)的時候,我們就可以通過這個監(jiān)聽事件來獲取到數(shù)據(jù)。這個時候 localStorage 對象就是充當?shù)闹薪檎叩慕巧?/p>

          使用 postMessage 方法,如果我們能夠獲得對應(yīng)標簽頁的引用,就可以使用postMessage 方法,進行通信。

          8. 對Service Worker的理解

          Service Worker 是運行在瀏覽器背后的獨立線程,一般可以用來實現(xiàn)緩存功能。使用 Service Worker的話,傳輸協(xié)議必須為 HTTPS。因為 Service Worker 中涉及到請求攔截,所以必須使用 HTTPS 協(xié)議來保障安全。

          Service Worker 實現(xiàn)緩存功能一般分為三個步驟:首先需要先注冊 Service Worker,然后監(jiān)聽到 install 事件以后就可以緩存需要的文件,那么在下次用戶訪問的時候就可以通過攔截請求的方式查詢是否存在緩存,存在緩存的話就可以直接讀取緩存文件,否則就去請求數(shù)據(jù)。以下是這個步驟的實現(xiàn):

          // index.js

          if (navigator.serviceWorker) {

          navigator.serviceWorker

          .register('sw.js')

          .then(function(registration) {

          console.log('service worker 注冊成功')

          })

          .catch(function(err) {

          console.log('servcie worker 注冊失敗')

          })

          }

          // sw.js

          // 監(jiān)聽 `install` 事件,回調(diào)中緩存所需文件

          self.addEventListener('install', e=> {

          e.waitUntil(

          caches.open('my-cache').then(function(cache) {

          return cache.addAll(['./index.html', './index.js'])

          })

          )

          })

          // 攔截所有請求事件

          // 如果緩存中已經(jīng)有請求的數(shù)據(jù)就直接用緩存,否則去請求數(shù)據(jù)

          self.addEventListener('fetch', e=> {

          e.respondWith(

          caches.match(e.request).then(function(response) {

          if (response) {

          return response

          }

          console.log('fetch source')

          })

          )

          })

          打開頁面,可以在開發(fā)者工具中的 Application 看到 Service Worker 已經(jīng)啟動了:

          image

          在 Cache 中也可以發(fā)現(xiàn)所需的文件已被緩存:

          image

          三、瀏覽器緩存

          1. 對瀏覽器的緩存機制的理解

          瀏覽器緩存的全過程:

          瀏覽器第一次加載資源,服務(wù)器返回 200,瀏覽器從服務(wù)器下載資源文件,并緩存資源文件與 response header,以供下次加載時對比使用;

          下一次加載資源時,由于強制緩存優(yōu)先級較高,先比較當前時間與上一次返回 200 時的時間差,如果沒有超過 cache-control 設(shè)置的 max-age,則沒有過期,并命中強緩存,直接從本地讀取資源。如果瀏覽器不支持HTTP1.1,則使用 expires 頭判斷是否過期;

          如果資源已過期,則表明強制緩存沒有被命中,則開始協(xié)商緩存,向服務(wù)器發(fā)送帶有 If-None-Match 和 If-Modified-Since 的請求;

          服務(wù)器收到請求后,優(yōu)先根據(jù) Etag 的值判斷被請求的文件有沒有做修改,Etag 值一致則沒有修改,命中協(xié)商緩存,返回 304;如果不一致則有改動,直接返回新的資源文件帶上新的 Etag 值并返回 200;

          如果服務(wù)器收到的請求沒有 Etag 值,則將 If-Modified-Since 和被請求文件的最后修改時間做比對,一致則命中協(xié)商緩存,返回 304;不一致則返回新的 last-modified 和文件并返回 200;

          業(yè)務(wù)流程圖1.png

          很多網(wǎng)站的資源后面都加了版本號,這樣做的目的是:每次升級了 JS 或 CSS 文件后,為了防止瀏覽器進行緩存,強制改變版本號,客戶端瀏覽器就會重新下載新的 JS 或 CSS 文件 ,以保證用戶能夠及時獲得網(wǎng)站的最新更新。

          2. 瀏覽器資源緩存的位置有哪些?

          資源緩存的位置一共有 3 種,按優(yōu)先級從高到低分別是:

          Service Worker:Service Worker 運行在 JavaScript 主線程之外,雖然由于脫離了瀏覽器窗體無法直接訪問 DOM,但是它可以完成離線緩存、消息推送、網(wǎng)絡(luò)代理等功能。它可以讓我們自由控制緩存哪些文件、如何匹配緩存、如何讀取緩存,并且緩存是持續(xù)性的。當 Service Worker 沒有命中緩存的時候,需要去調(diào)用 fetch 函數(shù)獲取 數(shù)據(jù)。也就是說,如果沒有在 Service Worker 命中緩存,會根據(jù)緩存查找優(yōu)先級去查找數(shù)據(jù)。但是不管是從 Memory Cache 中還是從網(wǎng)絡(luò)請求中獲取的數(shù)據(jù),瀏覽器都會顯示是從 Service Worker 中獲取的內(nèi)容。

          **Memory Cache:**Memory Cache 就是內(nèi)存緩存,它的效率最快,**但是內(nèi)存緩存雖然讀取高效,可是緩存持續(xù)性很短,會隨著進程的釋放而釋放。**一旦我們關(guān)閉 Tab 頁面,內(nèi)存中的緩存也就被釋放了。

          **Disk Cache:**Disk Cache 也就是存儲在硬盤中的緩存,讀取速度慢點,但是什么都能存儲到磁盤中,比之 Memory Cache **勝在容量和存儲時效性上。**在所有瀏覽器緩存中,Disk Cache 覆蓋面基本是最大的。它會根據(jù) HTTP Herder 中的字段判斷哪些資源需要緩存,哪些資源可以不請求直接使用,哪些資源已經(jīng)過期需要重新請求。并且即使在跨站點的情況下,相同地址的資源一旦被硬盤緩存下來,就不會再次去請求數(shù)據(jù)。

          **Disk Cache:**Push Cache 是 HTTP/2 中的內(nèi)容,當以上三種緩存都沒有命中時,它才會被使用。**并且緩存時間也很短暫,只在會話(Session)中存在,一旦會話結(jié)束就被釋放。**其具有以下特點:

          所有的資源都能被推送,但是 Edge 和 Safari 瀏覽器兼容性不怎么好

          可以推送 no-cache 和 no-store 的資源

          一旦連接被關(guān)閉,Push Cache 就被釋放

          多個頁面可以使用相同的 HTTP/2 連接,也就是說能使用同樣的緩存

          Push Cache 中的緩存只能被使用一次

          瀏覽器可以拒絕接受已經(jīng)存在的資源推送

          可以給其他域名推送資源

          3. 協(xié)商緩存和強緩存的區(qū)別

          (1)強緩存

          使用強緩存策略時,如果緩存資源有效,則直接使用緩存資源,不必再向服務(wù)器發(fā)起請求。

          強緩存策略可以通過兩種方式來設(shè)置,分別是 http 頭信息中的 Expires 屬性和 Cache-Control 屬性。

          (1)服務(wù)器通過在響應(yīng)頭中添加 Expires 屬性,來指定資源的過期時間。在過期時間以內(nèi),該資源可以被緩存使用,不必再向服務(wù)器發(fā)送請求。這個時間是一個絕對時間,它是服務(wù)器的時間,因此可能存在這樣的問題,就是客戶端的時間和服務(wù)器端的時間不一致,或者用戶可以對客戶端時間進行修改的情況,這樣就可能會影響緩存命中的結(jié)果。

          (2)Expires 是 http1.0 中的方式,因為它的一些缺點,在 HTTP 1.1 中提出了一個新的頭部屬性就是 Cache-Control 屬性,它提供了對資源的緩存的更精確的控制。它有很多不同的值,

          Cache-Control可設(shè)置的字段:

          public:設(shè)置了該字段值的資源表示可以被任何對象(包括:發(fā)送請求的客戶端、代理服務(wù)器等等)緩存。這個字段值不常用,一般還是使用max-age=來精確控制;

          private:設(shè)置了該字段值的資源只能被用戶瀏覽器緩存,不允許任何代理服務(wù)器緩存。在實際開發(fā)當中,對于一些含有用戶信息的HTML,通常都要設(shè)置這個字段值,避免代理服務(wù)器(CDN)緩存;

          no-cache:設(shè)置了該字段需要先和服務(wù)端確認返回的資源是否發(fā)生了變化,如果資源未發(fā)生變化,則直接使用緩存好的資源;

          no-store:設(shè)置了該字段表示禁止任何緩存,每次都會向服務(wù)端發(fā)起新的請求,拉取最新的資源;

          max-age=:設(shè)置緩存的最大有效期,單位為秒;

          s-maxage=:優(yōu)先級高于max-age=,僅適用于共享緩存(CDN),優(yōu)先級高于max-age或者Expires頭;

          max-stale[=]:設(shè)置了該字段表明客戶端愿意接收已經(jīng)過期的資源,但是不能超過給定的時間限制。

          一般來說只需要設(shè)置其中一種方式就可以實現(xiàn)強緩存策略,當兩種方式一起使用時,Cache-Control 的優(yōu)先級要高于 Expires。

          no-cache和no-store很容易混淆:

          no-cache 是指先要和服務(wù)器確認是否有資源更新,在進行判斷。也就是說沒有強緩存,但是會有協(xié)商緩存;

          no-store 是指不使用任何緩存,每次請求都直接從服務(wù)器獲取資源。

          (2)協(xié)商緩存

          如果命中強制緩存,我們無需發(fā)起新的請求,直接使用緩存內(nèi)容,如果沒有命中強制緩存,如果設(shè)置了協(xié)商緩存,這個時候協(xié)商緩存就會發(fā)揮作用了。

          上面已經(jīng)說到了,命中協(xié)商緩存的條件有兩個:

          max-age=xxx 過期了

          值為no-store

          使用協(xié)商緩存策略時,會先向服務(wù)器發(fā)送一個請求,如果資源沒有發(fā)生修改,則返回一個 304 狀態(tài),讓瀏覽器使用本地的緩存副本。如果資源發(fā)生了修改,則返回修改后的資源。

          協(xié)商緩存也可以通過兩種方式來設(shè)置,分別是 http 頭信息中的 Etag 和 Last-Modified 屬性。

          (1)服務(wù)器通過在響應(yīng)頭中添加 Last-Modified 屬性來指出資源最后一次修改的時間,當瀏覽器下一次發(fā)起請求時,會在請求頭中添加一個 If-Modified-Since 的屬性,屬性值為上一次資源返回時的 Last-Modified 的值。當請求發(fā)送到服務(wù)器后服務(wù)器會通過這個屬性來和資源的最后一次的修改時間來進行比較,以此來判斷資源是否做了修改。如果資源沒有修改,那么返回 304 狀態(tài),讓客戶端使用本地的緩存。如果資源已經(jīng)被修改了,則返回修改后的資源。使用這種方法有一個缺點,就是 Last-Modified 標注的最后修改時間只能精確到秒級,如果某些文件在1秒鐘以內(nèi),被修改多次的話,那么文件已將改變了但是 Last-Modified 卻沒有改變,這樣會造成緩存命中的不準確。

          (2)因為 Last-Modified 的這種可能發(fā)生的不準確性,http 中提供了另外一種方式,那就是 Etag 屬性。服務(wù)器在返回資源的時候,在頭信息中添加了 Etag 屬性,這個屬性是資源生成的唯一標識符,當資源發(fā)生改變的時候,這個值也會發(fā)生改變。在下一次資源請求時,瀏覽器會在請求頭中添加一個 If-None-Match 屬性,這個屬性的值就是上次返回的資源的 Etag 的值。服務(wù)接收到請求后會根據(jù)這個值來和資源當前的 Etag 的值來進行比較,以此來判斷資源是否發(fā)生改變,是否需要返回資源。通過這種方式,比 Last-Modified 的方式更加精確。

          當 Last-Modified 和 Etag 屬性同時出現(xiàn)的時候,Etag 的優(yōu)先級更高。使用協(xié)商緩存的時候,服務(wù)器需要考慮負載平衡的問題,因此多個服務(wù)器上資源的 Last-Modified 應(yīng)該保持一致,因為每個服務(wù)器上 Etag 的值都不一樣,因此在考慮負載平衡時,最好不要設(shè)置 Etag 屬性。

          總結(jié):

          強緩存策略和協(xié)商緩存策略在緩存命中時都會直接使用本地的緩存副本,區(qū)別只在于協(xié)商緩存會向服務(wù)器發(fā)送一次請求。它們緩存不命中時,都會向服務(wù)器發(fā)送請求來獲取資源。在實際的緩存機制中,強緩存策略和協(xié)商緩存策略是一起合作使用的。瀏覽器首先會根據(jù)請求的信息判斷,強緩存是否命中,如果命中則直接使用資源。如果不命中則根據(jù)頭信息向服務(wù)器發(fā)起請求,使用協(xié)商緩存,如果協(xié)商緩存命中的話,則服務(wù)器不返回資源,瀏覽器直接使用本地資源的副本,如果協(xié)商緩存不命中,則瀏覽器返回最新的資源給瀏覽器。

          4. 為什么需要瀏覽器緩存?

          對于瀏覽器的緩存,主要針對的是前端的靜態(tài)資源,最好的效果就是,在發(fā)起請求之后,拉取相應(yīng)的靜態(tài)資源,并保存在本地。如果服務(wù)器的靜態(tài)資源沒有更新,那么在下次請求的時候,就直接從本地讀取即可,如果服務(wù)器的靜態(tài)資源已經(jīng)更新,那么我們再次請求的時候,就到服務(wù)器拉取新的資源,并保存在本地。這樣就大大的減少了請求的次數(shù),提高了網(wǎng)站的性能。這就要用到瀏覽器的緩存策略了。

          所謂的瀏覽器緩存指的是瀏覽器將用戶請求過的靜態(tài)資源,存儲到電腦本地磁盤中,當瀏覽器再次訪問時,就可以直接從本地加載,不需要再去服務(wù)端請求了。

          使用瀏覽器緩存,有以下優(yōu)點:

          減少了服務(wù)器的負擔(dān),提高了網(wǎng)站的性能

          加快了客戶端網(wǎng)頁的加載速度

          減少了多余網(wǎng)絡(luò)數(shù)據(jù)傳輸

          5. 點擊刷新按鈕或者按 F5、按 Ctrl+F5 (強制刷新)、地址欄回車有什么區(qū)別?

          **點擊刷新按鈕或者按 F5:**瀏覽器直接對本地的緩存文件過期,但是會帶上If-Modifed-Since,If-None-Match,這就意味著服務(wù)器會對文件檢查新鮮度,返回結(jié)果可能是 304,也有可能是 200。

          **用戶按 Ctrl+F5(強制刷新):**瀏覽器不僅會對本地文件過期,而且不會帶上 If-Modifed-Since,If-None-Match,相當于之前從來沒有請求過,返回結(jié)果是 200。

          地址欄回車: 瀏覽器發(fā)起請求,按照正常流程,本地檢查是否過期,然后服務(wù)器檢查新鮮度,最后返回內(nèi)容。

          四、瀏覽器組成

          1. 對瀏覽器的理解

          瀏覽器的主要功能是將用戶選擇的 web 資源呈現(xiàn)出來,它需要從服務(wù)器請求資源,并將其顯示在瀏覽器窗口中,資源的格式通常是 HTML,也包括 PDF、image 及其他格式。用戶用 URI(Uniform Resource Identifier 統(tǒng)一資源標識符)來指定所請求資源的位置。

          HTML 和 CSS 規(guī)范中規(guī)定了瀏覽器解釋 html 文檔的方式,由 W3C 組織對這些規(guī)范進行維護,W3C 是負責(zé)制定 web 標準的組織。但是瀏覽器廠商紛紛開發(fā)自己的擴展,對規(guī)范的遵循并不完善,這為 web 開發(fā)者帶來了嚴重的兼容性問題。

          瀏覽器可以分為兩部分,shell 和 內(nèi)核。其中 shell 的種類相對比較多,內(nèi)核則比較少。也有一些瀏覽器并不區(qū)分外殼和內(nèi)核。從 Mozilla 將 Gecko 獨立出來后,才有了外殼和內(nèi)核的明確劃分。

          shell 是指瀏覽器的外殼:例如菜單,工具欄等。主要是提供給用戶界面操作,參數(shù)設(shè)置等等。它是調(diào)用內(nèi)核來實現(xiàn)各種功能的。

          內(nèi)核是瀏覽器的核心。內(nèi)核是基于標記語言顯示內(nèi)容的程序或模塊。

          2. 對瀏覽器內(nèi)核的理解

          瀏覽器內(nèi)核主要分成兩部分:

          渲染引擎的職責(zé)就是渲染,即在瀏覽器窗口中顯示所請求的內(nèi)容。默認情況下,渲染引擎可以顯示 html、xml 文檔及圖片,它也可以借助插件顯示其他類型數(shù)據(jù),例如使用 PDF 閱讀器插件,可以顯示 PDF 格式。

          JS 引擎:解析和執(zhí)行 javascript 來實現(xiàn)網(wǎng)頁的動態(tài)效果。

          最開始渲染引擎和 JS 引擎并沒有區(qū)分的很明確,后來 JS 引擎越來越獨立,內(nèi)核就傾向于只指渲染引擎。

          3. 常見的瀏覽器內(nèi)核比較

          **Trident:**這種瀏覽器內(nèi)核是 IE 瀏覽器用的內(nèi)核,因為在早期 IE 占有大量的市場份額,所以這種內(nèi)核比較流行,以前有很多網(wǎng)頁也是根據(jù)這個內(nèi)核的標準來編寫的,但是實際上這個內(nèi)核對真正的網(wǎng)頁標準支持不是很好。但是由于 IE 的高市場占有率,微軟也很長時間沒有更新 Trident 內(nèi)核,就導(dǎo)致了 Trident 內(nèi)核和 W3C 標準脫節(jié)。還有就是 Trident 內(nèi)核的大量 Bug 等安全問題沒有得到解決,加上一些專家學(xué)者公開自己認為 IE 瀏覽器不安全的觀點,使很多用戶開始轉(zhuǎn)向其他瀏覽器。

          **Gecko:**這是 Firefox 和 Flock 所采用的內(nèi)核,這個內(nèi)核的優(yōu)點就是功能強大、豐富,可以支持很多復(fù)雜網(wǎng)頁效果和瀏覽器擴展接口,但是代價是也顯而易見就是要消耗很多的資源,比如內(nèi)存。

          **Presto:**Opera 曾經(jīng)采用的就是 Presto 內(nèi)核,Presto 內(nèi)核被稱為公認的瀏覽網(wǎng)頁速度最快的內(nèi)核,這得益于它在開發(fā)時的天生優(yōu)勢,在處理 JS 腳本等腳本語言時,會比其他的內(nèi)核快3倍左右,缺點就是為了達到很快的速度而丟掉了一部分網(wǎng)頁兼容性。

          **Webkit:**Webkit 是 Safari 采用的內(nèi)核,它的優(yōu)點就是網(wǎng)頁瀏覽速度較快,雖然不及 Presto 但是也勝于 Gecko 和 Trident,缺點是對于網(wǎng)頁代碼的容錯性不高,也就是說對網(wǎng)頁代碼的兼容性較低,會使一些編寫不標準的網(wǎng)頁無法正確顯示。WebKit 前身是 KDE 小組的 KHTML 引擎,可以說 WebKit 是 KHTML 的一個開源的分支。

          **Blink:**谷歌在 Chromium Blog 上發(fā)表博客,稱將與蘋果的開源瀏覽器核心 Webkit 分道揚鑣,在 Chromium 項目中研發(fā) Blink 渲染引擎(即瀏覽器核心),內(nèi)置于 Chrome 瀏覽器之中。其實 Blink 引擎就是 Webkit 的一個分支,就像 webkit 是KHTML 的分支一樣。Blink 引擎現(xiàn)在是谷歌公司與 Opera Software 共同研發(fā),上面提到過的,Opera 棄用了自己的 Presto 內(nèi)核,加入 Google 陣營,跟隨谷歌一起研發(fā) Blink。

          4. 常見瀏覽器所用內(nèi)核---了解即可

          (1) IE 瀏覽器內(nèi)核:Trident 內(nèi)核,也是俗稱的 IE 內(nèi)核;

          (2) Chrome 瀏覽器內(nèi)核:統(tǒng)稱為 Chromium 內(nèi)核或 Chrome 內(nèi)核,以前是 Webkit 內(nèi)核,現(xiàn)在是 Blink內(nèi)核;

          (3) Firefox 瀏覽器內(nèi)核:Gecko 內(nèi)核,俗稱 Firefox 內(nèi)核;

          (4) Safari 瀏覽器內(nèi)核:Webkit 內(nèi)核;

          (5) Opera 瀏覽器內(nèi)核:最初是自己的 Presto 內(nèi)核,后來加入谷歌大軍,從 Webkit 又到了 Blink 內(nèi)核;

          (6) 360瀏覽器、獵豹瀏覽器內(nèi)核:IE + Chrome 雙內(nèi)核;

          (7) 搜狗、遨游、QQ 瀏覽器內(nèi)核:Trident(兼容模式)+ Webkit(高速模式);

          (8) 百度瀏覽器、世界之窗內(nèi)核:IE 內(nèi)核;

          (9) 2345瀏覽器內(nèi)核:好像以前是 IE 內(nèi)核,現(xiàn)在也是 IE + Chrome 雙內(nèi)核了;

          (10)UC 瀏覽器內(nèi)核:這個眾口不一,UC 說是他們自己研發(fā)的 U3 內(nèi)核,但好像還是基于 Webkit 和 Trident ,還有說是基于火狐內(nèi)核。

          5. 瀏覽器的主要組成部分

          ?戶界? - 包括地址欄、前進/后退按鈕、書簽菜單等。除了瀏覽器主窗?顯示的您請求的??外,其他顯示的各個部分都屬于?戶界?。

          瀏覽器引擎 - 在?戶界?和呈現(xiàn)引擎之間傳送指令。

          呈現(xiàn)引擎 - 負責(zé)顯示請求的內(nèi)容。如果請求的內(nèi)容是 HTML,它就負責(zé)解析 HTML 和 CSS 內(nèi)容,并將解析后的內(nèi)容顯示在屏幕上。

          ?絡(luò) - ?于?絡(luò)調(diào)?,?如 HTTP 請求。其接?與平臺?關(guān),并為所有平臺提供底層實現(xiàn)。

          ?戶界?后端 - ?于繪制基本的窗??部件,?如組合框和窗?。其公開了與平臺?關(guān)的通?接?,?在底層使?操作系統(tǒng)的?戶界??法。

          JavaScript 解釋器。?于解析和執(zhí)? JavaScript 代碼。

          數(shù)據(jù)存儲 - 這是持久層。瀏覽器需要在硬盤上保存各種數(shù)據(jù),例如 Cookie。新的 HTML 規(guī)范 (HTML5) 定義了“?絡(luò)數(shù)據(jù)庫”,這是?個完整(但是輕便)的瀏覽器內(nèi)數(shù)據(jù)庫。

          值得注意的是,和?多數(shù)瀏覽器不同,Chrome 瀏覽器的每個標簽?都分別對應(yīng)?個呈現(xiàn)引擎實例。每個標簽?都是?個獨?的進程。

          五、瀏覽器渲染原理

          1. 瀏覽器的渲染過程

          瀏覽器渲染主要有以下步驟:

          首先解析收到的文檔,根據(jù)文檔定義構(gòu)建一棵 DOM 樹,DOM 樹是由 DOM 元素及屬性節(jié)點組成的。

          然后對 CSS 進行解析,生成 CSSOM 規(guī)則樹。

          根據(jù) DOM 樹和 CSSOM 規(guī)則樹構(gòu)建渲染樹。渲染樹的節(jié)點被稱為渲染對象,渲染對象是一個包含有顏色和大小等屬性的矩形,渲染對象和 DOM 元素相對應(yīng),但這種對應(yīng)關(guān)系不是一對一的,不可見的 DOM 元素不會被插入渲染樹。還有一些 DOM元素對應(yīng)幾個可見對象,它們一般是一些具有復(fù)雜結(jié)構(gòu)的元素,無法用一個矩形來描述。

          當渲染對象被創(chuàng)建并添加到樹中,它們并沒有位置和大小,所以當瀏覽器生成渲染樹以后,就會根據(jù)渲染樹來進行布局(也可以叫做回流)。這一階段瀏覽器要做的事情是要弄清楚各個節(jié)點在頁面中的確切位置和大小。通常這一行為也被稱為“自動重排”。

          布局階段結(jié)束后是繪制階段,遍歷渲染樹并調(diào)用渲染對象的 paint 方法將它們的內(nèi)容顯示在屏幕上,繪制使用 UI 基礎(chǔ)組件。

          大致過程如圖所示:

          image

          **注意:**這個過程是逐步完成的,為了更好的用戶體驗,渲染引擎將會盡可能早的將內(nèi)容呈現(xiàn)到屏幕上,并不會等到所有的html 都解析完成之后再去構(gòu)建和布局 render 樹。它是解析完一部分內(nèi)容就顯示一部分內(nèi)容,同時,可能還在通過網(wǎng)絡(luò)下載其余內(nèi)容。

          2. 瀏覽器渲染優(yōu)化

          **(1)針對JavaScript:**JavaScript既會阻塞HTML的解析,也會阻塞CSS的解析。因此我們可以對JavaScript的加載方式進行改變,來進行優(yōu)化:

          (1)盡量將JavaScript文件放在body的最后

          (2) body中間盡量不要寫<script>標簽

          (3)<script>標簽的引入資源方式有三種,有一種就是我們常用的直接引入,還有兩種就是使用 async 屬性和 defer 屬性來異步引入,兩者都是去異步加載外部的JS文件,不會阻塞DOM的解析(盡量使用異步加載)。三者的區(qū)別如下:

          script 立即停止頁面渲染去加載資源文件,當資源加載完畢后立即執(zhí)行js代碼,js代碼執(zhí)行完畢后繼續(xù)渲染頁面;

          async 是在下載完成之后,立即異步加載,加載好后立即執(zhí)行,多個帶async屬性的標簽,不能保證加載的順序;

          defer 是在下載完成之后,立即異步加載。加載好后,如果 DOM 樹還沒構(gòu)建好,則先等 DOM 樹解析好再執(zhí)行;如果DOM樹已經(jīng)準備好,則立即執(zhí)行。多個帶defer屬性的標簽,按照順序執(zhí)行。

          (2)針對CSS:使用CSS有三種方式:使用link、@import、內(nèi)聯(lián)樣式,其中l(wèi)ink和@import都是導(dǎo)入外部樣式。它們之間的區(qū)別:

          link:瀏覽器會派發(fā)一個新等線程(HTTP線程)去加載資源文件,與此同時GUI渲染線程會繼續(xù)向下渲染代碼

          @import:GUI渲染線程會暫時停止渲染,去服務(wù)器加載資源文件,資源文件沒有返回之前不會繼續(xù)渲染(阻礙瀏覽器渲染)

          style:GUI直接渲染

          外部樣式如果長時間沒有加載完畢,瀏覽器為了用戶體驗,會使用瀏覽器會默認樣式,確保首次渲染的速度。所以CSS一般寫在headr中,讓瀏覽器盡快發(fā)送請求去獲取css樣式。

          所以,在開發(fā)過程中,導(dǎo)入外部樣式使用link,而不用@import。如果css少,盡可能采用內(nèi)嵌樣式,直接寫在style標簽中。

          (3)針對DOM樹、CSSOM樹:

          可以通過以下幾種方式來減少渲染的時間:

          HTML文件的代碼層級盡量不要太深

          使用語義化的標簽,來避免不標準語義化的特殊處理

          減少CSSD代碼的層級,因為選擇器是從左向右進行解析的

          (4)減少回流與重繪:

          操作DOM時,盡量在低層級的DOM節(jié)點進行操作

          不要使用table布局, 一個小的改動可能會使整個table進行重新布局

          使用CSS的表達式

          不要頻繁操作元素的樣式,對于靜態(tài)頁面,可以修改類名,而不是樣式。

          使用absolute或者fixed,使元素脫離文檔流,這樣他們發(fā)生變化就不會影響其他元素

          避免頻繁操作DOM,可以創(chuàng)建一個文檔片段documentFragment,在它上面應(yīng)用所有DOM操作,最后再把它添加到文檔中

          將元素先設(shè)置display: none,操作結(jié)束后再把它顯示出來。因為在display屬性為none的元素上進行的DOM操作不會引發(fā)回流和重繪。

          將DOM的多個讀操作(或者寫操作)放在一起,而不是讀寫操作穿插著寫。這得益于瀏覽器的渲染隊列機制。

          瀏覽器針對頁面的回流與重繪,進行了自身的優(yōu)化——渲染隊列

          瀏覽器會將所有的回流、重繪的操作放在一個隊列中,當隊列中的操作到了一定的數(shù)量或者到了一定的時間間隔,瀏覽器就會對隊列進行批處理。這樣就會讓多次的回流、重繪變成一次回流重繪。

          將多個讀操作(或者寫操作)放在一起,就會等所有的讀操作進入隊列之后執(zhí)行,這樣,原本應(yīng)該是觸發(fā)多次回流,變成了只觸發(fā)一次回流。

          3. 渲染過程中遇到 JS 文件如何處理?

          JavaScript 的加載、解析與執(zhí)行會阻塞文檔的解析,也就是說,在構(gòu)建 DOM 時,HTML 解析器若遇到了 JavaScript,那么它會暫停文檔的解析,將控制權(quán)移交給 JavaScript 引擎,等 JavaScript 引擎運行完畢,瀏覽器再從中斷的地方恢復(fù)繼續(xù)解析文檔。也就是說,如果想要首屏渲染的越快,就越不應(yīng)該在首屏就加載 JS 文件,這也是都建議將 script 標簽放在 body 標簽底部的原因。當然在當下,并不是說 script 標簽必須放在底部,因為你可以給 script 標簽添加 defer 或者 async 屬性。

          4. 什么是文檔的預(yù)解析?

          Webkit 和 Firefox 都做了這個優(yōu)化,當執(zhí)行 JavaScript 腳本時,另一個線程解析剩下的文檔,并加載后面需要通過網(wǎng)絡(luò)加載的資源。這種方式可以使資源并行加載從而使整體速度更快。需要注意的是,預(yù)解析并不改變 DOM 樹,它將這個工作留給主解析過程,自己只解析外部資源的引用,比如外部腳本、樣式表及圖片。

          5. CSS 如何阻塞文檔解析?

          理論上,既然樣式表不改變 DOM 樹,也就沒有必要停下文檔的解析等待它們。然而,存在一個問題,JavaScript 腳本執(zhí)行時可能在文檔的解析過程中請求樣式信息,如果樣式還沒有加載和解析,腳本將得到錯誤的值,顯然這將會導(dǎo)致很多問題。所以如果瀏覽器尚未完成 CSSOM 的下載和構(gòu)建,而我們卻想在此時運行腳本,那么瀏覽器將延遲 JavaScript 腳本執(zhí)行和文檔的解析,直至其完成 CSSOM 的下載和構(gòu)建。也就是說,在這種情況下,瀏覽器會先下載和構(gòu)建 CSSOM,然后再執(zhí)行 JavaScript,最后再繼續(xù)文檔的解析。

          6. 如何優(yōu)化關(guān)鍵渲染路徑?

          為盡快完成首次渲染,我們需要最大限度減小以下三種可變因素:

          (1)關(guān)鍵資源的數(shù)量。

          (2)關(guān)鍵路徑長度。

          (3)關(guān)鍵字節(jié)的數(shù)量。

          關(guān)鍵資源是可能阻止網(wǎng)頁首次渲染的資源。這些資源越少,瀏覽器的工作量就越小,對 CPU 以及其他資源的占用也就越少。同樣,關(guān)鍵路徑長度受所有關(guān)鍵資源與其字節(jié)大小之間依賴關(guān)系圖的影響:某些資源只能在上一資源處理完畢之后才能開始下載,并且資源越大,下載所需的往返次數(shù)就越多。最后,瀏覽器需要下載的關(guān)鍵字節(jié)越少,處理內(nèi)容并讓其出現(xiàn)在屏幕上的速度就越快。要減少字節(jié)數(shù),我們可以減少資源數(shù)(將它們刪除或設(shè)為非關(guān)鍵資源),此外還要壓縮和優(yōu)化各項資源,確保最大限度減小傳送大小。

          優(yōu)化關(guān)鍵渲染路徑的常規(guī)步驟如下:

          (1)對關(guān)鍵路徑進行分析和特性描述:資源數(shù)、字節(jié)數(shù)、長度。

          (2)最大限度減少關(guān)鍵資源的數(shù)量:刪除它們,延遲它們的下載,將它們標記為異步等。

          (3)優(yōu)化關(guān)鍵字節(jié)數(shù)以縮短下載時間(往返次數(shù))。

          (4)優(yōu)化其余關(guān)鍵資源的加載順序:您需要盡早下載所有關(guān)鍵資產(chǎn),以縮短關(guān)鍵路徑長度

          7. 什么情況會阻塞渲染?

          首先渲染的前提是生成渲染樹,所以 HTML 和 CSS 肯定會阻塞渲染。如果你想渲染的越快,你越應(yīng)該降低一開始需要渲染的文件大小,并且扁平層級,優(yōu)化選擇器。然后當瀏覽器在解析到 script 標簽時,會暫停構(gòu)建 DOM,完成后才會從暫停的地方重新開始。也就是說,如果你想首屏渲染的越快,就越不應(yīng)該在首屏就加載 JS 文件,這也是都建議將 script 標簽放在 body 標簽底部的原因。

          當然在當下,并不是說 script 標簽必須放在底部,因為你可以給 script 標簽添加 defer 或者 async 屬性。當 script 標簽加上 defer 屬性以后,表示該 JS 文件會并行下載,但是會放到 HTML 解析完成后順序執(zhí)行,所以對于這種情況你可以把 script 標簽放在任意位置。對于沒有任何依賴的 JS 文件可以加上 async 屬性,表示 JS 文件下載和解析不會阻塞渲染。

          六、瀏覽器本地存儲

          1. 瀏覽器本地存儲方式及使用場景

          (1)Cookie

          Cookie是最早被提出來的本地存儲方式,在此之前,服務(wù)端是無法判斷網(wǎng)絡(luò)中的兩個請求是否是同一用戶發(fā)起的,為解決這個問題,Cookie就出現(xiàn)了。Cookie的大小只有4kb,它是一種純文本文件,每次發(fā)起HTTP請求都會攜帶Cookie。

          Cookie的特性:

          Cookie一旦創(chuàng)建成功,名稱就無法修改

          Cookie是無法跨域名的,也就是說a域名和b域名下的cookie是無法共享的,這也是由Cookie的隱私安全性決定的,這樣就能夠阻止非法獲取其他網(wǎng)站的Cookie

          每個域名下Cookie的數(shù)量不能超過20個,每個Cookie的大小不能超過4kb

          有安全問題,如果Cookie被攔截了,那就可獲得session的所有信息,即使加密也于事無補,無需知道cookie的意義,只要轉(zhuǎn)發(fā)cookie就能達到目的

          Cookie在請求一個新的頁面的時候都會被發(fā)送過去

          如果需要域名之間跨域共享Cookie,有兩種方法:

          使用Nginx反向代理

          在一個站點登陸之后,往其他網(wǎng)站寫Cookie。服務(wù)端的Session存儲到一個節(jié)點,Cookie存儲sessionId

          Cookie的使用場景:

          最常見的使用場景就是Cookie和session結(jié)合使用,我們將sessionId存儲到Cookie中,每次發(fā)請求都會攜帶這個sessionId,這樣服務(wù)端就知道是誰發(fā)起的請求,從而響應(yīng)相應(yīng)的信息。

          可以用來統(tǒng)計頁面的點擊次數(shù)

          (2)LocalStorage

          LocalStorage是HTML5新引入的特性,由于有的時候我們存儲的信息較大,Cookie就不能滿足我們的需求,這時候LocalStorage就派上用場了。

          LocalStorage的優(yōu)點:

          在大小方面,LocalStorage的大小一般為5MB,可以儲存更多的信息

          LocalStorage是持久儲存,并不會隨著頁面的關(guān)閉而消失,除非主動清理,不然會永久存在

          僅儲存在本地,不像Cookie那樣每次HTTP請求都會被攜帶

          LocalStorage的缺點:

          存在瀏覽器兼容問題,IE8以下版本的瀏覽器不支持

          如果瀏覽器設(shè)置為隱私模式,那我們將無法讀取到LocalStorage

          LocalStorage受到同源策略的限制,即端口、協(xié)議、主機地址有任何一個不相同,都不會訪問

          LocalStorage的****常用API:

          // 保存數(shù)據(jù)到 localStorage

          localStorage.setItem('key', 'value');

          // 從 localStorage 獲取數(shù)據(jù)

          let data=localStorage.getItem('key');

          // 從 localStorage 刪除保存的數(shù)據(jù)

          localStorage.removeItem('key');

          // 從 localStorage 刪除所有保存的數(shù)據(jù)

          localStorage.clear();

          // 獲取某個索引的Key

          localStorage.key(index)

          LocalStorage的****使用場景:

          有些網(wǎng)站有換膚的功能,這時候就可以將換膚的信息存儲在本地的LocalStorage中,當需要換膚的時候,直接操作LocalStorage即可

          在網(wǎng)站中的用戶瀏覽信息也會存儲在LocalStorage中,還有網(wǎng)站的一些不常變動的個人信息等也可以存儲在本地的LocalStorage中

          (3)SessionStorage

          SessionStorage和LocalStorage都是在HTML5才提出來的存儲方案,SessionStorage 主要用于臨時保存同一窗口(或標簽頁)的數(shù)據(jù),刷新頁面時不會刪除,關(guān)閉窗口或標簽頁之后將會刪除這些數(shù)據(jù)。

          SessionStorage****與LocalStorage對比:

          SessionStorage和LocalStorage都在本地進行數(shù)據(jù)存儲;

          SessionStorage也有同源策略的限制,但是SessionStorage有一條更加嚴格的限制,SessionStorage只有在同一瀏覽器的同一窗口下才能夠共享;

          LocalStorage和SessionStorage都不能被爬蟲爬取;

          SessionStorage的****常用API:

          // 保存數(shù)據(jù)到 sessionStorage

          sessionStorage.setItem('key', 'value');

          // 從 sessionStorage 獲取數(shù)據(jù)

          let data=sessionStorage.getItem('key');

          // 從 sessionStorage 刪除保存的數(shù)據(jù)

          sessionStorage.removeItem('key');

          // 從 sessionStorage 刪除所有保存的數(shù)據(jù)

          sessionStorage.clear();

          // 獲取某個索引的Key

          sessionStorage.key(index)

          SessionStorage的****使用場景

          由于SessionStorage具有時效性,所以可以用來存儲一些網(wǎng)站的游客登錄的信息,還有臨時的瀏覽記錄的信息。當關(guān)閉網(wǎng)站之后,這些信息也就隨之消除了。

          2. Cookie有哪些字段,作用分別是什么

          Cookie由以下字段組成:

          Name:cookie的名稱

          Value:cookie的值,對于認證cookie,value值包括web服務(wù)器所提供的訪問令牌;

          Size: cookie的大小

          Path:可以訪問此cookie的頁面路徑。 比如domain是abc.com,path是/test,那么只有/test路徑下的頁面可以讀取此cookie。

          Secure: 指定是否使用HTTPS安全協(xié)議發(fā)送Cookie。使用HTTPS安全協(xié)議,可以保護Cookie在瀏覽器和Web服務(wù)器間的傳輸過程中不被竊取和篡改。該方法也可用于Web站點的身份鑒別,即在HTTPS的連接建立階段,瀏覽器會檢查Web網(wǎng)站的SSL證書的有效性。但是基于兼容性的原因(比如有些網(wǎng)站使用自簽署的證書)在檢測到SSL證書無效時,瀏覽器并不會立即終止用戶的連接請求,而是顯示安全風(fēng)險信息,用戶仍可以選擇繼續(xù)訪問該站點。

          Domain:可以訪問該cookie的域名,Cookie 機制并未遵循嚴格的同源策略,允許一個子域可以設(shè)置或獲取其父域的 Cookie。當需要實現(xiàn)單點登錄方案時,Cookie 的上述特性非常有用,然而也增加了 Cookie受攻擊的危險,比如攻擊者可以借此發(fā)動會話定置攻擊。因而,瀏覽器禁止在 Domain 屬性中設(shè)置.org、.com 等通用頂級域名、以及在國家及地區(qū)頂級域下注冊的二級域名,以減小攻擊發(fā)生的范圍。

          HTTP: 該字段包含HTTPOnly 屬性 ,該屬性用來設(shè)置cookie能否通過腳本來訪問,默認為空,即可以通過腳本訪問。在客戶端是不能通過js代碼去設(shè)置一個httpOnly類型的cookie的,這種類型的cookie只能通過服務(wù)端來設(shè)置。該屬性用于防止客戶端腳本通過document.cookie屬性訪問Cookie,有助于保護Cookie不被跨站腳本攻擊竊取或篡改。但是,HTTPOnly的應(yīng)用仍存在局限性,一些瀏覽器可以阻止客戶端腳本對Cookie的讀操作,但允許寫操作;此外大多數(shù)瀏覽器仍允許通過XMLHTTP對象讀取HTTP響應(yīng)中的Set-Cookie頭。

          Expires/Max-size : 此cookie的超時時間。若設(shè)置其值為一個時間,那么當?shù)竭_此時間后,此cookie失效。不設(shè)置的話默認值是Session,意思是cookie會和session一起失效。當瀏覽器關(guān)閉(不是瀏覽器標簽頁,而是整個瀏覽器) 后,此cookie失效。

          總結(jié):

          服務(wù)器端可以使用 Set-Cookie 的響應(yīng)頭部來配置 cookie 信息。一條cookie 包括了5個屬性值 expires、domain、path、secure、HttpOnly。其中 expires 指定了 cookie 失效的時間,domain 是域名、path是路徑,domain 和 path 一起限制了 cookie 能夠被哪些 url 訪問。secure 規(guī)定了 cookie 只能在確保安全的情況下傳輸,HttpOnly 規(guī)定了這個 cookie 只能被服務(wù)器訪問,不能使用 js 腳本訪問。

          3. Cookie、LocalStorage、SessionStorage區(qū)別

          瀏覽器端常用的存儲技術(shù)是 cookie 、localStorage 和 sessionStorage。

          **cookie:**其實最開始是服務(wù)器端用于記錄用戶狀態(tài)的一種方式,由服務(wù)器設(shè)置,在客戶端存儲,然后每次發(fā)起同源請求時,發(fā)送給服務(wù)器端。cookie 最多能存儲 4 k 數(shù)據(jù),它的生存時間由 expires 屬性指定,并且 cookie 只能被同源的頁面訪問共享。

          **sessionStorage:**html5 提供的一種瀏覽器本地存儲的方法,它借鑒了服務(wù)器端 session 的概念,代表的是一次會話中所保存的數(shù)據(jù)。它一般能夠存儲 5M 或者更大的數(shù)據(jù),它在當前窗口關(guān)閉后就失效了,并且 sessionStorage 只能被同一個窗口的同源頁面所訪問共享。

          **localStorage:**html5 提供的一種瀏覽器本地存儲的方法,它一般也能夠存儲 5M 或者更大的數(shù)據(jù)。它和 sessionStorage 不同的是,除非手動刪除它,否則它不會失效,并且 localStorage 也只能被同源頁面所訪問共享。

          上面幾種方式都是存儲少量數(shù)據(jù)的時候的存儲方式,當需要在本地存儲大量數(shù)據(jù)的時候,我們可以使用瀏覽器的 indexDB 這是瀏覽器提供的一種本地的數(shù)據(jù)庫存儲機制。它不是關(guān)系型數(shù)據(jù)庫,它內(nèi)部采用對象倉庫的形式存儲數(shù)據(jù),它更接近 NoSQL 數(shù)據(jù)庫。

          4. 前端儲存的?式有哪些?

          cookies: 在HTML5標準前本地儲存的主要?式,優(yōu)點是兼容性好,請求頭?帶cookie?便,缺點是??只有4k,?動請求頭加?cookie浪費流量,每個domain限制20個cookie,使?起來麻煩,需要??封裝;

          localStorage:HTML5加?的以鍵值對(Key-Value)為標準的?式,優(yōu)點是操作?便,永久性儲存(除??動刪除),??為5M,兼容IE8+ ;

          sessionStorage:與localStorage基本類似,區(qū)別是sessionStorage當??關(guān)閉后會被清理,?且與cookie、localStorage不同,他不能在所有同源窗?中共享,是會話級別的儲存?式;

          Web SQL:2010年被W3C廢棄的本地數(shù)據(jù)庫數(shù)據(jù)存儲?案,但是主流瀏覽器(?狐除外)都已經(jīng)有了相關(guān)的實現(xiàn),web sql類似于SQLite,是真正意義上的關(guān)系型數(shù)據(jù)庫,?sql進?操作,當我們?JavaScript時要進?轉(zhuǎn)換,較為繁瑣;

          IndexedDB: 是被正式納?HTML5標準的數(shù)據(jù)庫儲存?案,它是NoSQL數(shù)據(jù)庫,?鍵值對進?儲存,可以進?快速讀取操作,?常適合web場景,同時?JavaScript進?操作會?常便。

          5. IndexedDB有哪些特點?---了解即可

          IndexedDB 具有以下特點:

          鍵值對儲存:IndexedDB 內(nèi)部采用對象倉庫(object store)存放數(shù)據(jù)。所有類型的數(shù)據(jù)都可以直接存入,包括 JavaScript 對象。對象倉庫中,數(shù)據(jù)以"鍵值對"的形式保存,每一個數(shù)據(jù)記錄都有對應(yīng)的主鍵,主鍵是獨一無二的,不能有重復(fù),否則會拋出一個錯誤。

          異步:IndexedDB 操作時不會鎖死瀏覽器,用戶依然可以進行其他操作,這與 LocalStorage 形成對比,后者的操作是同步的。異步設(shè)計是為了防止大量數(shù)據(jù)的讀寫,拖慢網(wǎng)頁的表現(xiàn)。

          支持事務(wù):IndexedDB 支持事務(wù)(transaction),這意味著一系列操作步驟之中,只要有一步失敗,整個事務(wù)就都取消,數(shù)據(jù)庫回滾到事務(wù)發(fā)生之前的狀態(tài),不存在只改寫一部分數(shù)據(jù)的情況。

          **同源限制:**IndexedDB 受到同源限制,每一個數(shù)據(jù)庫對應(yīng)創(chuàng)建它的域名。網(wǎng)頁只能訪問自身域名下的數(shù)據(jù)庫,而不能訪問跨域的數(shù)據(jù)庫。

          儲存空間大:IndexedDB 的儲存空間比 LocalStorage 大得多,一般來說不少于 250MB,甚至沒有上限。

          支持二進制儲存:IndexedDB 不僅可以儲存字符串,還可以儲存二進制數(shù)據(jù)(ArrayBuffer 對象和 Blob 對象)。

          七、瀏覽器同源策略

          1. 什么是同源策略

          跨域問題其實就是瀏覽器的同源策略造成的。

          同源策略限制了從同一個源加載的文檔或腳本如何與另一個源的資源進行交互。這是瀏覽器的一個用于隔離潛在惡意文件的重要的安全機制。同源指的是:協(xié)議、端口號、域名必須一致。

          下表給出了與 URL http://store.company.com/dir/page.html 的源進行對比的示例:

          URL 是否跨域 原因

          http://store.company.com/dir/page.html 同源 完全相同

          http://store.company.com/dir/inner/another.html 同源 只有路徑不同

          https://store.company.com/secure.html 跨域 協(xié)議不同

          http://store.company.com:81/dir/etc.html 跨域 端口不同 ( http:// 默認端口是80)

          http://news.company.com/dir/other.html 跨域 主機不同

          同源策略:protocol(協(xié)議)、domain(域名)、port(端口)三者必須一致。

          同源政策主要限制了三個方面:

          當前域下的 js 腳本不能夠訪問其他域下的 cookie、localStorage 和 indexDB。

          當前域下的 js 腳本不能夠操作訪問操作其他域下的 DOM。

          當前域下 ajax 無法發(fā)送跨域請求。

          同源政策的目的主要是為了保證用戶的信息安全,它只是對 js 腳本的一種限制,并不是對瀏覽器的限制,對于一般的 img、或者script 腳本請求都不會有跨域的限制,這是因為這些操作都不會通過響應(yīng)結(jié)果來進行可能出現(xiàn)安全問題的操作。

          2. 如何解決跨越問題

          (1)CORS

          下面是MDN對于CORS的定義:

          跨域資源共享(CORS) 是一種機制,它使用額外的 HTTP 頭來告訴瀏覽器 讓運行在一個 origin (domain)上的Web應(yīng)用被準許訪問來自不同源服務(wù)器上的指定的資源。當一個資源從與該資源本身所在的服務(wù)器不同的域、協(xié)議或端口請求一個資源時,資源會發(fā)起一個跨域HTTP 請求。

          CORS需要瀏覽器和服務(wù)器同時支持,整個CORS過程都是瀏覽器完成的,無需用戶參與。因此實現(xiàn)CORS的關(guān)鍵就是服務(wù)器,只要服務(wù)器實現(xiàn)了CORS請求,就可以跨源通信了。

          瀏覽器將CORS分為簡單請求和非簡單請求:

          簡單請求不會觸發(fā)CORS預(yù)檢請求。若該請求滿足以下兩個條件,就可以看作是簡單請求:

          1)請求方法是以下三種方法之一:

          HEAD

          GET

          POST

          2)HTTP的頭信息不超出以下幾種字段:

          Accept

          Accept-Language

          Content-Language

          Last-Event-ID

          Content-Type:只限于三個值application/x-www-form-urlencoded、multipart/form-data、text/plain

          若不滿足以上條件,就屬于非簡單請求了。

          (1)簡單請求過程:

          對于簡單請求,瀏覽器會直接發(fā)出CORS請求,它會在請求的頭信息中增加一個Orign字段,該字段用來說明本次請求來自哪個源(協(xié)議+端口+域名),服務(wù)器會根據(jù)這個值來決定是否同意這次請求。如果Orign指定的域名在許可范圍之內(nèi),服務(wù)器返回的響應(yīng)就會多出以下信息頭:

          Access-Control-Allow-Origin: http://api.bob.com // 和Orign一直

          Access-Control-Allow-Credentials: true // 表示是否允許發(fā)送Cookie

          Access-Control-Expose-Headers: FooBar // 指定返回其他字段的值

          Content-Type: text/html; charset=utf-8 // 表示文檔類型

          如果Orign指定的域名不在許可范圍之內(nèi),服務(wù)器會返回一個正常的HTTP回應(yīng),瀏覽器發(fā)現(xiàn)沒有上面的Access-Control-Allow-Origin頭部信息,就知道出錯了。這個錯誤無法通過狀態(tài)碼識別,因為返回的狀態(tài)碼可能是200。

          在簡單請求中,在服務(wù)器內(nèi),至少需要設(shè)置字段:**Access-Control-Allow-Origin**

          (2)非簡單請求過程

          非簡單請求是對服務(wù)器有特殊要求的請求,比如請求方法為DELETE或者PUT等。非簡單請求的CORS請求會在正式通信之前進行一次HTTP查詢請求,稱為預(yù)檢請求。

          瀏覽器會詢問服務(wù)器,當前所在的網(wǎng)頁是否在服務(wù)器允許訪問的范圍內(nèi),以及可以使用哪些HTTP請求方式和頭信息字段,只有得到肯定的回復(fù),才會進行正式的HTTP請求,否則就會報錯。

          預(yù)檢請求使用的請求方法是OPTIONS,表示這個請求是來詢問的。他的頭信息中的關(guān)鍵字段是Orign,表示請求來自哪個源。除此之外,頭信息中還包括兩個字段:

          Access-Control-Request-Method:該字段是必須的,用來列出瀏覽器的CORS請求會用到哪些HTTP方法。

          Access-Control-Request-Headers: 該字段是一個逗號分隔的字符串,指定瀏覽器CORS請求會額外發(fā)送的頭信息字段。

          服務(wù)器在收到瀏覽器的預(yù)檢請求之后,會根據(jù)頭信息的三個字段來進行判斷,如果返回的頭信息在中有Access-Control-Allow-Origin這個字段就是允許跨域請求,如果沒有,就是不同意這個預(yù)檢請求,就會報錯。

          服務(wù)器回應(yīng)的CORS的字段如下:

          Access-Control-Allow-Origin: http://api.bob.com // 允許跨域的源地址

          Access-Control-Allow-Methods: GET, POST, PUT // 服務(wù)器支持的所有跨域請求的方法

          Access-Control-Allow-Headers: X-Custom-Header // 服務(wù)器支持的所有頭信息字段

          Access-Control-Allow-Credentials: true // 表示是否允許發(fā)送Cookie

          Access-Control-Max-Age: 1728000 // 用來指定本次預(yù)檢請求的有效期,單位為秒

          只要服務(wù)器通過了預(yù)檢請求,在以后每次的CORS請求都會自帶一個Origin頭信息字段。服務(wù)器的回應(yīng),也都會有一個Access-Control-Allow-Origin頭信息字段。

          在非簡單請求中,至少需要設(shè)置以下字段:

          'Access-Control-Allow-Origin'

          'Access-Control-Allow-Methods'

          'Access-Control-Allow-Headers'

          減少OPTIONS請求次數(shù):

          OPTIONS請求次數(shù)過多就會損耗頁面加載的性能,降低用戶體驗度。所以盡量要減少OPTIONS請求次數(shù),可以后端在請求的返回頭部添加:Access-Control-Max-Age:number。它表示預(yù)檢請求的返回結(jié)果可以被緩存多久,單位是秒。該字段只對完全一樣的URL的緩存設(shè)置生效,所以設(shè)置了緩存時間,在這個時間范圍內(nèi),再次發(fā)送請求就不需要進行預(yù)檢請求了。

          CORS中Cookie相關(guān)問題:

          在CORS請求中,如果想要傳遞Cookie,就要滿足以下三個條件:

          在請求中設(shè)置 **withCredentials**

          默認情況下在跨域請求,瀏覽器是不帶 cookie 的。但是我們可以通過設(shè)置 withCredentials 來進行傳遞 cookie.

          // 原生 xml 的設(shè)置方式

          var xhr=new XMLHttpRequest();

          xhr.withCredentials=true;

          // axios 設(shè)置方式

          axios.defaults.withCredentials=true;

          Access-Control-Allow-Credentials 設(shè)置為 true

          Access-Control-Allow-Origin 設(shè)置為非 *****

          (2)JSONP

          jsonp的原理就是利用<script>標簽沒有跨域限制,通過<script>標簽src屬性,發(fā)送帶有callback參數(shù)的GET請求,服務(wù)端將接口返回數(shù)據(jù)拼湊到callback函數(shù)中,返回給瀏覽器,瀏覽器解析執(zhí)行,從而前端拿到callback函數(shù)返回的數(shù)據(jù)。

          1)原生JS實現(xiàn):

          <script>

          var script=document.createElement('script');

          script.type='text/javascript';

          // 傳參一個回調(diào)函數(shù)名給后端,方便后端返回時執(zhí)行這個在前端定義的回調(diào)函數(shù)

          script.src='http://www.domain2.com:8080/login?user=admin&callback=handleCallback';

          document.head.appendChild(script);

          // 回調(diào)執(zhí)行函數(shù)

          function handleCallback(res) {

          alert(JSON.stringify(res));

          }

          </script>

          服務(wù)端返回如下(返回時即執(zhí)行全局函數(shù)):

          handleCallback({"success": true, "user": "admin"})

          2)Vue axios實現(xiàn):

          this.$http=axios;

          this.$http.jsonp('http://www.domain2.com:8080/login', {

          params: {},

          jsonp: 'handleCallback'

          }).then((res)=> {

          console.log(res);

          })

          后端node.js代碼:

          var querystring=require('querystring');

          var http=require('http');

          var server=http.createServer();

          server.on('request', function(req, res) {

          var params=querystring.parse(req.url.split('?')[1]);

          var fn=params.callback;

          // jsonp返回設(shè)置

          res.writeHead(200, { 'Content-Type': 'text/javascript' });

          res.write(fn + '(' + JSON.stringify(params) + ')');

          res.end();

          });

          server.listen('8080');

          console.log('Server is running at port 8080...');

          JSONP的缺點:

          具有局限性, 僅支持get方法

          不安全,可能會遭受XSS攻擊

          (3)postMessage 跨域

          postMessage是HTML5 XMLHttpRequest Level 2中的API,且是為數(shù)不多可以跨域操作的window屬性之一,它可用于解決以下方面的問題:

          頁面和其打開的新窗口的數(shù)據(jù)傳遞

          多窗口之間消息傳遞

          頁面與嵌套的iframe消息傳遞

          上面三個場景的跨域數(shù)據(jù)傳遞

          用法:postMessage(data,origin)方法接受兩個參數(shù):

          data: html5規(guī)范支持任意基本類型或可復(fù)制的對象,但部分瀏覽器只支持字符串,所以傳參時最好用JSON.stringify()序列化。

          origin: 協(xié)議+主機+端口號,也可以設(shè)置為"*",表示可以傳遞給任意窗口,如果要指定和當前窗口同源的話設(shè)置為"/"。

          1)a.html:(domain1.com/a.html)

          <iframe id="iframe" src="http://www.domain2.com/b.html" style="display:none;"></iframe>

          <script>

          var iframe=document.getElementById('iframe');

          iframe.onload=function() {

          var data={

          name: 'aym'

          };

          // 向domain2傳送跨域數(shù)據(jù)

          iframe.contentWindow.postMessage(JSON.stringify(data), 'http://www.domain2.com');

          };

          // 接受domain2返回數(shù)據(jù)

          window.addEventListener('message', function(e) {

          alert('data from domain2 ---> ' + e.data);

          }, false);

          </script>

          2)b.html:(domain2.com/b.html)

          <script>

          // 接收domain1的數(shù)據(jù)

          window.addEventListener('message', function(e) {

          alert('data from domain1 ---> ' + e.data);

          var data=JSON.parse(e.data);

          if (data) {

          data.number=16;

          // 處理后再發(fā)回domain1

          window.parent.postMessage(JSON.stringify(data), 'http://www.domain1.com');

          }

          }, false);

          </script>

          <script>

          // 接收domain1的數(shù)據(jù)

          window.addEventListener('message', function(e) {

          alert('data from domain1 ---> ' + e.data);

          var data=JSON.parse(e.data);

          if (data) {

          data.number=16;

          // 處理后再發(fā)回domain1

          window.parent.postMessage(JSON.stringify(data), 'http://www.domain1.com');

          }

          }, false);

          </script>

          (4)nginx代理跨域

          nginx代理跨域,實質(zhì)和CORS跨域原理一樣,通過配置文件設(shè)置請求響應(yīng)頭Access-Control-Allow-Origin…等字段。

          1)nginx配置解決iconfont跨域

          瀏覽器跨域訪問js、css、img等常規(guī)靜態(tài)資源被同源策略許可,但iconfont字體文件(eot|otf|ttf|woff|svg)例外,此時可在nginx的靜態(tài)資源服務(wù)器中加入以下配置。

          location / {

          add_header Access-Control-Allow-Origin *;

          }

          2)nginx反向代理接口跨域

          跨域問題:同源策略僅是針對瀏覽器的安全策略。服務(wù)器端調(diào)用HTTP接口只是使用HTTP協(xié)議,不需要同源策略,也就不存在跨域問題。

          實現(xiàn)思路:通過Nginx配置一個代理服務(wù)器域名與domain1相同,端口不同)做跳板機,反向代理訪問domain2接口,并且可以順便修改cookie中domain信息,方便當前域cookie寫入,實現(xiàn)跨域訪問。

          nginx具體配置:

          #proxy服務(wù)器

          server {

          listen 81;

          server_name www.domain1.com;

          location / {

          proxy_pass http://www.domain2.com:8080; #反向代理

          proxy_cookie_domain www.domain2.com www.domain1.com; #修改cookie里域名

          index index.html index.htm;

          # 當用webpack-dev-server等中間件代理接口訪問nignx時,此時無瀏覽器參與,故沒有同源限制,下面的跨域配置可不啟用

          add_header Access-Control-Allow-Origin http://www.domain1.com; #當前端只跨域不帶cookie時,可為*

          add_header Access-Control-Allow-Credentials true;

          }

          }

          (5)nodejs 中間件代理跨域

          node中間件實現(xiàn)跨域代理,原理大致與nginx相同,都是通過啟一個代理服務(wù)器,實現(xiàn)數(shù)據(jù)的轉(zhuǎn)發(fā),也可以通過設(shè)置cookieDomainRewrite參數(shù)修改響應(yīng)頭中cookie中域名,實現(xiàn)當前域的cookie寫入,方便接口登錄認證。

          1)非vue框架的跨域

          使用node + express + http-proxy-middleware搭建一個proxy服務(wù)器。

          前端代碼:

          var xhr=new XMLHttpRequest();

          // 前端開關(guān):瀏覽器是否讀寫cookie

          xhr.withCredentials=true;

          // 訪問http-proxy-middleware代理服務(wù)器

          xhr.open('get', 'http://www.domain1.com:3000/login?user=admin', true);

          xhr.send();

          中間件服務(wù)器代碼:

          var express=require('express');

          var proxy=require('http-proxy-middleware');

          var app=express();

          app.use('/', proxy({

          // 代理跨域目標接口

          target: 'http://www.domain2.com:8080',

          changeOrigin: true,

          // 修改響應(yīng)頭信息,實現(xiàn)跨域并允許帶cookie

          onProxyRes: function(proxyRes, req, res) {

          res.header('Access-Control-Allow-Origin', 'http://www.domain1.com');

          res.header('Access-Control-Allow-Credentials', 'true');

          },

          // 修改響應(yīng)信息中的cookie域名

          cookieDomainRewrite: 'www.domain1.com' // 可以為false,表示不修改

          }));

          app.listen(3000);

          console.log('Proxy server is listen at port 3000...');

          2)vue框架的跨域

          node + vue + webpack + webpack-dev-server搭建的項目,跨域請求接口,直接修改webpack.config.js配置。開發(fā)環(huán)境下,vue渲染服務(wù)和接口代理服務(wù)都是webpack-dev-server同一個,所以頁面與代理接口之間不再跨域。

          webpack.config.js部分配置:

          module.exports={

          entry: {},

          module: {},

          ...

          devServer: {

          historyApiFallback: true,

          proxy: [{

          context: '/login',

          target: 'http://www.domain2.com:8080', // 代理跨域目標接口

          changeOrigin: true,

          secure: false, // 當代理某些https服務(wù)報錯時用

          cookieDomainRewrite: 'www.domain1.com' // 可以為false,表示不修改

          }],

          noInfo: true

          }

          }

          (6)document.domain + iframe跨域

          此方案僅限主域相同,子域不同的跨域應(yīng)用場景。實現(xiàn)原理:兩個頁面都通過js強制設(shè)置document.domain為基礎(chǔ)主域,就實現(xiàn)了同域。

          1)父窗口:(domain.com/a.html)

          <iframe id="iframe" src="http://child.domain.com/b.html"></iframe>

          <script>

          document.domain='domain.com';

          var user='admin';

          </script>

          1)子窗口:(child.domain.com/a.html)

          <script>

          document.domain='domain.com';

          // 獲取父窗口中變量

          console.log('get js data from parent ---> ' + window.parent.user);

          </script>

          (7)location.hash + iframe跨域

          實現(xiàn)原理:a欲與b跨域相互通信,通過中間頁c來實現(xiàn)。 三個頁面,不同域之間利用iframe的location.hash傳值,相同域之間直接js訪問來通信。

          具體實現(xiàn):A域:a.html -> B域:b.html -> A域:c.html,a與b不同域只能通過hash值單向通信,b與c也不同域也只能單向通信,但c與a同域,所以c可通過parent.parent訪問a頁面所有對象。

          1)a.html:(domain1.com/a.html)

          <iframe id="iframe" src="http://www.domain2.com/b.html" style="display:none;"></iframe>

          <script>

          var iframe=document.getElementById('iframe');

          // 向b.html傳hash值

          setTimeout(function() {

          iframe.src=iframe.src + '#user=admin';

          }, 1000);


          // 開放給同域c.html的回調(diào)方法

          function onCallback(res) {

          alert('data from c.html ---> ' + res);

          }

          </script>

          2)b.html:(.domain2.com/b.html)

          <iframe id="iframe" src="http://www.domain1.com/c.html" style="display:none;"></iframe>

          <script>

          var iframe=document.getElementById('iframe');

          // 監(jiān)聽a.html傳來的hash值,再傳給c.html

          window.onhashchange=function () {

          iframe.src=iframe.src + location.hash;

          };

          </script>

          3)c.html:(http://www.domain1.com/c.html)

          <script>

          // 監(jiān)聽b.html傳來的hash值

          window.onhashchange=function () {

          // 再通過操作同域a.html的js回調(diào),將結(jié)果傳回

          window.parent.parent.onCallback('hello: ' + location.hash.replace('#user=', ''));

          };

          </script>

          (8)window.name + iframe跨域

          window.name屬性的獨特之處:name值在不同的頁面(甚至不同域名)加載后依舊存在,并且可以支持非常長的 name 值(2MB)。

          1)a.html:(domain1.com/a.html)

          var proxy=function(url, callback) {

          var state=0;

          var iframe=document.createElement('iframe');

          // 加載跨域頁面

          iframe.src=url;

          // onload事件會觸發(fā)2次,第1次加載跨域頁,并留存數(shù)據(jù)于window.name

          iframe.onload=function() {

          if (state===1) {

          // 第2次onload(同域proxy頁)成功后,讀取同域window.name中數(shù)據(jù)

          callback(iframe.contentWindow.name);

          destoryFrame();

          } else if (state===0) {

          // 第1次onload(跨域頁)成功后,切換到同域代理頁面

          iframe.contentWindow.location='http://www.domain1.com/proxy.html';

          state=1;

          }

          };

          document.body.appendChild(iframe);

          // 獲取數(shù)據(jù)以后銷毀這個iframe,釋放內(nèi)存;這也保證了安全(不被其他域frame js訪問)

          function destoryFrame() {

          iframe.contentWindow.document.write('');

          iframe.contentWindow.close();

          document.body.removeChild(iframe);

          }

          };

          // 請求跨域b頁面數(shù)據(jù)

          proxy('http://www.domain2.com/b.html', function(data){

          alert(data);

          });

          2)proxy.html:(domain1.com/proxy.html)

          中間代理頁,與a.html同域,內(nèi)容為空即可。

          3)b.html:(domain2.com/b.html)

          <script>

          window.name='This is domain2 data!';

          </script>

          通過iframe的src屬性由外域轉(zhuǎn)向本地域,跨域數(shù)據(jù)即由iframe的window.name從外域傳遞到本地域。這個就巧妙地繞過了瀏覽器的跨域訪問限制,但同時它又是安全操作。

          (9)WebSocket協(xié)議跨域

          WebSocket protocol是HTML5一種新的協(xié)議。它實現(xiàn)了瀏覽器與服務(wù)器全雙工通信,同時允許跨域通訊,是server push技術(shù)的一種很好的實現(xiàn)。

          原生WebSocket API使用起來不太方便,我們使用Socket.io,它很好地封裝了webSocket接口,提供了更簡單、靈活的接口,也對不支持webSocket的瀏覽器提供了向下兼容。

          1)前端代碼:

          <div>user input:<input type="text"></div>

          <script src="https://cdn.bootcss.com/socket.io/2.2.0/socket.io.js"></script>

          <script>

          var socket=io('http://www.domain2.com:8080');

          // 連接成功處理

          socket.on('connect', function() {

          // 監(jiān)聽服務(wù)端消息

          socket.on('message', function(msg) {

          console.log('data from server: ---> ' + msg);

          });

          // 監(jiān)聽服務(wù)端關(guān)閉

          socket.on('disconnect', function() {

          console.log('Server socket has closed.');

          });

          });

          document.getElementsByTagName('input')[0].onblur=function() {

          socket.send(this.value);

          };

          </script>

          2)Nodejs socket后臺:

          var http=require('http');

          var socket=require('socket.io');

          // 啟http服務(wù)

          var server=http.createServer(function(req, res) {

          res.writeHead(200, {

          'Content-type': 'text/html'

          });

          res.end();

          });

          server.listen('8080');

          console.log('Server is running at port 8080...');

          // 監(jiān)聽socket連接

          socket.listen(server).on('connection', function(client) {

          // 接收信息

          client.on('message', function(msg) {

          client.send('hello:' + msg);

          console.log('data from client: ---> ' + msg);

          });

          // 斷開處理

          client.on('disconnect', function() {

          console.log('Client socket has closed.');

          });

          });

          3. 正向代理和反向代理的區(qū)別---了解即可

          正向代理:

          客戶端想獲得一個服務(wù)器的數(shù)據(jù),但是因為種種原因無法直接獲取。于是客戶端設(shè)置了一個代理服務(wù)器,并且指定目標服務(wù)器,之后代理服務(wù)器向目標服務(wù)器轉(zhuǎn)交請求并將獲得的內(nèi)容發(fā)送給客戶端。這樣本質(zhì)上起到了對真實服務(wù)器隱藏真實客戶端的目的。實現(xiàn)正向代理需要修改客戶端,比如修改瀏覽器配置。

          反向代理:

          服務(wù)器為了能夠?qū)⒐ぷ髫撦d分不到多個服務(wù)器來提高網(wǎng)站性能 (負載均衡)等目的,當其受到請求后,會首先根據(jù)轉(zhuǎn)發(fā)規(guī)則來確定請求應(yīng)該被轉(zhuǎn)發(fā)到哪個服務(wù)器上,然后將請求轉(zhuǎn)發(fā)到對應(yīng)的真實服務(wù)器上。這樣本質(zhì)上起到了對客戶端隱藏真實服務(wù)器的作用。

          一般使用反向代理后,需要通過修改 DNS 讓域名解析到代理服務(wù)器 IP,這時瀏覽器無法察覺到真正服務(wù)器的存在,當然也就不需要修改配置了。

          兩者區(qū)別如圖示:

          image

          正向代理和反向代理的結(jié)構(gòu)是一樣的,都是 client-proxy-server 的結(jié)構(gòu),它們主要的區(qū)別就在于中間這個 proxy 是哪一方設(shè)置的。在正向代理中,proxy 是 client 設(shè)置的,用來隱藏 client;而在反向代理中,proxy 是 server 設(shè)置的,用來隱藏 server。

          4. Nginx的概念及其工作原理---了解即可(或者不需要看)

          Nginx 是一款輕量級的 Web 服務(wù)器,也可以用于反向代理、負載平衡和 HTTP 緩存等。Nginx 使用異步事件驅(qū)動的方法來處理請求,是一款面向性能設(shè)計的 HTTP 服務(wù)器。

          傳統(tǒng)的 Web 服務(wù)器如 Apache 是 process-based 模型的,而 Nginx 是基于event-driven模型的。正是這個主要的區(qū)別帶給了 Nginx 在性能上的優(yōu)勢。

          Nginx 架構(gòu)的最頂層是一個 master process,這個 master process 用于產(chǎn)生其他的 worker process,這一點和Apache 非常像,但是 Nginx 的 worker process 可以同時處理大量的HTTP請求,而每個 Apache process 只能處理一個。

          八、瀏覽器事件機制

          1. 事件是什么?事件模型?

          事件是用戶操作網(wǎng)頁時發(fā)生的交互動作,比如 click/move, 事件除了用戶觸發(fā)的動作外,還可以是文檔加載,窗口滾動和大小調(diào)整。事件被封裝成一個 event 對象,包含了該事件發(fā)生時的所有相關(guān)信息( event 的屬性)以及可以對事件進行的操作( event 的方法)。

          事件是用戶操作網(wǎng)頁時發(fā)生的交互動作或者網(wǎng)頁本身的一些操作,現(xiàn)代瀏覽器一共有三種事件模型:

          DOM0 級事件模型,這種模型不會傳播,所以沒有事件流的概念,但是現(xiàn)在有的瀏覽器支持以冒泡的方式實現(xiàn),它可以在網(wǎng)頁中直接定義監(jiān)聽函數(shù),也可以通過 js 屬性來指定監(jiān)聽函數(shù)。所有瀏覽器都兼容這種方式。直接在dom對象上注冊事件名稱,就是DOM0寫法。

          IE 事件模型,在該事件模型中,一次事件共有兩個過程,事件處理階段和事件冒泡階段。事件處理階段會首先執(zhí)行目標元素綁定的監(jiān)聽事件。然后是事件冒泡階段,冒泡指的是事件從目標元素冒泡到 document,依次檢查經(jīng)過的節(jié)點是否綁定了事件監(jiān)聽函數(shù),如果有則執(zhí)行。這種模型通過attachEvent 來添加監(jiān)聽函數(shù),可以添加多個監(jiān)聽函數(shù),會按順序依次執(zhí)行。

          DOM2 級事件模型,在該事件模型中,一次事件共有三個過程,第一個過程是事件捕獲階段。捕獲指的是事件從 document 一直向下傳播到目標元素,依次檢查經(jīng)過的節(jié)點是否綁定了事件監(jiān)聽函數(shù),如果有則執(zhí)行。后面兩個階段和 IE 事件模型的兩個階段相同。這種事件模型,事件綁定的函數(shù)是addEventListener,其中第三個參數(shù)可以指定事件是否在捕獲階段執(zhí)行。

          2. 如何阻止事件冒泡

          普通瀏覽器使用:event.stopPropagation()

          IE瀏覽器使用:event.cancelBubble=true;

          3. 對事件委托的理解

          (1)事件委托的概念

          事件委托本質(zhì)上是利用了瀏覽器事件冒泡的機制。因為事件在冒泡過程中會上傳到父節(jié)點,父節(jié)點可以通過事件對象獲取到目標節(jié)點,因此可以把子節(jié)點的監(jiān)聽函數(shù)定義在父節(jié)點上,由父節(jié)點的監(jiān)聽函數(shù)統(tǒng)一處理多個子元素的事件,這種方式稱為事件委托(事件代理)。

          使用事件委托可以不必要為每一個子元素都綁定一個監(jiān)聽事件,這樣減少了內(nèi)存上的消耗。并且使用事件代理還可以實現(xiàn)事件的動態(tài)綁定,比如說新增了一個子節(jié)點,并不需要單獨地為它添加一個監(jiān)聽事件,它綁定的事件會交給父元素中的監(jiān)聽函數(shù)來處理。

          (2)事件委托的特點

          減少內(nèi)存消耗

          如果有一個列表,列表之中有大量的列表項,需要在點擊列表項的時候響應(yīng)一個事件:

          <ul id="list">

          <li>item 1</li>

          <li>item 2</li>

          <li>item 3</li>

          ......

          <li>item n</li>

          </ul>

          如果給每個列表項一一都綁定一個函數(shù),那對于內(nèi)存消耗是非常大的,效率上需要消耗很多性能。因此,比較好的方法就是把這個點擊事件綁定到他的父層,也就是 ul 上,然后在執(zhí)行事件時再去匹配判斷目標元素,所以事件委托可以減少大量的內(nèi)存消耗,節(jié)約效率。

          動態(tài)綁定事件

          給上述的例子中每個列表項都綁定事件,在很多時候,需要通過 AJAX 或者用戶操作動態(tài)的增加或者去除列表項元素,那么在每一次改變的時候都需要重新給新增的元素綁定事件,給即將刪去的元素解綁事件;如果用了事件委托就沒有這種麻煩了,因為事件是綁定在父層的,和目標元素的增減是沒有關(guān)系的,執(zhí)行到目標元素是在真正響應(yīng)執(zhí)行事件函數(shù)的過程中去匹配的,所以使用事件在動態(tài)綁定事件的情況下是可以減少很多重復(fù)工作的。

          // 來實現(xiàn)把 #list 下的 li 元素的事件代理委托到它的父層元素也就是 #list 上:

          // 給父層元素綁定事件

          document.getElementById('list').addEventListener('click', function (e) {

          // 兼容性處理

          var event=e || window.event;

          var target=event.target || event.srcElement;

          // 判斷是否匹配目標元素

          if (target.nodeName.toLocaleLowerCase==='li') {

          console.log('the content is: ', target.innerHTML);

          }

          });

          在上述代碼中, target 元素則是在 #list 元素之下具體被點擊的元素,然后通過判斷 target 的一些屬性(比如:nodeName,id 等等)可以更精確地匹配到某一類 #list li 元素之上;

          (3)局限性

          當然,事件委托也是有局限的。比如 focus、blur 之類的事件沒有事件冒泡機制,所以無法實現(xiàn)事件委托;mousemove、mouseout 這樣的事件,雖然有事件冒泡,但是只能不斷通過位置去計算定位,對性能消耗高,因此也是不適合于事件委托的。

          當然事件委托不是只有優(yōu)點,它也是有缺點的,事件委托會影響頁面性能,主要影響因素有:

          元素中,綁定事件委托的次數(shù);

          點擊的最底層元素,到綁定事件元素之間的DOM層數(shù);

          在必須使用事件委托的地方,可以進行如下的處理:

          只在必須的地方,使用事件委托,比如:ajax的局部刷新區(qū)域

          盡量的減少綁定的層級,不在body元素上,進行綁定

          減少綁定的次數(shù),如果可以,那么把多個事件的綁定,合并到一次事件委托中去,由這個事件委托的回調(diào),來進行分發(fā)。

          4. 事件委托的使用場景

          場景:給頁面的所有的a標簽添加click事件,代碼如下:

          document.addEventListener("click", function(e) {

          if (e.target.nodeName=="A")

          console.log("a");

          }, false);

          但是這些a標簽可能包含一些像span、img等元素,如果點擊到了這些a標簽中的元素,就不會觸發(fā)click事件,因為事件綁定上在a標簽元素上,而觸發(fā)這些內(nèi)部的元素時,e.target指向的是觸發(fā)click事件的元素(span、img等其他元素)。

          這種情況下就可以使用事件委托來處理,將事件綁定在a標簽的內(nèi)部元素上,當點擊它的時候,就會逐級向上查找,知道找到a標簽為止,代碼如下:

          document.addEventListener("click", function(e) {

          var node=e.target;

          while (node.parentNode.nodeName !="BODY") {

          if (node.nodeName=="A") {

          console.log("a");

          break;

          }

          node=node.parentNode;

          }

          }, false);

          5. 同步和異步的區(qū)別

          同步指的是當一個進程在執(zhí)行某個請求時,如果這個請求需要等待一段時間才能返回,那么這個進程會一直等待下去,直到消息返回為止再繼續(xù)向下執(zhí)行。

          異步指的是當一個進程在執(zhí)行某個請求時,如果這個請求需要等待一段時間才能返回,這個時候進程會繼續(xù)往下執(zhí)行,不會阻塞等待消息的返回,當消息返回時系統(tǒng)再通知進程進行處理。

          6. 對事件循環(huán)的理解

          因為 js 是單線程運行的,在代碼執(zhí)行時,通過將不同函數(shù)的執(zhí)行上下文壓入執(zhí)行棧中來保證代碼的有序執(zhí)行。在執(zhí)行同步代碼時,如果遇到異步事件,js 引擎并不會一直等待其返回結(jié)果,而是會將這個事件掛起,繼續(xù)執(zhí)行執(zhí)行棧中的其他任務(wù)。當異步事件執(zhí)行完畢后,再將異步事件對應(yīng)的回調(diào)加入到一個任務(wù)隊列中等待執(zhí)行。任務(wù)隊列可以分為宏任務(wù)隊列和微任務(wù)隊列,當當前執(zhí)行棧中的事件執(zhí)行完畢后,js 引擎首先會判斷微任務(wù)隊列中是否有任務(wù)可以執(zhí)行,如果有就將微任務(wù)隊首的事件壓入棧中執(zhí)行。當微任務(wù)隊列中的任務(wù)都執(zhí)行完成后再去執(zhí)行宏任務(wù)隊列中的任務(wù)。

          image

          Event Loop 執(zhí)行順序如下所示:

          首先執(zhí)行同步代碼,這屬于宏任務(wù)

          當執(zhí)行完所有同步代碼后,執(zhí)行棧為空,查詢是否有異步代碼需要執(zhí)行

          執(zhí)行所有微任務(wù)

          當執(zhí)行完所有微任務(wù)后,如有必要會渲染頁面

          然后開始下一輪 Event Loop,執(zhí)行宏任務(wù)中的異步代碼

          7. 宏任務(wù)和微任務(wù)分別有哪些

          微任務(wù)包括: promise 的回調(diào)、node 中的 process.nextTick 、對 Dom 變化監(jiān)聽的 MutationObserver。

          宏任務(wù)包括: script 腳本的執(zhí)行、setTimeout ,setInterval ,setImmediate 一類的定時事件,還有如 I/O 操作、UI 渲染等。

          8. 什么是執(zhí)行棧

          可以把執(zhí)行棧認為是一個存儲函數(shù)調(diào)用的棧結(jié)構(gòu),遵循先進后出的原則。

          image

          當開始執(zhí)行 JS 代碼時,根據(jù)先進后出的原則,后執(zhí)行的函數(shù)會先彈出棧,可以看到,foo 函數(shù)后執(zhí)行,當執(zhí)行完畢后就從棧中彈出了。

          平時在開發(fā)中,可以在報錯中找到執(zhí)行棧的痕跡:

          function foo() {

          throw new Error('error')

          }

          function bar() {

          foo()

          }

          bar()

          img

          可以看到報錯在 foo 函數(shù),foo 函數(shù)又是在 bar 函數(shù)中調(diào)用的。當使用遞歸時,因為棧可存放的函數(shù)是有限制的,一旦存放了過多的函數(shù)且沒有得到釋放的話,就會出現(xiàn)爆棧的問題

          function bar() {

          bar()

          }

          bar()

          img

          9. Node 中的 Event Loop 和瀏覽器中的有什么區(qū)別?process.nextTick 執(zhí)行順序?

          Node 中的 Event Loop 和瀏覽器中的是完全不相同的東西。

          Node 的 Event Loop 分為 6 個階段,它們會按照順序反復(fù)運行。每當進入某一個階段的時候,都會從對應(yīng)的回調(diào)隊列中取出函數(shù)去執(zhí)行。當隊列為空或者執(zhí)行的回調(diào)函數(shù)數(shù)量到達系統(tǒng)設(shè)定的閾值,就會進入下一階段。

          image

          (1)Timers(計時器階段):初次進入事件循環(huán),會從計時器階段開始。此階段會判斷是否存在過期的計時器回調(diào)(包含 setTimeout 和 setInterval),如果存在則會執(zhí)行所有過期的計時器回調(diào),執(zhí)行完畢后,如果回調(diào)中觸發(fā)了相應(yīng)的微任務(wù),會接著執(zhí)行所有微任務(wù),執(zhí)行完微任務(wù)后再進入 Pending callbacks 階段。

          (2)Pending callbacks:執(zhí)行推遲到下一個循環(huán)迭代的I / O回調(diào)(系統(tǒng)調(diào)用相關(guān)的回調(diào))。

          (3)Idle/Prepare:僅供內(nèi)部使用。

          (4)Poll(輪詢階段):

          當回調(diào)隊列不為空時:會執(zhí)行回調(diào),若回調(diào)中觸發(fā)了相應(yīng)的微任務(wù),這里的微任務(wù)執(zhí)行時機和其他地方有所不同,不會等到所有回調(diào)執(zhí)行完畢后才執(zhí)行,而是針對每一個回調(diào)執(zhí)行完畢后,就執(zhí)行相應(yīng)微任務(wù)。執(zhí)行完所有的回調(diào)后,變?yōu)橄旅娴那闆r。

          當回調(diào)隊列為空時(沒有回調(diào)或所有回調(diào)執(zhí)行完畢):但如果存在有計時器(setTimeout、setInterval和setImmediate)沒有執(zhí)行,會結(jié)束輪詢階段,進入 Check 階段。否則會阻塞并等待任何正在執(zhí)行的I/O操作完成,并馬上執(zhí)行相應(yīng)的回調(diào),直到所有回調(diào)執(zhí)行完畢。

          (5)Check(查詢階段):會檢查是否存在 setImmediate 相關(guān)的回調(diào),如果存在則執(zhí)行所有回調(diào),執(zhí)行完畢后,如果回調(diào)中觸發(fā)了相應(yīng)的微任務(wù),會接著執(zhí)行所有微任務(wù),執(zhí)行完微任務(wù)后再進入 Close callbacks 階段。

          (6)Close callbacks:執(zhí)行一些關(guān)閉回調(diào),比如socket.on('close', ...)等。

          下面來看一個例子,首先在有些情況下,定時器的執(zhí)行順序其實是隨機的

          setTimeout(()=> {

          console.log('setTimeout')

          }, 0)

          setImmediate(()=> {

          console.log('setImmediate')

          })

          對于以上代碼來說,setTimeout 可能執(zhí)行在前,也可能執(zhí)行在后

          首先 setTimeout(fn, 0)===setTimeout(fn, 1),這是由源碼決定的

          進入事件循環(huán)也是需要成本的,如果在準備時候花費了大于 1ms 的時間,那么在 timer 階段就會直接執(zhí)行 setTimeout 回調(diào)

          那么如果準備時間花費小于 1ms,那么就是 setImmediate 回調(diào)先執(zhí)行了

          當然在某些情況下,他們的執(zhí)行順序一定是固定的,比如以下代碼:

          const fs=require('fs')

          fs.readFile(__filename, ()=> {

          setTimeout(()=> {

          console.log('timeout');

          }, 0)

          setImmediate(()=> {

          console.log('immediate')

          })

          })

          在上述代碼中,setImmediate 永遠先執(zhí)行。因為兩個代碼寫在 IO 回調(diào)中,IO 回調(diào)是在 poll 階段執(zhí)行,當回調(diào)執(zhí)行完畢后隊列為空,發(fā)現(xiàn)存在 setImmediate 回調(diào),所以就直接跳轉(zhuǎn)到 check 階段去執(zhí)行回調(diào)了。

          上面都是 macrotask 的執(zhí)行情況,對于 microtask 來說,它會在以上每個階段完成前清空 microtask 隊列,下圖中的 Tick 就代表了 microtask

          image

          setTimeout(()=> {

          console.log('timer21')

          }, 0)

          Promise.resolve().then(function() {

          console.log('promise1')

          })

          對于以上代碼來說,其實和瀏覽器中的輸出是一樣的,microtask 永遠執(zhí)行在 macrotask 前面。

          最后來看 Node 中的 process.nextTick,這個函數(shù)其實是獨立于 Event Loop 之外的,它有一個自己的隊列,當每個階段完成后,如果存在 nextTick 隊列,就會清空隊列中的所有回調(diào)函數(shù),并且優(yōu)先于其他 microtask 執(zhí)行。

          setTimeout(()=> {

          console.log('timer1')

          Promise.resolve().then(function() {

          console.log('promise1')

          })

          }, 0)

          process.nextTick(()=> {

          console.log('nextTick')

          process.nextTick(()=> {

          console.log('nextTick')

          process.nextTick(()=> {

          console.log('nextTick')

          process.nextTick(()=> {

          console.log('nextTick')

          })

          })

          })

          })

          對于以上代碼,永遠都是先把 nextTick 全部打印出來。

          10. 事件觸發(fā)的過程是怎樣的

          事件觸發(fā)有三個階段:

          window 往事件觸發(fā)處傳播,遇到注冊的捕獲事件會觸發(fā)

          傳播到事件觸發(fā)處時觸發(fā)注冊的事件

          從事件觸發(fā)處往 window 傳播,遇到注冊的冒泡事件會觸發(fā)

          事件觸發(fā)一般來說會按照上面的順序進行,但是也有特例,如果給一個 **body** 中的子節(jié)點同時注冊冒泡和捕獲事件,事件觸發(fā)會按照注冊的順序執(zhí)行。

          // 以下會先打印冒泡然后是捕獲

          node.addEventListener(

          'click',

          event=> {

          console.log('冒泡')

          },

          false

          )

          node.addEventListener(

          'click',

          event=> {

          console.log('捕獲 ')

          },

          true

          )

          通常使用 addEventListener 注冊事件,該函數(shù)的第三個參數(shù)可以是布爾值,也可以是對象。對于布爾值 useCapture 參數(shù)來說,該參數(shù)默認值為 false ,useCapture 決定了注冊的事件是捕獲事件還是冒泡事件。對于對象參數(shù)來說,可以使用以下幾個屬性:

          capture:布爾值,和 useCapture 作用一樣

          once:布爾值,值為 true 表示該回調(diào)只會調(diào)用一次,調(diào)用后會移除監(jiān)聽

          passive:布爾值,表示永遠不會調(diào)用 preventDefault

          一般來說,如果只希望事件只觸發(fā)在目標上,這時候可以使用 stopPropagation 來阻止事件的進一步傳播。通常認為 stopPropagation 是用來阻止事件冒泡的,其實該函數(shù)也可以阻止捕獲事件。

          stopImmediatePropagation 同樣也能實現(xiàn)阻止事件,但是還能阻止該事件目標執(zhí)行別的注冊事件。

          node.addEventListener(

          'click',

          event=> {

          event.stopImmediatePropagation()

          console.log('冒泡')

          },

          false

          )

          // 點擊 node 只會執(zhí)行上面的函數(shù),該函數(shù)不會執(zhí)行

          node.addEventListener(

          'click',

          event=> {

          console.log('捕獲 ')

          },

          true

          )

          九、瀏覽器垃圾回收機制---了解即可

          1. V8的垃圾回收機制是怎樣的

          V8 實現(xiàn)了準確式 GC,GC 算法采用了分代式垃圾回收機制。因此,V8 將內(nèi)存(堆)分為新生代和老生代兩部分。

          (1)新生代算法

          新生代中的對象一般存活時間較短,使用 Scavenge GC 算法。

          在新生代空間中,內(nèi)存空間分為兩部分,分別為 From 空間和 To 空間。在這兩個空間中,必定有一個空間是使用的,另一個空間是空閑的。新分配的對象會被放入 From 空間中,當 From 空間被占滿時,新生代 GC 就會啟動了。算法會檢查 From 空間中存活的對象并復(fù)制到 To 空間中,如果有失活的對象就會銷毀。當復(fù)制完成后將 From 空間和 To 空間互換,這樣 GC 就結(jié)束了。

          (2)老生代算法

          老生代中的對象一般存活時間較長且數(shù)量也多,使用了兩個算法,分別是標記清除算法和標記壓縮算法。

          先來說下什么情況下對象會出現(xiàn)在老生代空間中:

          新生代中的對象是否已經(jīng)經(jīng)歷過一次 Scavenge 算法,如果經(jīng)歷過的話,會將對象從新生代空間移到老生代空間中。

          To 空間的對象占比大小超過 25 %。在這種情況下,為了不影響到內(nèi)存分配,會將對象從新生代空間移到老生代空間中。

          老生代中的空間很復(fù)雜,有如下幾個空間

          enum AllocationSpace {

          // TODO(v8:7464): Actually map this space's memory as read-only.

          RO_SPACE, // 不變的對象空間

          NEW_SPACE, // 新生代用于 GC 復(fù)制算法的空間

          OLD_SPACE, // 老生代常駐對象空間

          CODE_SPACE, // 老生代代碼對象空間

          MAP_SPACE, // 老生代 map 對象

          LO_SPACE, // 老生代大空間對象

          NEW_LO_SPACE, // 新生代大空間對象

          FIRST_SPACE=RO_SPACE,

          LAST_SPACE=NEW_LO_SPACE,

          FIRST_GROWABLE_PAGED_SPACE=OLD_SPACE,

          LAST_GROWABLE_PAGED_SPACE=MAP_SPACE

          };

          在老生代中,以下情況會先啟動標記清除算法:

          某一個空間沒有分塊的時候

          空間中被對象超過一定限制

          空間不能保證新生代中的對象移動到老生代中

          在這個階段中,會遍歷堆中所有的對象,然后標記活的對象,在標記完成后,銷毀所有沒有被標記的對象。在標記大型對內(nèi)存時,可能需要幾百毫秒才能完成一次標記。這就會導(dǎo)致一些性能上的問題。為了解決這個問題,2011 年,V8 從 stop-the-world 標記切換到增量標志。在增量標記期間,GC 將標記工作分解為更小的模塊,可以讓 JS 應(yīng)用邏輯在模塊間隙執(zhí)行一會,從而不至于讓應(yīng)用出現(xiàn)停頓情況。但在 2018 年,GC 技術(shù)又有了一個重大突破,這項技術(shù)名為并發(fā)標記。該技術(shù)可以讓 GC 掃描和標記對象時,同時允許 JS 運行。

          清除對象后會造成堆內(nèi)存出現(xiàn)碎片的情況,當碎片超過一定限制后會啟動壓縮算法。在壓縮過程中,將活的對象向一端移動,直到所有對象都移動完成然后清理掉不需要的內(nèi)存。

          2. 哪些操作會造成內(nèi)存泄漏?

          第一種情況是由于使用未聲明的變量,而意外的創(chuàng)建了一個全局變量,而使這個變量一直留在內(nèi)存中無法被回收。

          第二種情況是設(shè)置了 setInterval 定時器,而忘記取消它,如果循環(huán)函數(shù)有對外部變量的引用的話,那么這個變量會被一直留在內(nèi)存中,而無法被回收。

          第三種情況是獲取一個 DOM 元素的引用,而后面這個元素被刪除,由于我們一直保留了對這個元素的引用,所以它也無法被回收。

          第四種情況是不合理的使用閉包,從而導(dǎo)致某些變量一直被留在內(nèi)存當中。

          、引言

          1.1、開發(fā)目的和背景


          隨著企業(yè)規(guī)模的不斷擴大,日常辦公活動的復(fù)雜性日益增加,對于信息的高效管理和資源的合理利用的需求也越發(fā)凸顯。傳統(tǒng)的管理模式往往效率低下,易出錯,難以滿足現(xiàn)代企業(yè)對精細化、智能化管理的需求。因此,我們開發(fā)了這款名為“辦公資源智慧管理系統(tǒng)”的軟件。


          該系統(tǒng)的核心目的是打造一個集多功能于一體的綜合性辦公管理平臺,旨在解決企業(yè)在日常運營中的諸多痛點。通過部門管理模塊,可以實現(xiàn)人員和職能的清晰劃分,提升組織效率;會議管理模塊則幫助團隊有效規(guī)劃和跟蹤會議進程,減少無效溝通;借還管理模塊則簡化了資源借用和歸還流程,避免資源浪費。


          權(quán)限管理、任務(wù)管理和認證授權(quán)等功能,確保數(shù)據(jù)安全與操作規(guī)范,保障企業(yè)的信息安全。同時,日志記錄管理、數(shù)據(jù)備份和恢復(fù)機制,為數(shù)據(jù)保護提供了多重保險。私信管理、通知公告管理則加強了內(nèi)部溝通,提高了決策速度。


          維修管理模塊有助于及時發(fā)現(xiàn)并解決問題,保證設(shè)備正常運行。消息推送管理實時更新重要信息,提高員工的工作響應(yīng)速度。用戶管理和預(yù)約管理模塊,使得用戶界面友好,操作便捷。資源分類和資源管理模塊,讓資源分配更加有序,提高資源利用率。


          在當前數(shù)字化轉(zhuǎn)型的大潮中,我們的“辦公資源智慧管理系統(tǒng)”正是為了適應(yīng)這一變革,幫助企業(yè)提升管理水平,降低運營成本,優(yōu)化工作流程,從而實現(xiàn)業(yè)務(wù)的高效運轉(zhuǎn),助力企業(yè)在激烈的市場競爭中保持領(lǐng)先地位。

          1.2、軟件的目標用戶


          辦公資源智慧管理系統(tǒng)是一款專為現(xiàn)代化企業(yè)設(shè)計的全方位辦公工具,它將企業(yè)的日常行政管理工作無縫整合,適用于各種規(guī)模的公司,無論是大型跨國企業(yè)還是中小型企業(yè)。在一個繁忙的工作環(huán)境中,這個系統(tǒng)可以幫助各部門高效協(xié)同,提升辦公效率。


          例如,當一個團隊需要預(yù)約會議室進行會議時,他們可以直接在系統(tǒng)中進行操作,選擇合適的會議室,查看其可用時間和預(yù)定狀態(tài),大大減少了協(xié)調(diào)時間。在資源管理方面,員工可以方便地查找和申請所需的辦公設(shè)備、文件資料,或者提交物品借用和歸還,避免了資源的混亂和尋找浪費。


          此外,系統(tǒng)還提供了考勤管理和任務(wù)管理功能,員工可以通過手機應(yīng)用或電腦端進行簽到,上級可以清晰地了解員工的工作進度,便于進行有效的時間管理和績效評估。數(shù)據(jù)備份和恢復(fù)功能則確保了重要信息的安全,防止因意外情況導(dǎo)致的數(shù)據(jù)丟失。


          我們的主要目標用戶是對效率和協(xié)作有高要求的企業(yè)管理者、行政人員、以及一線員工。對于管理者來說,他們可以通過系統(tǒng)輕松監(jiān)控整個組織的運營狀況,進行決策支持。行政人員可以專注于日常運營工作,而不是繁瑣的文檔管理。而一線員工則能通過直觀易用的界面,簡化他們的工作流程,提高工作效率。


          總的來說,辦公資源智慧管理系統(tǒng)是任何希望提升辦公效率,實現(xiàn)數(shù)字化管理的企業(yè)的理想選擇,無論他們是希望通過更好的資源配置優(yōu)化工作環(huán)境,還是希望通過更有效的管理手段提升員工滿意度,都能在這款系統(tǒng)中找到解決方案。

          二、軟件總體設(shè)計

          2.1、系統(tǒng)概述


          辦公資源智慧管理系統(tǒng)是一款專為現(xiàn)代企業(yè)打造的全面集成辦公解決方案。該系統(tǒng)基于Java編程語言,采用高效的SpringMVC開發(fā)框架,數(shù)據(jù)存儲則依賴于成熟穩(wěn)定的MySQL數(shù)據(jù)庫。系統(tǒng)設(shè)計旨在提升企業(yè)的行政效率和協(xié)作管理水平。


          首先,部門管理模塊幫助用戶清晰劃分工作職責(zé),便于信息共享和協(xié)調(diào)。會議管理支持預(yù)約、議題設(shè)置和實時通知,確保所有參與者能及時了解并參與決策。借還管理功能實現(xiàn)資產(chǎn)的有序流轉(zhuǎn),避免資源浪費。


          考勤管理模塊通過電子簽到記錄員工出勤情況,簡化傳統(tǒng)的人工記錄過程。權(quán)限管理嚴格控制各用戶的操作權(quán)限,保障信息安全。任務(wù)管理模塊讓任務(wù)分配、跟蹤和完成過程透明化。


          認證授權(quán)功能確保只有授權(quán)用戶才能訪問特定功能或資源,日志記錄管理則有助于審計和追蹤系統(tǒng)活動。數(shù)據(jù)備份和恢復(fù)功能為重要數(shù)據(jù)提供雙重保護,防止數(shù)據(jù)丟失。


          私信管理和通知公告管理加強內(nèi)部溝通,提高團隊協(xié)作效率。維修管理記錄設(shè)備維護歷史,及時處理故障。消息推送管理確保重要信息能即時送達用戶。用戶管理模塊負責(zé)賬戶創(chuàng)建、修改和注銷等操作。


          此外,系統(tǒng)還提供統(tǒng)計報表生成功能,幫助企業(yè)快速分析運營狀況;預(yù)約管理功能支持預(yù)約會議室、設(shè)備等;資源分類和資源管理模塊則確保資源的有效分配和利用。


          總的來說,辦公資源智慧管理系統(tǒng)以用戶為中心,結(jié)合現(xiàn)代化技術(shù)手段,構(gòu)建了一套全面、高效、安全的企業(yè)辦公環(huán)境,助力企業(yè)提升運營效能和員工滿意度。

          2.2、系統(tǒng)架構(gòu)

          辦公資源智慧管理系統(tǒng)采用先進的B/S(Browser/Server)架構(gòu)設(shè)計,這種架構(gòu)允許用戶通過任何支持Web瀏覽器的設(shè)備訪問系統(tǒng),極大地提升了系統(tǒng)的便捷性和可擴展性。整個系統(tǒng)主要由以下幾個關(guān)鍵組件組成:


          1. 前端界面(User Interface):基于HTML5、CSS3和JavaScript的現(xiàn)代Web客戶端,提供直觀、響應(yīng)式的用戶界面。用戶可以進行各種操作,如查看信息、管理資源、發(fā)送私信等,所有操作均通過瀏覽器實時與服務(wù)器交互。


          2. 后端服務(wù)(Backend Services):Java語言作為核心技術(shù),結(jié)合Spring MVC框架,構(gòu)建了高效、穩(wěn)定的服務(wù)層。它處理來自前端的請求,執(zhí)行業(yè)務(wù)邏輯,調(diào)用數(shù)據(jù)訪問層進行數(shù)據(jù)操作,并返回響應(yīng)結(jié)果。


          3. 數(shù)據(jù)訪問層(Data Access Layer):通常使用JDBC或者ORM框架如MyBatis,負責(zé)與數(shù)據(jù)庫交互,執(zhí)行SQL查詢或更新操作,保證數(shù)據(jù)的安全性和一致性。


          4. 數(shù)據(jù)庫(Database):采用關(guān)系型數(shù)據(jù)庫如MySQL或Oracle,存儲所有的系統(tǒng)信息、用戶信息、資源信息以及日志記錄等數(shù)據(jù)。


          5. 認證授權(quán)(Authentication and Authorization):采用角色基礎(chǔ)的訪問控制機制,確保只有授權(quán)的用戶能訪問特定功能和數(shù)據(jù)。


          6. 消息隊列(Message Queue):對于異步處理和消息推送,可能采用RabbitMQ等工具,提高系統(tǒng)的并發(fā)能力和響應(yīng)速度。


          7. 日志記錄管理(Logging):通過整合log4j或SLF4J,記錄系統(tǒng)運行狀態(tài)和操作日志,便于問題排查和審計。


          8. 備份恢復(fù)機制(Backup and Recovery):系統(tǒng)自帶數(shù)據(jù)備份功能,定期自動備份關(guān)鍵數(shù)據(jù),以應(yīng)對突發(fā)情況。


          9. 統(tǒng)計報表(Reporting):通過ECharts、Tableau等工具生成各種業(yè)務(wù)指標的報表,方便管理層決策。


          10. 系統(tǒng)集成(Integration):與其他辦公系統(tǒng)(如ERP、CRM等)進行接口集成,實現(xiàn)數(shù)據(jù)共享和流程協(xié)同。


          綜上,辦公資源智慧管理系統(tǒng)的設(shè)計充分考慮了易用性、性能和安全性,旨在為用戶提供一個高效、安全、穩(wěn)定的辦公資源管理環(huán)境。

          三、軟件操作說明

          3.1、系統(tǒng)登錄


          在瀏覽器中輸入系統(tǒng)網(wǎng)址,打開登錄界面后輸入登錄賬號、登錄密碼、驗證碼即可登錄。

          3.2、工作臺


          工作臺包含:部門管理、會議管理、借還管理、考勤管理、權(quán)限管理、任務(wù)管理、認證授權(quán)、日志記錄管理、數(shù)據(jù)備份、數(shù)據(jù)恢復(fù)、私信管理、統(tǒng)計報表、通知公告管理、維修管理、消息推送管理、用戶管理、預(yù)約管理、資源分類管理、資源管理,根據(jù)不同角色權(quán)限菜單展示會有所區(qū)別。

          3.2.1、部門管理


          管理功能主要字段信息包含:管理編碼、部門名稱、部門編號、部門描述、上級部門、創(chuàng)建時間、修改時間等。使用表格形式展示這些信息,方便用戶查看和編輯,方便用戶進行管理信息的管理。


          系統(tǒng)為管理提供了全面支持,包括新增記錄、編輯信息、刪除條目、數(shù)據(jù)導(dǎo)出、條件檢索及詳情查看等功能。用戶只需遵循頁面清晰的操作指引,即可輕松完成各項任務(wù)。界面設(shè)計遵循極簡原則,布局直觀,交互流暢,旨在營造無負擔(dān)的操作環(huán)境,顯著提升用戶的使用體驗與工作效率。

          3.2.2、會議管理


          管理功能主要字段信息包含:管理編碼、會議名稱、會議時間、會議地點、會議內(nèi)容、參會人員、會議狀態(tài)等。使用表格形式展示這些信息,方便用戶查看和編輯,方便用戶進行管理信息的管理。


          針對管理,系統(tǒng)精心設(shè)置了全方位功能模塊,涵蓋新增、編輯、刪除、導(dǎo)出、條件檢索以及查看詳情等核心操作。用戶在使用過程中,僅需緊密跟隨頁面內(nèi)直觀且詳盡的操作提示,即可輕松駕馭各項流程。我們秉持化繁為簡的理念,打造出簡約明快的界面風(fēng)格與邏輯清晰的操作流程,旨在讓用戶在高效管理數(shù)據(jù),享受到愉悅、無壓力的操作體驗。

          3.2.3、借還管理


          管理功能主要字段信息包含:管理編碼、資源編號、資源名稱、借出人員、借出時間、歸還時間、備注等。使用表格形式展示這些信息,方便用戶查看和編輯,方便用戶進行管理信息的管理。


          為實現(xiàn)對管理,系統(tǒng)精心配備了豐富的功能組件,包括新增、編輯、刪除、導(dǎo)出、條件搜以及詳情查看等實用操作。用戶在操作過程中,只需遵循頁面上清晰易懂的引導(dǎo)提示,即可順暢地完成各項任務(wù)。我們注重用戶體驗,以簡約而不失專業(yè)的界面設(shè)計,輔以直觀且高效的流程布局,旨在助力用戶在輕松管理數(shù)據(jù)同時,全面提升操作滿意度與工作效率。

          3.2.4、考勤管理


          管理功能主要字段信息包含:管理編碼、考勤人員、考勤時間、考勤位置、考勤狀態(tài)、考勤記錄等。使用表格形式展示這些信息,方便用戶查看和編輯,方便用戶進行管理信息的管理。


          為滿足管理的多元需求,系統(tǒng)配置了一系列操作功能:新增、編輯、刪除、導(dǎo)出、搜索、詳情。用戶在實際操作中,僅需按照頁面上直觀且詳盡的操作提示,即可輕松駕馭各項流程。系統(tǒng)界面設(shè)計簡約清爽,操作邏輯清晰明了,旨在讓用戶在高效管理數(shù)據(jù)的同時,盡享流暢、無壓力的操作體驗,大幅提升工作效率與滿意度。

          3.2.5、權(quán)限管理


          管理功能主要字段信息包含:管理編碼、角色名稱、角色描述、角色權(quán)限、創(chuàng)建時間、修改時間等。使用表格形式展示這些信息,方便用戶查看和編輯,方便用戶進行管理信息的管理。


          管理設(shè)置新增、編輯、刪除、條件搜索、查看詳情等操作,可按照頁面提示進行操作執(zhí)行,界面結(jié)構(gòu)設(shè)計簡單,操作流程簡潔明了,可提升用戶操作體驗。

          3.2.6、任務(wù)管理


          管理功能主要字段信息包含:管理編碼、任務(wù)名稱、任務(wù)描述、任務(wù)創(chuàng)建時間、任務(wù)完成時間、任務(wù)狀態(tài)等。使用表格形式展示這些信息,方便用戶查看和編輯,方便用戶進行管理信息的管理。


          系統(tǒng)為管理提供了全面支持,包括新增記錄、編輯信息、刪除條目、數(shù)據(jù)導(dǎo)出、條件檢索及詳情查看等功能。用戶只需遵循頁面清晰的操作指引,即可輕松完成各項任務(wù)。界面設(shè)計遵循極簡原則,布局直觀,交互流暢,旨在營造無負擔(dān)的操作環(huán)境,顯著提升用戶的使用體驗與工作效率。

          3.2.7、認證授權(quán)


          認證授權(quán)管理功能主要字段信息包含:編碼、用戶賬號、用戶密碼、權(quán)限控制、角色授權(quán)、用戶登錄授權(quán)等。使用表格形式展示這些信息,方便用戶查看和編輯,方便用戶進行認證授權(quán)信息的管理。


          針對認證授權(quán)管理,系統(tǒng)精心設(shè)置了全方位功能模塊,涵蓋新增、編輯、刪除、導(dǎo)出、條件檢索以及查看詳情等核心操作。用戶在使用過程中,僅需緊密跟隨頁面內(nèi)直觀且詳盡的操作提示,即可輕松駕馭各項流程。我們秉持化繁為簡的理念,打造出簡約明快的界面風(fēng)格與邏輯清晰的操作流程,旨在讓用戶在高效管理數(shù)據(jù),享受到愉悅、無壓力的操作體驗。

          3.2.8、日志記錄管理


          管理功能主要字段信息包含:管理編碼、操作人員、操作時間、操作內(nèi)容、操作結(jié)果等。使用表格形式展示這些信息,方便用戶查看和編輯,方便用戶進行管理信息的管理。


          為實現(xiàn)對管理,系統(tǒng)精心配備了豐富的功能組件,包括新增、編輯、刪除、導(dǎo)出、條件搜以及詳情查看等實用操作。用戶在操作過程中,只需遵循頁面上清晰易懂的引導(dǎo)提示,即可順暢地完成各項任務(wù)。我們注重用戶體驗,以簡約而不失專業(yè)的界面設(shè)計,輔以直觀且高效的流程布局,旨在助力用戶在輕松管理數(shù)據(jù)同時,全面提升操作滿意度與工作效率。

          3.2.9、數(shù)據(jù)備份


          數(shù)據(jù)備份管理功能主要字段信息包含:編碼、備份名稱、備份時間、備份狀態(tài)、備份路徑、備份方式等。使用表格形式展示這些信息,方便用戶查看和編輯,方便用戶進行數(shù)據(jù)備份信息的管理。


          為滿足數(shù)據(jù)備份管理的多元需求,系統(tǒng)配置了一系列操作功能:新增、編輯、刪除、導(dǎo)出、搜索、詳情。用戶在實際操作中,僅需按照頁面上直觀且詳盡的操作提示,即可輕松駕馭各項流程。系統(tǒng)界面設(shè)計簡約清爽,操作邏輯清晰明了,旨在讓用戶在高效管理數(shù)據(jù)的同時,盡享流暢、無壓力的操作體驗,大幅提升工作效率與滿意度。

          3.2.10、數(shù)據(jù)恢復(fù)


          數(shù)據(jù)恢復(fù)管理功能主要字段信息包含:編碼、備份名稱、恢復(fù)時間、恢復(fù)方式、恢復(fù)狀態(tài)、恢復(fù)路徑等。使用表格形式展示這些信息,方便用戶查看和編輯,方便用戶進行數(shù)據(jù)恢復(fù)信息的管理。


          數(shù)據(jù)恢復(fù)管理設(shè)置新增、編輯、刪除、條件搜索、查看詳情等操作,可按照頁面提示進行操作執(zhí)行,界面結(jié)構(gòu)設(shè)計簡單,操作流程簡潔明了,可提升用戶操作體驗。

          3.2.11、私信管理


          管理功能主要字段信息包含:管理編碼、發(fā)送人、接收人、發(fā)送時間、私信內(nèi)容、是否已讀等。使用表格形式展示這些信息,方便用戶查看和編輯,方便用戶進行管理信息的管理。


          系統(tǒng)為管理提供了全面支持,包括新增記錄、編輯信息、刪除條目、數(shù)據(jù)導(dǎo)出、條件檢索及詳情查看等功能。用戶只需遵循頁面清晰的操作指引,即可輕松完成各項任務(wù)。界面設(shè)計遵循極簡原則,布局直觀,交互流暢,旨在營造無負擔(dān)的操作環(huán)境,顯著提升用戶的使用體驗與工作效率。

          3.2.12、統(tǒng)計報表


          統(tǒng)計報表管理功能主要字段信息包含:編碼、借還次數(shù)、資源使用率、用戶活躍度、資源維修情況、資源分類統(tǒng)計等。使用表格形式展示這些信息,方便用戶查看和編輯,方便用戶進行統(tǒng)計報表信息的管理。


          針對統(tǒng)計報表管理,系統(tǒng)精心設(shè)置了全方位功能模塊,涵蓋新增、編輯、刪除、導(dǎo)出、條件檢索以及查看詳情等核心操作。用戶在使用過程中,僅需緊密跟隨頁面內(nèi)直觀且詳盡的操作提示,即可輕松駕馭各項流程。我們秉持化繁為簡的理念,打造出簡約明快的界面風(fēng)格與邏輯清晰的操作流程,旨在讓用戶在高效管理數(shù)據(jù),享受到愉悅、無壓力的操作體驗。

          3.2.13、通知公告管理


          管理功能主要字段信息包含:管理編碼、標題、內(nèi)容、發(fā)布人、發(fā)布時間、是否置頂?shù)取J褂帽砀裥问秸故具@些信息,方便用戶查看和編輯,方便用戶進行管理信息的管理。


          為實現(xiàn)對管理,系統(tǒng)精心配備了豐富的功能組件,包括新增、編輯、刪除、導(dǎo)出、條件搜以及詳情查看等實用操作。用戶在操作過程中,只需遵循頁面上清晰易懂的引導(dǎo)提示,即可順暢地完成各項任務(wù)。我們注重用戶體驗,以簡約而不失專業(yè)的界面設(shè)計,輔以直觀且高效的流程布局,旨在助力用戶在輕松管理數(shù)據(jù)同時,全面提升操作滿意度與工作效率。

          3.2.14、維修管理


          管理功能主要字段信息包含:管理編碼、資源名稱、資源編號、維修人員、維修時間、維修內(nèi)容、維修備注等。使用表格形式展示這些信息,方便用戶查看和編輯,方便用戶進行管理信息的管理。


          為滿足管理的多元需求,系統(tǒng)配置了一系列操作功能:新增、編輯、刪除、導(dǎo)出、搜索、詳情。用戶在實際操作中,僅需按照頁面上直觀且詳盡的操作提示,即可輕松駕馭各項流程。系統(tǒng)界面設(shè)計簡約清爽,操作邏輯清晰明了,旨在讓用戶在高效管理數(shù)據(jù)的同時,盡享流暢、無壓力的操作體驗,大幅提升工作效率與滿意度。

          3.2.15、消息推送管理


          管理功能主要字段信息包含:管理編碼、推送類型、推送內(nèi)容、推送時間、推送狀態(tài)、推送對象等。使用表格形式展示這些信息,方便用戶查看和編輯,方便用戶進行管理信息的管理。


          管理設(shè)置新增、編輯、刪除、條件搜索、查看詳情等操作,可按照頁面提示進行操作執(zhí)行,界面結(jié)構(gòu)設(shè)計簡單,操作流程簡潔明了,可提升用戶操作體驗。

          3.2.16、用戶管理


          管理功能主要字段信息包含:管理編碼、用戶名、密碼、姓名、電子郵件地址、聯(lián)系電話等。使用表格形式展示這些信息,方便用戶查看和編輯,方便用戶進行管理信息的管理。


          系統(tǒng)為管理提供了全面支持,包括新增記錄、編輯信息、刪除條目、數(shù)據(jù)導(dǎo)出、條件檢索及詳情查看等功能。用戶只需遵循頁面清晰的操作指引,即可輕松完成各項任務(wù)。界面設(shè)計遵循極簡原則,布局直觀,交互流暢,旨在營造無負擔(dān)的操作環(huán)境,顯著提升用戶的使用體驗與工作效率。

          3.2.17、預(yù)約管理


          管理功能主要字段信息包含:管理編碼、預(yù)約人員、預(yù)約時間、預(yù)約資源、預(yù)約目的、預(yù)約狀態(tài)等。使用表格形式展示這些信息,方便用戶查看和編輯,方便用戶進行管理信息的管理。


          針對管理,系統(tǒng)精心設(shè)置了全方位功能模塊,涵蓋新增、編輯、刪除、導(dǎo)出、條件檢索以及查看詳情等核心操作。用戶在使用過程中,僅需緊密跟隨頁面內(nèi)直觀且詳盡的操作提示,即可輕松駕馭各項流程。我們秉持化繁為簡的理念,打造出簡約明快的界面風(fēng)格與邏輯清晰的操作流程,旨在讓用戶在高效管理數(shù)據(jù),享受到愉悅、無壓力的操作體驗。

          3.2.18、資源分類管理


          管理功能主要字段信息包含:管理編碼、分類名稱、分類描述、分類編號、創(chuàng)建時間、修改時間等。使用表格形式展示這些信息,方便用戶查看和編輯,方便用戶進行管理信息的管理。


          為實現(xiàn)對管理,系統(tǒng)精心配備了豐富的功能組件,包括新增、編輯、刪除、導(dǎo)出、條件搜以及詳情查看等實用操作。用戶在操作過程中,只需遵循頁面上清晰易懂的引導(dǎo)提示,即可順暢地完成各項任務(wù)。我們注重用戶體驗,以簡約而不失專業(yè)的界面設(shè)計,輔以直觀且高效的流程布局,旨在助力用戶在輕松管理數(shù)據(jù)同時,全面提升操作滿意度與工作效率。

          3.2.19、資源管理


          管理功能主要字段信息包含:管理編碼、資源名稱、資源類型、資源描述、資源編號、資源狀態(tài)、創(chuàng)建時間、修改時間、所屬分類、所屬部門、負責(zé)人等。使用表格形式展示這些信息,方便用戶查看和編輯,方便用戶進行管理信息的管理。


          為滿足管理的多元需求,系統(tǒng)配置了一系列操作功能:新增、編輯、刪除、導(dǎo)出、搜索、詳情。用戶在實際操作中,僅需按照頁面上直觀且詳盡的操作提示,即可輕松駕馭各項流程。系統(tǒng)界面設(shè)計簡約清爽,操作邏輯清晰明了,旨在讓用戶在高效管理數(shù)據(jù)的同時,盡享流暢、無壓力的操作體驗,大幅提升工作效率與滿意度。

          四、注意事項


          系統(tǒng)支持唯一登錄,一個賬號同時只能由一人使用。信息展示順序如果特殊說明,按照排序索引值從大到小進行排序。數(shù)據(jù)刪除之后,其關(guān)聯(lián)的數(shù)據(jù)將不可用使用,或無法正常顯示。內(nèi)容狀態(tài)一般為正常時,表示數(shù)據(jù)可正常使用操作,如果為異常或者未審核,則表示在關(guān)聯(lián)數(shù)據(jù)調(diào)用時,不會顯示。



          、簡介

          1.1、開發(fā)目的和背景


          隨著保險行業(yè)的發(fā)展,對業(yè)務(wù)流程的自動化和信息化需求日益增強。保單智慧管理系統(tǒng)應(yīng)運而生,其核心目標是為了提升保險公司運營效率,優(yōu)化客戶體驗,并實現(xiàn)業(yè)務(wù)數(shù)據(jù)的高效管理和分析。


          在過去的傳統(tǒng)模式中,保險公司往往需要通過人工操作來處理大量的保單信息,這不僅耗時,且容易出錯,影響服務(wù)質(zhì)量和決策效率。本軟件旨在打破這種限制,將繁瑣的流程數(shù)字化,通過智能化的方式,如一鍵查詢、自動計算、實時更新等功能,實現(xiàn)保單信息的一體化管理。


          保單查詢模塊讓用戶能夠快速找到所需信息,保費查詢和管理則有助于精確跟蹤保險費用,提高資金利用率。保險產(chǎn)品和計劃管理模塊幫助保險公司靈活調(diào)整策略,適應(yīng)市場變化。承保、導(dǎo)入導(dǎo)出、告知事項管理等功能,保證了業(yè)務(wù)流程的順暢進行。


          同時,系統(tǒng)還涵蓋了人員管理,如銷售人員、管理員和客戶信息的高效管理,以及投訴和理賠的跟蹤處理,這些都是提升服務(wù)質(zhì)量的關(guān)鍵。數(shù)據(jù)備份與恢復(fù)功能確保了信息安全,而統(tǒng)計分析和團險管理模塊,則為決策者提供了有力的數(shù)據(jù)支持,幫助他們做出更科學(xué)的決策。


          總的來說,保單智慧管理系統(tǒng)是在洞察行業(yè)痛點和用戶需求的基礎(chǔ)上,結(jié)合現(xiàn)代科技手段,打造的一款集高效、便捷、安全于一體的全方位保險管理工具。它的實施,旨在推動保險行業(yè)的數(shù)字化轉(zhuǎn)型,推動行業(yè)整體效率的提升,為保險公司創(chuàng)造更大的商業(yè)價值,也為客戶提供更加便捷、貼心的服務(wù)體驗。

          1.2、軟件的目標用戶


          在保單智慧管理系統(tǒng)中,一個典型的應(yīng)用場景可能是這樣的:保險公司或保險經(jīng)紀公司的工作人員,例如客戶服務(wù)專員、保險顧問、理賠人員等,每天面對著大量的保單數(shù)據(jù)和客戶請求。他們可以利用系統(tǒng)進行高效的操作。比如,當接到客戶咨詢時,他們可以通過保單查詢模塊迅速找到客戶的詳細信息;通過保費查詢和管理功能,了解客戶的繳費狀態(tài);通過產(chǎn)品管理和計劃管理,為客戶提供最適合的保險產(chǎn)品推薦;對于承保和理賠過程,系統(tǒng)提供了標準化的流程管理,大大提高了處理效率。


          當有新數(shù)據(jù)需要導(dǎo)入或者現(xiàn)有數(shù)據(jù)需要導(dǎo)出時,導(dǎo)入導(dǎo)出功能使得數(shù)據(jù)整合和分享變得簡單;告知事項管理幫助他們跟蹤并確保不會錯過任何重要的通知或更新;管理員和銷售人員管理模塊則有助于團隊協(xié)作和績效追蹤。


          此外,對于大規(guī)模的團險管理、營銷活動管理和續(xù)保管理,系統(tǒng)提供了強大的工具,幫助保險公司更好地執(zhí)行策略并保持客戶關(guān)系。


          該軟件的主要目標用戶是各類保險公司、保險經(jīng)紀公司以及他們的內(nèi)部工作人員,特別是那些負責(zé)客戶服務(wù)、銷售、承保、理賠及數(shù)據(jù)分析的團隊。他們需要處理大量保單信息,進行日常操作,并需要系統(tǒng)來提升工作流程的效率和準確性。此外,企業(yè)決策者也可能使用該系統(tǒng)來獲取實時的業(yè)務(wù)統(tǒng)計和分析報告,以支持戰(zhàn)略規(guī)劃和優(yōu)化。因此,無論是一線操作人員還是管理層,保單智慧管理系統(tǒng)都能提供所需的功能支持。

          二、軟件總體設(shè)計

          2.1、系統(tǒng)概述


          保單智慧管理系統(tǒng)是一款專為保險公司和相關(guān)機構(gòu)設(shè)計的高效信息化解決方案,采用Java語言和SpringMVC開發(fā)框架構(gòu)建,數(shù)據(jù)庫選用了穩(wěn)定可靠的MySQL。該系統(tǒng)旨在通過集成化的功能,簡化業(yè)務(wù)流程,提升運營效率。


          1. 保單查詢與管理:用戶可以快速查找并查看保單詳細信息,包括保單狀態(tài)、保障內(nèi)容等,方便日常管理和跟蹤。


          2. 保費管理:提供保費計算、支付記錄以及自動提醒功能,確保保費及時準確無誤。


          3. 保險產(chǎn)品與計劃管理:支持多類型保險產(chǎn)品的錄入、更新和銷售計劃制定,便于產(chǎn)品推廣和市場分析。


          4. 承保與理賠:簡化承保申請?zhí)幚砹鞒蹋瑫r提供在線理賠查詢和申請功能,提升客戶滿意度。


          5. 數(shù)據(jù)導(dǎo)入導(dǎo)出:支持各種格式的數(shù)據(jù)導(dǎo)入,方便數(shù)據(jù)整合和遷移,導(dǎo)出功能則有利于報告生成和審計。


          6. 統(tǒng)計分析與報告:通過強大的數(shù)據(jù)分析引擎,生成各類業(yè)務(wù)報表,幫助決策者做出明智的策略調(diào)整。


          7. 團險及銷售人員管理:方便對團隊工作進行跟蹤和評估,提升銷售團隊效能。


          8. 客戶關(guān)系管理:集成客戶信息管理、投訴處理等功能,實現(xiàn)全方位的客戶關(guān)懷。


          9. 安全與備份恢復(fù):系統(tǒng)內(nèi)置嚴格的權(quán)限控制和數(shù)據(jù)加密,確保信息安全,并支持定期數(shù)據(jù)備份與恢復(fù)。


          總之,保單智慧管理系統(tǒng)旨在通過高度自動化和智能化的功能,幫助用戶優(yōu)化業(yè)務(wù)流程,提升服務(wù)質(zhì)量,降低運營成本,從而在競爭激烈的保險市場中占據(jù)優(yōu)勢。

          2.2、系統(tǒng)架構(gòu)

          保單智慧管理系統(tǒng)是一款基于B/S(Browser/Server)架構(gòu)的全面解決方案,核心采用Java和Spring MVC技術(shù)構(gòu)建。該架構(gòu)設(shè)計旨在提供高效、穩(wěn)定且易擴展的服務(wù)。


          1. 前端界面:用戶通過瀏覽器訪問,圖形用戶界面(GUI)友好,簡潔直觀。采用了HTML5、CSS3和JavaScript進行頁面設(shè)計,使得跨平臺兼容性得到保障,無論是在PC還是移動設(shè)備上,都能流暢操作。


          2. 后端服務(wù):Java作為服務(wù)器端開發(fā)語言,其強大的面向?qū)ο筇匦允沟孟到y(tǒng)的業(yè)務(wù)邏輯處理更為清晰。Spring MVC框架則提供了分層架構(gòu),包括模型(Model)、視圖(View)和控制器(Controller),實現(xiàn)了松耦合和高內(nèi)聚。


          - 模型層(Model):負責(zé)業(yè)務(wù)邏輯和數(shù)據(jù)處理,如保單查詢、保費計算等。這些核心業(yè)務(wù)邏輯通過DAO(Data Access Object)與數(shù)據(jù)庫交互。


          - 視圖層(View):主要負責(zé)展示數(shù)據(jù),如JSP或Thymeleaf模板引擎生成的HTML頁面,用于顯示查詢結(jié)果和用戶輸入界面。


          - 控制器層(Controller):接收用戶請求,調(diào)用相應(yīng)模型層的方法,處理數(shù)據(jù),并將結(jié)果傳遞給視圖層。


          3. 服務(wù)模塊:如保單信息管理、保費管理等,每個模塊都是一個獨立的服務(wù),可以單獨測試和維護。這種模塊化設(shè)計提高了代碼復(fù)用性和可維護性。


          4. 數(shù)據(jù)庫管理:系統(tǒng)使用關(guān)系型數(shù)據(jù)庫(如MySQL或Oracle),通過ORM工具如MyBatis實現(xiàn)數(shù)據(jù)持久化,保證了數(shù)據(jù)的一致性和安全性。


          5. 安全性:系統(tǒng)內(nèi)置了用戶權(quán)限管理和身份驗證機制,以HTTPS加密通信,確保數(shù)據(jù)傳輸過程中的隱私和安全。


          6. 數(shù)據(jù)備份與恢復(fù):定期自動備份數(shù)據(jù),以防數(shù)據(jù)丟失。同時提供數(shù)據(jù)恢復(fù)功能,保證在出現(xiàn)意外時能快速恢復(fù)服務(wù)。


          7. 統(tǒng)計分析:通過集成數(shù)據(jù)分析工具,對系統(tǒng)產(chǎn)生的大量數(shù)據(jù)進行深入挖掘和報告生成,支持決策制定。


          8. 多模塊協(xié)作:團險管理、銷售人員管理等模塊間的協(xié)同工作通過事件驅(qū)動或者消息隊列機制實現(xiàn),保證系統(tǒng)的實時性和響應(yīng)速度。


          綜上所述,保單智慧管理系統(tǒng)采用先進的技術(shù)棧和模塊化設(shè)計,旨在提供一個功能齊全、高效穩(wěn)定、易于維護的保險業(yè)務(wù)處理平臺。

          三、軟件使用說明

          3.1、系統(tǒng)登錄


          在瀏覽器中輸入系統(tǒng)網(wǎng)址,打開登錄界面后輸入登錄賬號、登錄密碼、驗證碼即可登錄。

          3.2、工作臺


          工作臺包含:保單查詢、保單信息管理、保費查詢、保費管理、保險產(chǎn)品管理、產(chǎn)品計劃管理、承保管理、導(dǎo)入導(dǎo)出、告知事項管理、管理員信息管理、客戶投訴管理、客戶信息管理、理賠查詢、理賠管理、數(shù)據(jù)備份與恢復(fù)、統(tǒng)計分析、團險管理、銷售人員管理、續(xù)保管理、營銷活動管理,根據(jù)不同角色權(quán)限菜單展示會有所區(qū)別。

          3.2.1、保單查詢


          保單查詢管理功能主要字段信息包含:編碼、保單號、客戶姓名、投保人姓名、保單狀態(tài)、保險公司、保險產(chǎn)品、繳費周期、保費、保險期限、理賠狀態(tài)等。使用表格形式展示這些信息,方便用戶查看和編輯,方便用戶進行保單查詢信息的管理。


          為滿足保單查詢管理的多元需求,系統(tǒng)配置了一系列操作功能:新增、編輯、刪除、導(dǎo)出、搜索、詳情。用戶在實際操作中,僅需按照頁面上直觀且詳盡的操作提示,即可輕松駕馭各項流程。系統(tǒng)界面設(shè)計簡約清爽,操作邏輯清晰明了,旨在讓用戶在高效管理數(shù)據(jù)的同時,盡享流暢、無壓力的操作體驗,大幅提升工作效率與滿意度。

          3.2.2、保單信息管理


          保單管理功能主要字段信息包含:保單管理編碼、保單號、投保人姓名、聯(lián)系方式、保險公司、保險產(chǎn)品、保單狀態(tài)、保險期限、保費、理賠記錄等。使用表格形式展示這些信息,方便用戶查看和編輯,方便用戶進行保單管理信息的管理。


          保單管理設(shè)置新增、編輯、刪除、條件搜索、查看詳情等操作,可按照頁面提示進行操作執(zhí)行,界面結(jié)構(gòu)設(shè)計簡單,操作流程簡潔明了,可提升用戶操作體驗。

          3.2.3、保費查詢


          保費查詢管理功能主要字段信息包含:編碼、保費記錄編號、客戶姓名、保費金額、繳費方式、繳費日期、保費狀態(tài)、應(yīng)收/實收金額、扣費日期等。使用表格形式展示這些信息,方便用戶查看和編輯,方便用戶進行保費查詢信息的管理。


          系統(tǒng)為保費查詢管理提供了全面支持,包括新增記錄、編輯信息、刪除條目、數(shù)據(jù)導(dǎo)出、條件檢索及詳情查看等功能。用戶只需遵循頁面清晰的操作指引,即可輕松完成各項任務(wù)。界面設(shè)計遵循極簡原則,布局直觀,交互流暢,旨在營造無負擔(dān)的操作環(huán)境,顯著提升用戶的使用體驗與工作效率。

          3.2.4、保費管理


          管理功能主要字段信息包含:管理編碼、保費記錄編號、客戶姓名、保費金額、繳費方式、繳費日期、保費狀態(tài)、應(yīng)收/實收金額、扣費日期等。使用表格形式展示這些信息,方便用戶查看和編輯,方便用戶進行管理信息的管理。


          針對管理,系統(tǒng)精心設(shè)置了全方位功能模塊,涵蓋新增、編輯、刪除、導(dǎo)出、條件檢索以及查看詳情等核心操作。用戶在使用過程中,僅需緊密跟隨頁面內(nèi)直觀且詳盡的操作提示,即可輕松駕馭各項流程。我們秉持化繁為簡的理念,打造出簡約明快的界面風(fēng)格與邏輯清晰的操作流程,旨在讓用戶在高效管理數(shù)據(jù),享受到愉悅、無壓力的操作體驗。

          3.2.5、保險產(chǎn)品管理


          管理功能主要字段信息包含:管理編碼、保險產(chǎn)品編號、保險公司、產(chǎn)品名稱、產(chǎn)品類型、適用人群、保額、保費、保險期限、免賠額等。使用表格形式展示這些信息,方便用戶查看和編輯,方便用戶進行管理信息的管理。


          為實現(xiàn)對管理,系統(tǒng)精心配備了豐富的功能組件,包括新增、編輯、刪除、導(dǎo)出、條件搜以及詳情查看等實用操作。用戶在操作過程中,只需遵循頁面上清晰易懂的引導(dǎo)提示,即可順暢地完成各項任務(wù)。我們注重用戶體驗,以簡約而不失專業(yè)的界面設(shè)計,輔以直觀且高效的流程布局,旨在助力用戶在輕松管理數(shù)據(jù)同時,全面提升操作滿意度與工作效率。

          3.2.6、產(chǎn)品計劃管理


          管理功能主要字段信息包含:管理編碼、產(chǎn)品計劃編號、保險公司名稱、產(chǎn)品名稱、產(chǎn)品類型、適用人群、保額、保費、保險期限、免賠額等。使用表格形式展示這些信息,方便用戶查看和編輯,方便用戶進行管理信息的管理。


          為滿足管理的多元需求,系統(tǒng)配置了一系列操作功能:新增、編輯、刪除、導(dǎo)出、搜索、詳情。用戶在實際操作中,僅需按照頁面上直觀且詳盡的操作提示,即可輕松駕馭各項流程。系統(tǒng)界面設(shè)計簡約清爽,操作邏輯清晰明了,旨在讓用戶在高效管理數(shù)據(jù)的同時,盡享流暢、無壓力的操作體驗,大幅提升工作效率與滿意度。

          3.2.7、承保管理


          管理功能主要字段信息包含:管理編碼、承保記錄編號、保單號、客戶姓名、保險產(chǎn)品、承保時間、承保狀態(tài)、承保金額、投保人姓名、聯(lián)系方式等。使用表格形式展示這些信息,方便用戶查看和編輯,方便用戶進行管理信息的管理。


          管理設(shè)置新增、編輯、刪除、條件搜索、查看詳情等操作,可按照頁面提示進行操作執(zhí)行,界面結(jié)構(gòu)設(shè)計簡單,操作流程簡潔明了,可提升用戶操作體驗。

          3.2.8、導(dǎo)入導(dǎo)出


          導(dǎo)入導(dǎo)出管理功能主要字段信息包含:編碼、數(shù)據(jù)導(dǎo)入導(dǎo)出、支持各種格式的數(shù)據(jù)導(dǎo)入導(dǎo)出等。使用表格形式展示這些信息,方便用戶查看和編輯,方便用戶進行導(dǎo)入導(dǎo)出信息的管理。


          系統(tǒng)為導(dǎo)入導(dǎo)出管理提供了全面支持,包括新增記錄、編輯信息、刪除條目、數(shù)據(jù)導(dǎo)出、條件檢索及詳情查看等功能。用戶只需遵循頁面清晰的操作指引,即可輕松完成各項任務(wù)。界面設(shè)計遵循極簡原則,布局直觀,交互流暢,旨在營造無負擔(dān)的操作環(huán)境,顯著提升用戶的使用體驗與工作效率。

          3.2.9、告知事項管理


          管理功能主要字段信息包含:管理編碼、告知事項編號、投保單號、客戶姓名、告知事項類別、告知事項內(nèi)容、告知時間、責(zé)任人等。使用表格形式展示這些信息,方便用戶查看和編輯,方便用戶進行管理信息的管理。


          針對管理,系統(tǒng)精心設(shè)置了全方位功能模塊,涵蓋新增、編輯、刪除、導(dǎo)出、條件檢索以及查看詳情等核心操作。用戶在使用過程中,僅需緊密跟隨頁面內(nèi)直觀且詳盡的操作提示,即可輕松駕馭各項流程。我們秉持化繁為簡的理念,打造出簡約明快的界面風(fēng)格與邏輯清晰的操作流程,旨在讓用戶在高效管理數(shù)據(jù),享受到愉悅、無壓力的操作體驗。

          3.2.10、管理員信息管理


          管理員管理功能主要字段信息包含:管理員管理編碼、管理員編號、管理員姓名、聯(lián)系方式、用戶名、密碼、角色等。使用表格形式展示這些信息,方便用戶查看和編輯,方便用戶進行管理員管理信息的管理。


          為實現(xiàn)對管理員管理,系統(tǒng)精心配備了豐富的功能組件,包括新增、編輯、刪除、導(dǎo)出、條件搜以及詳情查看等實用操作。用戶在操作過程中,只需遵循頁面上清晰易懂的引導(dǎo)提示,即可順暢地完成各項任務(wù)。我們注重用戶體驗,以簡約而不失專業(yè)的界面設(shè)計,輔以直觀且高效的流程布局,旨在助力用戶在輕松管理數(shù)據(jù)同時,全面提升操作滿意度與工作效率。

          3.2.11、客戶投訴管理


          管理功能主要字段信息包含:管理編碼、投訴記錄編號、投訴時間、投訴內(nèi)容、投訴人姓名、聯(lián)系方式、處理人姓名、處理結(jié)果、處理時間等。使用表格形式展示這些信息,方便用戶查看和編輯,方便用戶進行管理信息的管理。


          為滿足管理的多元需求,系統(tǒng)配置了一系列操作功能:新增、編輯、刪除、導(dǎo)出、搜索、詳情。用戶在實際操作中,僅需按照頁面上直觀且詳盡的操作提示,即可輕松駕馭各項流程。系統(tǒng)界面設(shè)計簡約清爽,操作邏輯清晰明了,旨在讓用戶在高效管理數(shù)據(jù)的同時,盡享流暢、無壓力的操作體驗,大幅提升工作效率與滿意度。

          3.2.12、客戶信息管理


          客戶管理功能主要字段信息包含:客戶管理編碼、客戶編號、客戶姓名、聯(lián)系方式、證件類型、證件號碼、出生日期、性別、職業(yè)、居住地址等。使用表格形式展示這些信息,方便用戶查看和編輯,方便用戶進行客戶管理信息的管理。


          客戶管理設(shè)置新增、編輯、刪除、條件搜索、查看詳情等操作,可按照頁面提示進行操作執(zhí)行,界面結(jié)構(gòu)設(shè)計簡單,操作流程簡潔明了,可提升用戶操作體驗。

          3.2.13、理賠查詢


          理賠查詢管理功能主要字段信息包含:編碼、理賠記錄編號、保單號、客戶姓名、理賠類型、理賠原因、理賠金額、理賠狀態(tài)、理賠時間、理賠結(jié)果等。使用表格形式展示這些信息,方便用戶查看和編輯,方便用戶進行理賠查詢信息的管理。


          系統(tǒng)為理賠查詢管理提供了全面支持,包括新增記錄、編輯信息、刪除條目、數(shù)據(jù)導(dǎo)出、條件檢索及詳情查看等功能。用戶只需遵循頁面清晰的操作指引,即可輕松完成各項任務(wù)。界面設(shè)計遵循極簡原則,布局直觀,交互流暢,旨在營造無負擔(dān)的操作環(huán)境,顯著提升用戶的使用體驗與工作效率。

          3.2.14、理賠管理


          管理功能主要字段信息包含:管理編碼、理賠記錄編號、保單號、客戶姓名、理賠類型、理賠原因、理賠金額、理賠狀態(tài)、理賠時間、理賠結(jié)果等。使用表格形式展示這些信息,方便用戶查看和編輯,方便用戶進行管理信息的管理。


          針對管理,系統(tǒng)精心設(shè)置了全方位功能模塊,涵蓋新增、編輯、刪除、導(dǎo)出、條件檢索以及查看詳情等核心操作。用戶在使用過程中,僅需緊密跟隨頁面內(nèi)直觀且詳盡的操作提示,即可輕松駕馭各項流程。我們秉持化繁為簡的理念,打造出簡約明快的界面風(fēng)格與邏輯清晰的操作流程,旨在讓用戶在高效管理數(shù)據(jù),享受到愉悅、無壓力的操作體驗。

          3.2.15、數(shù)據(jù)備份與恢復(fù)


          數(shù)據(jù)備份與恢復(fù)管理功能主要字段信息包含:編碼、數(shù)據(jù)備份、數(shù)據(jù)恢復(fù)、定期備份數(shù)據(jù)并保證數(shù)據(jù)安全等。使用表格形式展示這些信息,方便用戶查看和編輯,方便用戶進行數(shù)據(jù)備份與恢復(fù)信息的管理。


          為實現(xiàn)對數(shù)據(jù)備份與恢復(fù)管理,系統(tǒng)精心配備了豐富的功能組件,包括新增、編輯、刪除、導(dǎo)出、條件搜以及詳情查看等實用操作。用戶在操作過程中,只需遵循頁面上清晰易懂的引導(dǎo)提示,即可順暢地完成各項任務(wù)。我們注重用戶體驗,以簡約而不失專業(yè)的界面設(shè)計,輔以直觀且高效的流程布局,旨在助力用戶在輕松管理數(shù)據(jù)同時,全面提升操作滿意度與工作效率。

          3.2.16、統(tǒng)計分析


          統(tǒng)計分析管理功能主要字段信息包含:編碼、保單數(shù)量、投保人數(shù)量、保費總額、賠款總額、理賠數(shù)量、理賠比例、每個產(chǎn)品的銷售數(shù)量及保費總額等。使用表格形式展示這些信息,方便用戶查看和編輯,方便用戶進行統(tǒng)計分析信息的管理。


          為滿足統(tǒng)計分析管理的多元需求,系統(tǒng)配置了一系列操作功能:新增、編輯、刪除、導(dǎo)出、搜索、詳情。用戶在實際操作中,僅需按照頁面上直觀且詳盡的操作提示,即可輕松駕馭各項流程。系統(tǒng)界面設(shè)計簡約清爽,操作邏輯清晰明了,旨在讓用戶在高效管理數(shù)據(jù)的同時,盡享流暢、無壓力的操作體驗,大幅提升工作效率與滿意度。

          3.2.17、團險管理


          管理功能主要字段信息包含:管理編碼、團險編號、保險公司名稱、團險名稱、團險人數(shù)、團險保費、生效日期、失效日期、團險狀態(tài)等。使用表格形式展示這些信息,方便用戶查看和編輯,方便用戶進行管理信息的管理。


          管理設(shè)置新增、編輯、刪除、條件搜索、查看詳情等操作,可按照頁面提示進行操作執(zhí)行,界面結(jié)構(gòu)設(shè)計簡單,操作流程簡潔明了,可提升用戶操作體驗。

          3.2.18、銷售人員管理


          管理功能主要字段信息包含:管理編碼、銷售人員編號、銷售人員姓名、聯(lián)系方式、所屬機構(gòu)、崗位職責(zé)、員工狀態(tài)、入職時間、離職時間等。使用表格形式展示這些信息,方便用戶查看和編輯,方便用戶進行管理信息的管理。


          系統(tǒng)為管理提供了全面支持,包括新增記錄、編輯信息、刪除條目、數(shù)據(jù)導(dǎo)出、條件檢索及詳情查看等功能。用戶只需遵循頁面清晰的操作指引,即可輕松完成各項任務(wù)。界面設(shè)計遵循極簡原則,布局直觀,交互流暢,旨在營造無負擔(dān)的操作環(huán)境,顯著提升用戶的使用體驗與工作效率。

          3.2.19、續(xù)保管理


          管理功能主要字段信息包含:管理編碼、續(xù)保記錄編號、保單號、客戶姓名、保險產(chǎn)品、續(xù)保時間、續(xù)保狀態(tài)、續(xù)保金額、投保人姓名、聯(lián)系方式等。使用表格形式展示這些信息,方便用戶查看和編輯,方便用戶進行管理信息的管理。


          針對管理,系統(tǒng)精心設(shè)置了全方位功能模塊,涵蓋新增、編輯、刪除、導(dǎo)出、條件檢索以及查看詳情等核心操作。用戶在使用過程中,僅需緊密跟隨頁面內(nèi)直觀且詳盡的操作提示,即可輕松駕馭各項流程。我們秉持化繁為簡的理念,打造出簡約明快的界面風(fēng)格與邏輯清晰的操作流程,旨在讓用戶在高效管理數(shù)據(jù),享受到愉悅、無壓力的操作體驗。

          3.2.20、營銷活動管理


          管理功能主要字段信息包含:管理編碼、活動編號、所屬機構(gòu)、活動名稱、活動類型、活動開始時間、活動結(jié)束時間、活動狀態(tài)、參與客戶數(shù)量、活動內(nèi)容等。使用表格形式展示這些信息,方便用戶查看和編輯,方便用戶進行管理信息的管理。


          為實現(xiàn)對管理,系統(tǒng)精心配備了豐富的功能組件,包括新增、編輯、刪除、導(dǎo)出、條件搜以及詳情查看等實用操作。用戶在操作過程中,只需遵循頁面上清晰易懂的引導(dǎo)提示,即可順暢地完成各項任務(wù)。我們注重用戶體驗,以簡約而不失專業(yè)的界面設(shè)計,輔以直觀且高效的流程布局,旨在助力用戶在輕松管理數(shù)據(jù)同時,全面提升操作滿意度與工作效率。

          四、注意事項


          系統(tǒng)支持唯一登錄,一個賬號同時只能由一人使用。信息展示順序如果特殊說明,按照排序索引值從大到小進行排序。數(shù)據(jù)刪除之后,其關(guān)聯(lián)的數(shù)據(jù)將不可用使用,或無法正常顯示。內(nèi)容狀態(tài)一般為正常時,表示數(shù)據(jù)可正常使用操作,如果為異常或者未審核,則表示在關(guān)聯(lián)數(shù)據(jù)調(diào)用時,不會顯示。


          主站蜘蛛池模板: 东京热人妻无码一区二区av| 亚洲国产综合无码一区二区二三区| 亚洲av乱码一区二区三区香蕉 | 色噜噜AV亚洲色一区二区| 冲田杏梨高清无一区二区| 国产成人久久精品一区二区三区| 亚洲熟妇AV一区二区三区宅男| 精品无码综合一区| 久久精品道一区二区三区| 精品一区二区三区电影| 久久精品午夜一区二区福利 | 精品乱码一区二区三区在线| 久久国产精品无码一区二区三区| 久久久99精品一区二区| 春暖花开亚洲性无区一区二区 | 熟女少妇精品一区二区| 视频一区二区精品的福利| 无码人妻精品一区二区三区99性| 夜夜精品视频一区二区| 一区二区三区四区精品| 国产一区二区三区日韩精品| 色窝窝免费一区二区三区| 日本免费电影一区二区| 久久精品国产亚洲一区二区三区| 国产麻豆精品一区二区三区v视界| 日韩高清一区二区三区不卡 | 欧洲无码一区二区三区在线观看 | 国产在线观看一区二区三区 | 视频一区视频二区在线观看| 精品欧洲AV无码一区二区男男 | 久久精品一区二区| 国产精品乱码一区二区三| 国产亚洲情侣一区二区无| 亚洲AV无码一区二三区| 日本福利一区二区| 亚洲AV无码一区二区三区性色| 国产精品资源一区二区| 精品国产免费观看一区 | 久久精品视频一区二区三区| 日本不卡一区二区视频a| 天天综合色一区二区三区|