前言
前文傳送地址:
連續(xù)四篇設(shè)計模式都是前端經(jīng)常使用到的,相信大家參考博文中的項目實戰(zhàn)之后再去琢磨自己的項目代碼、或者看一些優(yōu)秀的開源代碼對比后,能更深刻的體會到設(shè)計模式(Design pattern)是一套被反復(fù)使用、多數(shù)人知曉的、經(jīng)過分類編目的、代碼設(shè)計經(jīng)驗的總結(jié)這句話的含義。
(小聲BB,某人的埋點博客終于快到尾聲了)
在開發(fā)的過程中,同一種功能采用不同的或者組合的設(shè)計模式實現(xiàn),可以將代碼質(zhì)量提升。這里要 copy 第一篇博文的話重申一下為什么前端需要了解設(shè)計模式
在日常開發(fā)中大部分前端都在開發(fā)的中,進行組件、方法等封裝、提煉的時候或多或少已經(jīng)使用了一些設(shè)計模式的理念, 但是由于對設(shè)計模式的概念模糊,理解不夠,從而導(dǎo)致設(shè)計整體架構(gòu)的時候,會有各種局限性,拓展性、可讀性、維護性變差,不得不多次重構(gòu)甚至重寫。在 ts 在前端開發(fā)中加速推進的同時,合理的設(shè)計模式使得項目從架構(gòu)、設(shè)計、迭代、維護都有一定質(zhì)量的保障。
接下來我們通過使用設(shè)計模式中的工廠、代理模式來繼續(xù)改造我們的 fetch 工程
封裝 fetch 業(yè)務(wù)部分
業(yè)務(wù)層普通封裝
業(yè)務(wù)層的封裝,我們在上一篇的文末已經(jīng)提到過,這邊再結(jié)合代碼展示一下
一般來說我們的工程會有多個模塊,這邊我們先根據(jù)各個模塊封裝一層 service 層,方便我們業(yè)務(wù)側(cè)調(diào)用。
import Fetch from './util/fetch';
const prefix = 'https://api.github.com/users'
const fetch = new Fetch({ requestType: "JSON", cacheType: 'local', BASE_URL: prefix });
const getUser = (params) => {
return new Promise((resolve, reject) => {
fetch.get({
url: '/octocat',
params
}).then(response => {
const { data, code, errMessage } = response
if (code) {
resolve(data)
} else {
reject(errMessage)
}
})
})
}
const setUser = (params) => {
return new Promise((resolve, reject) => {
fetch.post({
url: '/octocat',
params
}).then(response => {
const { data, code, errMessage } = response
if (code) {
resolve(data)
} else {
reject(errMessage)
}
})
})
}
export {
getUser,
setUser
};
export default {
getUser,
setUser
}
如上我們封裝了一個用戶 service 層,一般來說,除了正常的 http 的請求狀態(tài)異常之外,會有業(yè)務(wù)處理的異常。所以在 service 層調(diào)用的時候,可以預(yù)先處理掉錯誤的異常,返回給業(yè)務(wù)側(cè)正常的數(shù)據(jù),業(yè)務(wù)側(cè)在調(diào)用的時候,可以直接使用 try/catch 去承接數(shù)據(jù)。同時在多個業(yè)務(wù)側(cè)都需要調(diào)用相同的接口的時候,可以在用戶 service 層處理、過濾一些后臺返回的參數(shù),這樣可以使得業(yè)務(wù)側(cè)調(diào)用到方便前端展示的數(shù)據(jù)(比如組裝列表數(shù)據(jù),日期、金額格式化等)。
但是當業(yè)務(wù)過多,都要處理統(tǒng)一的業(yè)務(wù)錯誤的時候,會顯得非常麻煩,造成冗余代碼跟維護困難,所以在這之上,我們可以在針對 service 層再做一層業(yè)務(wù)報錯封裝。
import Fetch from '../util/fetch';
const prefix = 'https://api.github.com'
const fetch = new Fetch({ requestType: "JSON", cacheType: 'local', BASE_URL: prefix });
const get = (url, params) => {
return new Promise((resolve, reject) => {
fetch.get({
url,
params
}).then(response => {
const { data, code, errMessage } = response
if (code) {
resolve(data)
} else {
reject(errMessage)
}
})
})
}
export {
get
};
export default {
get
}
如上可以將業(yè)務(wù)層的統(tǒng)一處理跟單獨的業(yè)務(wù)接口數(shù)據(jù)處理分開,用戶的 service 層改造如下
import { get, post } from './baseFetch';
const prefix = 'users'
const getUser = async (params) => {
try {
const data = get({
url: `${prefix}/octocat`,
params
})
return data
}
}
const setUser = (params) => {
try {
const data = post({
url: `${prefix}/octocat`,
params
})
return data
}
}
export {
getUser,
setUser
};
export default {
getUser,
setUser
}
業(yè)務(wù)層 restful 格式封裝
有些后臺接口是按照 restful 風格封裝的接口,如果還是按照上面的封裝,會顯得比較累贅,我們可以如下封裝一下
import baseFetch from './baseFetch';
const prefix = 'users'
const methods = ['get', 'post', 'put', 'delete']
const userUrl = {
users: 'octocats',
user: 'octocat'
}
const user = {}
Object.keys(userUrl).forEach(key => {
user[key] = {}
methods.forEach(method => {
user[key][method] = (params) => {
return baseFetch[method](`${prefix}/${userUrl[key]}`, params)
}
})
})
export {
user
};
export default {
user
}
user.user.get({ test: 1 }) // 業(yè)務(wù)側(cè)調(diào)用
user.user.post({ test: 1 }) // 業(yè)務(wù)側(cè)調(diào)用
如上我們將 url 跟請求方法組裝起來,業(yè)務(wù)側(cè)調(diào)用會簡便很多,但是中間的業(yè)務(wù)層數(shù)據(jù)處理似乎就沒了,我們可以將 userUrl 拓展成 userObj,把數(shù)據(jù)處理方法也放入對象里面,改造如下
const userObj = {
users: {
url: 'octocats',
get(data) { return data }
},
user: {
url: 'octocats',
post(data) { return data }
}
}
const user = {}
Object.keys(userObj).forEach(key => {
user[key] = {}
methods.forEach(method => {
user[key][method] = (params) => {
return new Promise((resolve) => {
baseFetch[method](`${prefix}/${userObj[key].url}`, params).then(data => {
if (userObj[key][method]) resolve(userObj[key][method](data))
resolve(data)
})
})
}
})
})
尾聲
完整的 demo 地址:項目實戰(zhàn) demo,喜歡的朋友可以 star 一下,后續(xù)會根據(jù)設(shè)計模式博文的推出,逐步的將此項目繼續(xù)拓展出來。