汀田鎮(zhèn)改進(jìn)異步封裝:處理帶返回值的異步調(diào)用 - 邊城客棧
閱讀 41828 · 發(fā)布日期 2020-08-24 17:26 · 溫州優(yōu)光網(wǎng)絡(luò)科技有限公司|建站|APP小程序制作|做網(wǎng)站SEO推廣優(yōu)化
【摘要】
最近幾篇文章都跟微信小程序開發(fā)有關(guān),所以有人就問:“小程序不懂啊,能不能寫點別的?”。其實不用太在意“小程序”這件事情,因為“小程序”在文章中只是一個開發(fā)場景,我們實際解決的問題并非只在小程序中才會遇到,而解決問題的手段完全與小程序無關(guān)!1. 問題在 Proxy 封裝微信小程序的異步調(diào)用 中留下了一個問題:像 wx.r... 【溫州小程序開發(fā),溫州微信公眾號,平陽做網(wǎng)站,平陽網(wǎng)站建設(shè)公司,平陽小程序商城制作,昆陽萬全做網(wǎng)站,鰲江水頭小程序,蕭江騰蛟微信公眾號,山門順溪南雁海西南麂鳳臥麻步懷溪網(wǎng)絡(luò)網(wǎng)店服務(wù),政采云網(wǎng)店管理服務(wù)】...
最近幾篇文章都跟微信小程序開發(fā)有關(guān),所以有人就問:
“小程序不懂啊,能不能寫點別的?”。
其實不用太在意“小程序”這件事情,因為“小程序”在文章中只是一個開發(fā)場景,我們實際解決的問題并非只在小程序中才會遇到,而解決問題的手段完全與小程序無關(guān)!1. 問題在 Proxy 封裝微信小程序的異步調(diào)用 中留下了一個問題:
像 wx.request() 這種原本就有返回值的情況,該如何封裝呢?如果需要在請求的過程中取消請求,就會用到 wx.request() 的返回值:
const requestTask = wx.request(...);
if (...) {
// 因為某些原因需要取消這次請求 requestTask.abort();
}
封裝過后的 awx.request() 會返回一個 Promise 對象,跟 wx.request() 原來的返回值毫無關(guān)系。
如果想要能夠取消請求,就必須將 wx.request() 原來的返回值帶出來,應(yīng)該怎么辦?function wxPromisify(fn) {
return async function (args) {
return new Promise((resolve, reject) => {
const originalResult = fn({
// ^^^^^^^^^^^^^^^^^^^^^^^ // 怎么把 originalResult 帶出去? ...(args || {
}
), success: res => resolve(res), fail: err => reject(err) }
);
}
);
}
;
}
2. 可選方案也不賣關(guān)子了,這里有幾個方案可選:
返回對象或數(shù)組,解構(gòu)后使用。
比如返回 {
promise, originalResult}
或 [promise, originalResult];通過一個“容器”參數(shù)將返回值帶出來,比如 awx.request(params, outBox = {
}
),在處理時為 outBox 賦值:
outBox.originalResult;JS 是動態(tài)類型,可以直接修改 Promise 對象,為其附加屬性:
promise.originalResult = ...。
從使用者的角度來考慮,多數(shù)時候是不需要原返回值的,這時候是肯定是希望 await awx.request(),而不是先解構(gòu)再 await(或 then()),所以,第 1 種方法不可選。
第 2 種方法可行,不需要原返回值的時候,直接使用即可。
但是需要原返回值的時候,稍嫌麻煩,需要先產(chǎn)生一個容器對象傳入。
第 3 種方法使用起來應(yīng)該是最“無感”的。
無論如何,原值隨 Promise 對象帶出來了,用或是不用,請便!現(xiàn)在我們來實現(xiàn)第 3 種方法,改造 wxPromisify():
3. 失敗的嘗試一開始想得很簡單,原來直接 return new Promise(),現(xiàn)在加個臨時變量應(yīng)該就可以吧:
function wxPromisify(fn) {
return async function (args) {
const promise = new Promise((resolve, reject) => {
// ^^^^^^^^^^^^^^^^ promise.originalResult = fn({
// ^^^^^^^^^^^^^^^^^^^^^^^^^ ...(args || {
}
), success: res => resolve(res), fail: err => reject(err) }
);
}
);
return promise;
// ^^^^^^^^^^^^^^^ }
;
}
然后得到一個錯誤:
TypeError: Cannot set property '
originalResult'
of undefined這個錯很好理解,也很容易改……不過確實也很容易犯!本來是認(rèn)為 promise 是個局部變量,可以直接訪問,所以在其子作用域中使用是沒問題。
但是這里忽略了這個子作用域是在構(gòu)造函數(shù)中。
來大概分析一下:
new Promise() 需要一個函數(shù)(假設(shè)叫 factory)作為參數(shù),但是這個 factory 執(zhí)行的時機是什么?注意到 new Promise() 產(chǎn)生 Promise 實例之后,我們再沒有主動調(diào)用這個實例的任何方法,所以可以斷定,factory 是在構(gòu)造的過程中執(zhí)行的。
換句話說,這時候 Promise 實例還沒產(chǎn)生呢,promise 引用的是 undefined。
4. 成功的嘗試既然已經(jīng)知道問題所在,我們接著分析。
構(gòu)造 Promise 實例的過程中調(diào)用了 factory,而 factory 的在函數(shù)體中直接執(zhí)行了 fn,可以立即拿到 fn 的返回值,所以這個 Promise 實例構(gòu)造完成之后,是可以拿到原返回值的。
現(xiàn)在來修改一下代碼:
function wxPromisify(fn) {
return async function (args) {
let originalResult;
// ^^^^^^^^^^^^^^^^^^^ const promise = new Promise((resolve, reject) => {
originalResult = fn({
// ^^^^^^^^^^^^^^ ...(args || {
}
), success: res => resolve(res), fail: err => reject(err) }
);
}
);
promise.originalResult = originalResult;
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ return promise;
}
;
}
我們需要在 new Promise() 之后對 promise.originalResult 賦值,而這個“值”產(chǎn)生于 new Promise() 的過程中,那么再加個局部變量 originalResult 把它帶出來就好。
搞定!5. 搞笑卻又應(yīng)該嚴(yán)肅對待的事情本來應(yīng)該結(jié)束了,但我猜一定會有人這么干(因為我在其他場景下見過):
注意:
下面這個是錯誤示例!function wxPromisify(fn) {
return async function (args) {
let promise = new Promise();
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ promise = new Promise((resolve, reject) => {
// ^^^^^^^^^^ promise.originalResult = fn({
... }
);
// ^^^^^^^^^^^^^^^^^^^^^^ }
);
return promise;
}
;
}
這樣做不會產(chǎn)生前面提到的 TypeError,但是外面拿到的 Promise 對象卻并不攜帶 originalResult。
具體原因跟上面失敗的那次嘗試一樣,所以不再詳述,只提醒一下:
這里產(chǎn)生了兩個 Promise 對象。
6. 再啰嗦一下這次帶出原返回值是以 wx.request() 為例,其返回值的主要用途是提供 .abort() 方法用于取消請求。
這個應(yīng)用場景其實和 Axios 處理“取消請求 (Cancellation)”類似,所以不妨參考 Axios 通過 cancelToken 實現(xiàn)的方法。
cancelToken 的實質(zhì)就是前面提到的第 2 種方法 —— 傳入“容器”對象把需要的東西帶出來。
通過 Promise 對象帶出來和通過一個專門的“容器”對象帶出來,本質(zhì)是一樣的,所以就不多說了。
推薦教程:
《微信小程序》以上就是改進(jìn)異步封裝:
處理帶返回值的異步調(diào)用 - 邊城客棧的詳細(xì)內(nèi)容,更多請關(guān)注php中文網(wǎng)其它相關(guān)文章!
微信
分享相關(guān)標(biāo)簽:
小程序 異步 封裝 promise本文轉(zhuǎn)載于:
segmentfault,如有侵犯,請聯(lián)系[email protected]刪除
上一篇:
微信小程序怎么使用車牌號輸入法
下一篇:
記一次微信小程序在安卓手機上的白屏問題相關(guān)文章相關(guān)視頻微信小程序開發(fā)初次體驗微信小程序常見的開發(fā)問題匯總小程序中wepy-redux的使用以及存儲全局變量微信小程序自動跳出來怎么解決?改進(jìn)異步封裝:
處理帶返回值的異步調(diào)用 - 邊城客棧認(rèn)識小程序的目錄結(jié)構(gòu)小程序的rpx長度單位詳解布局奔牛課堂小程序搜素框 [溫州做小程序]