需求背景
微信小程式的大部分api是非同步的。
簡單地舉個?: wx.showToast(Object object)
wx.showToast({
title: '成功',
icon: 'success',
duration: 2000,
success: function(res) { // TODO },
fail: function(err) { // TODO }
});
複製程式碼
事實上這樣的api 寫的真夠好,但是對於使用者來說並不友好。所以,為了方便同事們更加舒爽地去寫程式碼,於是我開始琢磨封裝一個小程式api的promisefy的函式。
那麼到底怎麼封裝呢?
// defaultProps為預設屬性,extraProps為定製化的屬性
/**
* promisefy 微信內建函式
* @param fn
* @return { promise }
*/
const promisefy = fn => defaultProps => extraProps => new Promise((resolve, reject) => fn({
...defaultProps,
...extraProps,
success: res => resolve(res),
reject: err => reject(err),
}));
複製程式碼
那麼到底怎麼使用呢?
const showToast = promisefy(wx.showToast)({
title: '',
icon: "none",
duration: 2000,
confirmColor: '#ff673f',
mask: true
});
showToast({ title: 'title' }); // 即可使用
複製程式碼
那麼這個promisefy還能怎麼用呢? 1.我們可能會經常使用storage相關的api, 那麼到底是把物件JSON.stringify, 再setStorage。需要使用的時候再getStorage, 最後JSON.parse呢?當然這是一種解決方案。如果使用promisefy,可以這樣幹。
/**
*
* @param 需要往LocalStorage裡面存資料
* @returns {Promise<any[] | never>}
*/
const setStorage = (param = {}) => {
if (!Object.keys(param).length) throw new Error('輸入的物件不為空');
return Promise.all(Object.entries(param)
.map(item => promisefy(wx.setStorage)({
key: item[0],
data: item[1]
})()));
};
setStorage({ a:1, b:2 });
複製程式碼
/**
*
* @param 需要從storage 讀取的key。
* 單個值直接傳string, 多個值傳陣列
* eg. ['key1', 'key2', 'key3'] 或者 'key1' ;
* @returns {key1: value1, key2: value2, key3: key3 }
*/
const getStorage = param => Promise.all(
Object.entries(((typeof param) === 'string') ? [param] : param)
.map(item => promisefy(wx.getStorage)({ key: item[1] })()
.then(res => ({ [`${item[1]}`]: res.data }))))
.then(res => res.reduce((prev, curr) => ({ ...prev, ...curr }), {}));
getStorage('a'); // { a: 1 },
getStorage(['a', 'b']); // { a: 1, b: 2 },
複製程式碼
/**
* @param 需要從storage 清除記錄eg. [key1, key2], key3。
*/
const removeStorage = param => Promise.all(
Object.entries(((typeof param) === 'string') ? [param] : param)
.map(item => promisefy(wx.removeStorage)({ key: item[1] })()));
removeStorage('a');
removeStorage(['a', 'b']);
複製程式碼
2.對於有router 的頁面我們經常會出現router 的三種跳轉方案。例如微信就提供了三種api:navigateTo,redirectTo,navigateBack,這裡沒有包含小程式跳小程式的api。那麼我們是不是可以封裝一個公共的方法呢?
// 路徑引數的拼接
const obj2Url = params => {
if (params instanceof Array || typeof params === 'number') throw new Error('跳轉引數限制於string和物件');
// 如果路徑引數為 object, 做以下轉換
if (typeof params === 'object') {
const rawParams = Object.entries(params).reduce((acc, cur) => {
if ((!cur[1]) && ((typeof cur[1]) !== 'boolean')) console.warn(`${cur[0]}的值為空, 請檢查原因!`);
return `${acc + cur[0]}=${cur[1]}&`;
}, '');
params = rawParams.substr(0, rawParams.length - 1);
}
return params;
};
/**
*
* @param page 需要跳轉的頁面或者頁面路徑(如果是"pages/a/b/b"這樣的路徑,page='pages/a/b/b', specialUrl=true )
* @param type
* @param params
* @param specialUrl
* @return {*}
*/
const jumpTo = (page = 'index', type = 'navigate', params = '', specialUrl = false) => {
const { navigateTo, redirectTo, navigateBack } = wx;
const types = {
navigate: url => promisefy(navigateTo)({ url })(),
redirect: url => promisefy(redirectTo)({ url })(),
back: delta => promisefy(navigateBack)({ delta })(),
};
params = obj2Url(params);
console.log('**test**', 'params', params, `${page}?${params}`);
if (specialUrl) return types[type](params ? `${page}?${params}` : page);
// 獲取跳轉引數,如果為數字,則為navigateBack,反之為 navigateTo 或 navigateBack。
const jumpPram = (typeof page === 'number') ? page : `/pages/${page}/${page}${params ? `?${params}` : ''}`;
console.log(`%c**跳轉引數**jumpPram** ${jumpPram}`, 'color:white;background:green');
sendTrack(`**跳轉引數**jumpParam** ${jumpPram}`);
return types[type](jumpPram);
};
jumpTo('a'); // navigateTo到a頁面
jumpTo('a', 'navigate', { m: 'm' }); // navigateTo到a頁面 ,路徑引數為?m=m
jumpTo('a', 'redirect', { m: 'm' }); // redirectTo到a頁面 ,路徑引數為?m=m
jumpTo(1, 'redirect', { m: 'm' }); // back 上一步 ,路徑引數為?m=m
複製程式碼
專案實踐
1.native 小程式開發者。(下載babel-polyfill,匯入regeneratorRuntime)
import regeneratorRuntime from '你放置的資料夾';
const showLoading = promisefy(wx.showLoading)({ title: '載入中', mask: true });
const hideLoading = () => wx.hideLoading();
const showToast = promisefy(wx.showToast)({ title: 'title', content: '', mask: true });
const Loading = { show: showLoading, hide: hideLoading };
const Toast = { show: showToast };
const handleErr = (e, cb) => {
Loading.hide();
if ((typeof e) === 'string') {
Toast.show({ title: e || '伺服器異常,請稍後再試' });
} else {
const { message } = e;
Toast.show({ title: message || '伺服器異常,請稍後再試' });
}
cb && cb();
};
const fetchData = () => {}
aync function() {
try {
await Loading.show();
const { data } = await fetchData();
this.setData({
data
})
Loading.hide();
} catch (e) {
handleErr(e)
}
}
複製程式碼
2.webpack和taro 使用者直接引入用配置bable 相關npm即可, 可參考
總結分析
函式的科裡化幹了什麼?
參考 科裡化
怎麼避免過多使用switch...case,if...else等?
參考 策略模式
扁平化陣列操作。
參考 編寫扁平化的程式碼
異常的處理。