91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

小程序中改進異步封裝的問題有哪些

發布時間:2021-04-01 09:48:10 來源:億速云 閱讀:142 作者:小新 欄目:移動開發

小編給大家分享一下小程序中改進異步封裝的問題有哪些,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!


1. 問題

在 Proxy 封裝微信小程序的異步調用 中留下了一個問題:

wx.request()  這種原本就有返回值的情況,該如何封裝呢?

如果需要在請求的過程中取消請求,就會用到 wx.request() 的返回值:

const requestTask = wx.request(...);
if (...) {
    // 因為某些原因需要取消這次請求
    requestTask.abort();
}

封裝過后的 awx.request() 會返回一個 Promise 對象,跟 wx.request() 原來的返回值毫無關系。如果想要能夠取消請求,就必須將 wx.request() 原來的返回值帶出來,應該怎么辦?

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. 可選方案

也不賣關子了,這里有幾個方案可選:

  1. 返回對象或數組,解構后使用。比如返回 { promise, originalResult}[promise, originalResult]

  2. 通過一個“容器”參數將返回值帶出來,比如 awx.request(params, outBox = {}),在處理時為 outBox 賦值:outBox.originalResult

  3. JS 是動態類型,可以直接修改 Promise 對象,為其附加屬性:promise.originalResult = ...

從使用者的角度來考慮,多數時候是不需要原返回值的,這時候是肯定是希望 await awx.request(),而不是先解構再 await(或 then()),所以,第 1 種方法不可選。

第 2 種方法可行,不需要原返回值的時候,直接使用即可。但是需要原返回值的時候,稍嫌麻煩,需要先產生一個容器對象傳入。

第 3 種方法使用起來應該是最“無感”的。無論如何,原值隨 Promise 對象帶出來了,用或是不用,請便!

現在我們來實現第 3 種方法,改造 wxPromisify()

3. 失敗的嘗試

一開始想得很簡單,原來直接 return new Promise(),現在加個臨時變量應該就可以吧:

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

這個錯很好理解,也很容易改……不過確實也很容易犯!

本來是認為 promise 是個局部變量,可以直接訪問,所以在其子作用域中使用是沒問題。但是這里忽略了這個子作用域是在構造函數中。來大概分析一下:

new Promise() 需要一個函數(假設叫 factory)作為參數,但是這個 factory 執行的時機是什么?注意到 new Promise() 產生 Promise 實例之后,我們再沒有主動調用這個實例的任何方法,所以可以斷定,factory 是在構造的過程中執行的。換句話說,這時候 Promise 實例還沒產生呢,promise 引用的是 undefined

4. 成功的嘗試

既然已經知道問題所在,我們接著分析。

構造 Promise 實例的過程中調用了 factory,而 factory 的在函數體中直接執行了 fn,可以立即拿到 fn 的返回值,所以這個 Promise 實例構造完成之后,是可以拿到原返回值的。

現在來修改一下代碼:

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 賦值,而這個“值”產生于 new Promise() 的過程中,那么再加個局部變量 originalResult 把它帶出來就好。

搞定!

5. 搞笑卻又應該嚴肅對待的事情

本來應該結束了,但我猜一定會有人這么干(因為我在其他場景下見過):

注意:下面這個是錯誤示例!
function wxPromisify(fn) {
    return async function (args) {
        let promise = new Promise();
//      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        promise = new Promise((resolve, reject) => {
//      ^^^^^^^^^^
            promise.originalResult = fn({ ... });
//          ^^^^^^^^^^^^^^^^^^^^^^
        });

        return promise;
    };
}

這樣做不會產生前面提到的 TypeError,但是外面拿到的 Promise 對象卻并不攜帶 originalResult。具體原因跟上面失敗的那次嘗試一樣,所以不再詳述,只提醒一下:這里產生了兩個 Promise 對象

6. 再啰嗦一下

這次帶出原返回值是以 wx.request() 為例,其返回值的主要用途是提供 .abort() 方法用于取消請求。這個應用場景其實和 Axios 處理“取消請求 (Cancellation)”類似,所以不妨參考 Axios 通過 cancelToken 實現的方法。cancelToken 的實質就是前面提到的第 2 種方法 —— 傳入“容器”對象把需要的東西帶出來。通過 Promise 對象帶出來和通過一個專門的“容器”對象帶出來,本質是一樣的,所以就不多說了。

以上是“小程序中改進異步封裝的問題有哪些”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

新民市| 会东县| 宜都市| 深水埗区| 通州区| 肥城市| 交城县| 大城县| 普格县| 乐安县| 辽阳县| 新蔡县| 福贡县| 雷山县| 高雄市| 富阳市| 汉寿县| 安顺市| 旅游| 体育| 中西区| 英吉沙县| 霸州市| 乐东| 陆良县| 团风县| 南陵县| 蒙阴县| 本溪市| 宜宾县| 鹰潭市| 四子王旗| 金秀| 会理县| 清徐县| 西林县| 池州市| 金川县| 哈尔滨市| 贡觉县| 建平县|