沙頭鎮(zhèn)改進(jìn)異步封裝:處理帶返回值的異步調(diào)用 - 邊城客棧

閱讀 41878  ·  發(fā)布日期 2020-08-24 17:26  ·  溫州優(yōu)光網(wǎng)絡(luò)科技有限公司|建站|APP小程序制作|做網(wǎng)站SEO推廣優(yōu)化
【摘要】 最近幾篇文章都跟微信小程序開(kāi)發(fā)有關(guān),所以有人就問(wèn):“小程序不懂啊,能不能寫(xiě)點(diǎn)別的?”。其實(shí)不用太在意“小程序”這件事情,因?yàn)椤靶〕绦颉痹谖恼轮兄皇且粋€(gè)開(kāi)發(fā)場(chǎng)景,我們實(shí)際解決的問(wèn)題并非只在小程序中才會(huì)遇到,而解決問(wèn)題的手段完全與小程序無(wú)關(guān)!1. 問(wèn)題在 Proxy 封裝微信小程序的異步調(diào)用 中留下了一個(gè)問(wèn)題:像 wx.r... 【溫州小程序開(kāi)發(fā),溫州微信公眾號(hào),平陽(yáng)做網(wǎng)站,平陽(yáng)網(wǎng)站建設(shè)公司,平陽(yáng)小程序商城制作,昆陽(yáng)萬(wàn)全做網(wǎng)站,鰲江水頭小程序,蕭江騰蛟微信公眾號(hào),山門(mén)順溪南雁海西南麂鳳臥麻步懷溪網(wǎng)絡(luò)網(wǎng)店服務(wù),政采云網(wǎng)店管理服務(wù)】...

改進(jìn)異步封裝:處理帶返回值的異步調(diào)用 - 邊城客棧

