【原理分析】Mock.js:我是如何「科學造假」的

Mock.js 主要乾了兩件事:javascript

  • 生成隨機數據
  • 攔截 Ajax 請求

走走,這就去看看是咋回事兒html

image.png

如何生成隨機數據

Mock.mock(template) 的工做原理前端

// 屬性名 name
// 生成規則 rule
// 屬性值 value
"name|rule": value
複製代碼

原理概述

正則拆分,分類處理java

  1. 根據 template 的類型,來調用對應的 handler 處理
  2. 藉助正則,在步驟 1 中,將當前處理的屬性名拆成 name, rule 兩部分
  3. handler 中,依據生成規則 rule,佔位符 placeholder 處理生成對應的 value
  4. 如爲對象,各屬性按步驟 1 繼續處理

舉個例子

以常見的狀況爲例,看源碼中的相關處理方式git

能夠在控制檯中實驗一波:mockjs.com/examples.ht…github

Mock.mock({
  "apples": {
      "weight": "@range(5)",
      "color|5": ["red"]
  },
  "sum": "@./apples/weight",
  "copy": "@sum"
})
複製代碼

1. Mock.mock(template) ->源碼直通車

只傳入模版,調用 Handler.gen(template) ->源碼直通車數組

2. Handler.gen(template, name, context)

此時 template 的類型爲 object,接下來調用 Handler['object']微信

Handler['object'] 的返回值會做爲 mock 的結果markdown

3. Handler['object'] ->源碼直通車

字段中包含 template,表示包含生成規則的 **app

path 指不包含生成規則的訪問路徑;templatePath指包含生成規則的訪問路徑

依次處理屬性,遞歸調用 Handler.gen(template, name, context)

template 爲當前處理到的屬性名 name(包含生成規則)對應的屬性值

在處理過程當中維護 context 中記錄的字段:

  • path / templatePath:記錄當前訪問路徑
  • currentContext / templateCurrentContext:處理完的數據
  • root / templateRoot:根對象

首次調用會將對應的數據保存到 root / templateRoot

4. Handler['string'] ->源碼直通車

"weight": "@range(5)" 或 "sum": "@./apples/weight" 或 "copy": "@sum"

空字符串

  • 如指定生成規則,則取對應個數的隨機字符;不然,直接取空字符串

    "ASCII|1-10": "" => 1~10 內取一隨機數做爲個數

非空字符串

  • 根據生成規則中指定的數字,獲得一待處理的完整字符串

  • 依次處理可能的佔位符,調用 Handler.placeholder(placeholder, obj, templateContext, options) 獲得對應的值,替換原有佔位符

    "@range(5)@test" => ["@range(5)", "@test"]

  • placeholder,待處理的佔位符,如"@range(5)"

  • obj / templateContext,對應前文 context 中保存的 currentContext / templateCurrentContext,處理完的數據

  • options,傳給該處理函數的全部字段,如當前處理的屬性值類型 type,屬性值模版 template,上下文 context 等等 ->源碼直通車

5. Handler.placeholder(placeholder, obj, templateContext, options) ->源碼直通車

拆分佔位符,獲得對應的名稱(下文以 key 代指)及參數

引用模版中屬性

"copy": "@sum"

  • obj[key] 已處理完,則直接使用(示例狀況)
  • key 還未處理到,則調用 Handler.gen,先計算被引用的屬性值

絕對 / 相對路徑

"sum": "@./apples/weight"

Handler.gen 首次執行時,將 1 做爲路徑根 ->源碼直通車

依次處理 path 路徑數組

  • 佔位符拆分,獲得路徑數組,拼接成絕對路徑

    • 當前路徑:[1, "sum"]
    • 相對路徑:[".", "apples", "weight"]
    • 絕對路徑:[1, "apples", "weight"]
  • 根據路徑,從 options 中的 context 裏,依據 root / templateRoot,依次向下取值

    • 已處理,直接用
    • 未處理,調用 Handler.gen,先計算被引用的屬性值
  • 路徑沒找到,返回 undefined

特定佔位符

"weight": "@range(5)"

Random 文件夾下,內置了許多隨機生成函數

  • Random 中有對應 key

    • 函數類型,傳參數,直接調用
    • 數組類型,隨機取一個
  • 無對應 key,佔位符原樣返回

6. Handler['array'] ->源碼直通車

"color|5": ["red"]

空數組

直接返回 ""

非空數組

  • 如無生成規則,直接遍歷元素,遞歸調用 Handler.gen
  • 若有,則會在遍歷過程當中處理,如從數組中隨機取一個生成,重複添加屢次等

關係總覽

mock(template).jpg

如何攔截 Ajax 請求

Mock.mock( rurl, rtype?, template|function(options)) 的工做原理

原理概述

從 1.0 開始,Mock.js 經過覆蓋模擬原生 XMLHttpRequest 的行爲來攔截 Ajax 請求

->源碼直通車

  1. MockXMLHttpRequest 上有一屬性 Mock,其中的 _mocked 會記錄須要攔截的請求

  2. MockXMLHttpRequest 覆蓋原生 window.XMLHttpRequest

  3. open 中,若是初始化的 urlmethod,在 _mocked 中找到,則會打上攔截標記(原型屬性 match,置爲 true),不然使用原生 XHR

  4. send 中,經過攔截標記判斷是否使用原生 XHR,如攔截請求,根據 template|function(options) ,設置響應數據:

    1. 傳入函數,返回函數調用結果
    2. 傳入 template,利用 Mock.mock,返回生成的假數據

關係總覽

mock 攔截請求.jpg

字節跳動幸福裏前端團隊急缺人才(校招/社招大量HC),歡迎加我微信 orca_o 諮詢~

相關文章:雙非大三,無實習經歷,如何以 hard 模式逆襲字節跳動(附春招筆記/字節內推)

相關文章
相關標籤/搜索