微信小程序實踐——用Promise 封裝API

爲何使用Promise

若是新接觸 Promise 的話,在網上能找到不少介紹 Promise 及其使用的文章(好比:ECMAScript 6 入門 / Promise 對象),這裏就不贅述了,簡而言之就是用來處理異步調用的一大利器。小程序

微信小程序的API均可以傳入函數 success,fail 和 complete 來實現異步回調。微信小程序

樣例一promise

// 顯示」載入中」,在一秒後消失
wx.showLoading({
    title: "載入中",
    success: function () {
        setTimeout(function () {
            wx.hideLoading()
        }, 1000)
    },
    fail: function(){},
    complete: function(){}
});

原生的 success,fail 和 complete 已可以知足基本的異步回調了,可是若是遇到多個連續的阻塞任務,會形成多層嵌套(如樣例二所示),就很奔潰。微信

樣例二異步

// 顯示「保存中」,一秒後隱藏,半秒後顯示「載入中」,一秒後隱藏
wx.showLoading({
    title: "保存中",
    success: function () {
        setTimeout(function () {
            wx.hideLoading({
                success: function () {
                    setTimeout(function () {
                        wx.showLoading({
                            title: "載入中",
                            success: function () {
                                setTimeout(function () {
                                    wx.hideLoading()
                                },1000)
                            }
                        })
                    }, 500)
                }
            })
        }, 1000)
    }
})

上面的例子有七個阻塞任務:顯示「保存中」,停頓一秒,隱藏,停頓半秒,顯示「載入中」,停頓一秒,隱藏。從直覺上來思考,這些任務應該是以隊列的形式存在,一個完成了再開始下一個,而非層層嵌套,這也是使用Promise的一大緣由,能夠鏈式調用。ide

上面的例子若是用Promise封裝以後的API來寫,看起來就很是直觀(樣例三)函數

樣例三this

wsAPI.taskSequence()
    .then(() => wsAPI.showLoading({title: "保存中"}))
    .then(() => wsAPI.sleep(1000))
    .then(() => wsAPI.hideLoading())
    .then(() => wsAPI.sleep(500))
    .then(() => wsAPI.showLoading({title: "載入中"}))
    .then(() => wsAPI.sleep(1000))
    .then(() => wsAPI.hideLoading())
    .then(() => console.log("done"))

注: (A)=>{B} 是 ES6 的箭頭函數,至關於 function(A){B},箭頭函數不用顯式 return。spa

好比 () => 5 就會 return 5code

console.log((() => 5)()) // 5

封裝實現

wsAPI的源代碼實現以下:

let nullFn = () => {
};
function IllegalAPIException(name) {
    this.message = "No Such API [" + name + "]";
    this.name = 'IllegalAPIException';
}
let services = {
    sleep: (time) => {
        return new Promise(function (resolve, reject) {
            setTimeout(resolve, time);
        })
    },
    stop: () => {
        return new Promise(function (resolve, reject) {
        })
    },
    taskSequence: () => {
        return new Promise(function (resolve, reject) {
            resolve()
        })
    }
};
export let wsAPI = new Proxy(services, {
    get: function (target, property) {
        if (property in target) {
            return target[property];
        } else if (property in wx) {
            return (obj) => {
                return new Promise(function (resolve, reject) {
                    obj = obj || {};
                    obj.success = (...args) => {
                        resolve(...args)
                    };
                    obj.fail = (...args) => {
                        reject(...args);
                    };
                    obj.complete = nullFn;
                    wx[property](obj);
                });
            }
        } else {
            throw new IllegalAPIException(property);
        }

    }
});

wsAPI 用 Proxy(ECMAScript 6 入門 / Proxy)從新封裝了 wx 的全部API。並新增了 sleep ,stop 和 taskSequence。sleep 用於阻塞一段時間;taskSequence 是一個空的 Promise,讓代碼看起來更整齊美觀,可讀性更好(樣例四);stop 用於中止任務序列進行下去(樣例五)

樣例四

// taskSequence
wsAPI.taskSequence()
    .then(() => wsAPI.showLoading({title: "保存中"}))
    .then(() => wsAPI.sleep(1000))
    .then(() => wsAPI.hideLoading())
    .then(() => wsAPI.sleep(500))
    .then(() => wsAPI.showLoading({title: "載入中"}))
    .then(() => wsAPI.sleep(1000))
    .then(() => wsAPI.hideLoading())
    .then(() => console.log("done"))

// 沒有 taskSequence,第一個promise就和下面的不對齊
wsAPI.showLoading({title: "保存中"})
    .then(() => wsAPI.sleep(1000))
    .then(() => wsAPI.hideLoading())
    .then(() => wsAPI.sleep(500))
    .then(() => wsAPI.showLoading({title: "載入中"}))
    .then(() => wsAPI.sleep(1000))
    .then(() => wsAPI.hideLoading())
    .then(() => console.log("done"))

樣例五

wsAPI.taskSequence()
    .then(() => wsAPI.showModal({title: "保存", content: "肯定保存?"}))
    .then(res => {
        if (!res.confirm) {
            return wsAPI.stop();
        }
    })
    .then(() => console.log("to save"))
    .then(() => wsAPI.showLoading({title: "保存中"}))
    .then(() => wsAPI.sleep(1000))
    .then(() => wsAPI.hideLoading())
    .then(() => console.log("done"))
相關文章
相關標籤/搜索