最近幾篇文章都跟微信小程序開(kāi)發(fā)有關(guān),所以有人就問(wèn):
“小程序不懂啊,能不能寫(xiě)點(diǎn)別的?”。
其實(shí)不用太在意“小程序”這件事情,因?yàn)椤靶〕绦颉痹谖恼轮兄皇且粋€(gè)開(kāi)發(fā)場(chǎng)景,我們實(shí)際解決的問(wèn)題并非只在小程序中才會(huì)遇到,而解決問(wèn)題的手段完全與小程序無(wú)關(guān)!1. 問(wèn)題在 Proxy 封裝微信小程序的異步調(diào)用 中留下了一個(gè)問(wèn)題:
像 wx.request() 這種原本就有返回值的情況,該如何封裝呢?如果需要在請(qǐng)求的過(guò)程中取消請(qǐng)求,就會(huì)用到 wx.request() 的返回值:
const requestTask = wx.request(...);
if (...) {
// 因?yàn)槟承┰蛐枰∠@次請(qǐng)求 requestTask.abort();
}
封裝過(guò)后的 awx.request() 會(huì)返回一個(gè) Promise 對(duì)象,跟 wx.request() 原來(lái)的返回值毫無(wú)關(guān)系。
如果想要能夠取消請(qǐng)求,就必須將 wx.request() 原來(lái)的返回值帶出來(lái),應(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. 可選方案也不賣(mài)關(guān)子了,這里有幾個(gè)方案可選:
返回對(duì)象或數(shù)組,解構(gòu)后使用。
比如返回 {
promise, originalResult}
或 [promise, originalResult];通過(guò)一個(gè)“容器”參數(shù)將返回值帶出來(lái),比如 awx.request(params, outBox = {
}
),在處理時(shí)為 outBox 賦值:
outBox.originalResult;JS 是動(dòng)態(tài)類(lèi)型,可以直接修改 Promise 對(duì)象,為其附加屬性:
promise.originalResult = ...。
從使用者的角度來(lái)考慮,多數(shù)時(shí)候是不需要原返回值的,這時(shí)候是肯定是希望 await awx.request(),而不是先解構(gòu)再 await(或 then()),所以,第 1 種方法不可選。
第 2 種方法可行,不需要原返回值的時(shí)候,直接使用即可。
但是需要原返回值的時(shí)候,稍嫌麻煩,需要先產(chǎn)生一個(gè)容器對(duì)象傳入。
第 3 種方法使用起來(lái)應(yīng)該是最“無(wú)感”的。
無(wú)論如何,原值隨 Promise 對(duì)象帶出來(lái)了,用或是不用,請(qǐng)便!現(xiàn)在我們來(lái)實(shí)現(xiàn)第 3 種方法,改造 wxPromisify():
3. 失敗的嘗試一開(kāi)始想得很簡(jiǎn)單,原來(lái)直接 return new Promise(),現(xiàn)在加個(gè)臨時(shí)變量應(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;
// ^^^^^^^^^^^^^^^ }
;
}
然后得到一個(gè)錯(cuò)誤:
TypeError: Cannot set property '
originalResult'
of undefined這個(gè)錯(cuò)很好理解,也很容易改……不過(guò)確實(shí)也很容易犯!本來(lái)是認(rèn)為 promise 是個(gè)局部變量,可以直接訪問(wèn),所以在其子作用域中使用是沒(méi)問(wèn)題。
但是這里忽略了這個(gè)子作用域是在構(gòu)造函數(shù)中。
來(lái)大概分析一下:
new Promise() 需要一個(gè)函數(shù)(假設(shè)叫 factory)作為參數(shù),但是這個(gè) factory 執(zhí)行的時(shí)機(jī)是什么?注意到 new Promise() 產(chǎn)生 Promise 實(shí)例之后,我們?cè)贈(zèng)]有主動(dòng)調(diào)用這個(gè)實(shí)例的任何方法,所以可以斷定,factory 是在構(gòu)造的過(guò)程中執(zhí)行的。
換句話說(shuō),這時(shí)候 Promise 實(shí)例還沒(méi)產(chǎn)生呢,promise 引用的是 undefined。
4. 成功的嘗試既然已經(jīng)知道問(wèn)題所在,我們接著分析。
構(gòu)造 Promise 實(shí)例的過(guò)程中調(diào)用了 factory,而 factory 的在函數(shù)體中直接執(zhí)行了 fn,可以立即拿到 fn 的返回值,所以這個(gè) Promise 實(shí)例構(gòu)造完成之后,是可以拿到原返回值的。
現(xiàn)在來(lái)修改一下代碼:
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() 之后對(duì) promise.originalResult 賦值,而這個(gè)“值”產(chǎn)生于 new Promise() 的過(guò)程中,那么再加個(gè)局部變量 originalResult 把它帶出來(lái)就好。
搞定!5. 搞笑卻又應(yīng)該嚴(yán)肅對(duì)待的事情本來(lái)應(yīng)該結(jié)束了,但我猜一定會(huì)有人這么干(因?yàn)槲以谄渌麍?chǎng)景下見(jiàn)過(guò)):
注意:
下面這個(gè)是錯(cuò)誤示例!function wxPromisify(fn) {
return async function (args) {
let promise = new Promise();
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ promise = new Promise((resolve, reject) => {
// ^^^^^^^^^^ promise.originalResult = fn({
... }
);
// ^^^^^^^^^^^^^^^^^^^^^^ }
);
return promise;
}
;
}
這樣做不會(huì)產(chǎn)生前面提到的 TypeError,但是外面拿到的 Promise 對(duì)象卻并不攜帶 originalResult。
具體原因跟上面失敗的那次嘗試一樣,所以不再詳述,只提醒一下:
這里產(chǎn)生了兩個(gè) Promise 對(duì)象。
6. 再啰嗦一下這次帶出原返回值是以 wx.request() 為例,其返回值的主要用途是提供 .abort() 方法用于取消請(qǐng)求。
這個(gè)應(yīng)用場(chǎng)景其實(shí)和 Axios 處理“取消請(qǐng)求 (Cancellation)”類(lèi)似,所以不妨參考 Axios 通過(guò) cancelToken 實(shí)現(xiàn)的方法。
cancelToken 的實(shí)質(zhì)就是前面提到的第 2 種方法 —— 傳入“容器”對(duì)象把需要的東西帶出來(lái)。
通過(guò) Promise 對(duì)象帶出來(lái)和通過(guò)一個(gè)專(zhuān)門(mén)的“容器”對(duì)象帶出來(lái),本質(zhì)是一樣的,所以就不多說(shuō)了。
推薦教程:
《微信小程序》以上就是改進(jìn)異步封裝:
處理帶返回值的異步調(diào)用 - 邊城客棧的詳細(xì)內(nèi)容,更多請(qǐng)關(guān)注php中文網(wǎng)其它相關(guān)文章!
微信
分享相關(guān)標(biāo)簽:
小程序 異步 封裝 promise本文轉(zhuǎn)載于:
segmentfault,如有侵犯,請(qǐng)聯(lián)系[email protected]刪除
上一篇:
微信小程序怎么使用車(chē)牌號(hào)輸入法
下一篇:
記一次微信小程序在安卓手機(jī)上的白屏問(wèn)題相關(guān)文章相關(guān)視頻微信小程序開(kāi)發(fā)初次體驗(yàn)微信小程序常見(jiàn)的開(kāi)發(fā)問(wèn)題匯總小程序中wepy-redux的使用以及存儲(chǔ)全局變量微信小程序自動(dòng)跳出來(lái)怎么解決?改進(jìn)異步封裝:
處理帶返回值的異步調(diào)用 - 邊城客棧認(rèn)識(shí)小程序的目錄結(jié)構(gòu)小程序的rpx長(zhǎng)度單位詳解布局奔牛課堂小程序搜素框 [溫州做小程序]