微信小程序实践——用Promise 封装API
微信小程序实践——用Promise 封装API
第九程序 发表于3个月前
微信小程序实践——用Promise 封装API
  • 发表于 3个月前
  • 阅读 1132
  • 收藏 19
  • 点赞 1
  • 评论 4

腾讯云 十分钟定制你的第一个小程序>>>   

摘要: 如果新接触 Promise 的话,在网上能找到很多介绍 Promise 及其使用的文章(比如:ECMAScript 6 入门 / Promise 对象),这里就不赘述了,简而言之就是用来处理异步调用的一大利器。

为什么使用Promise

如果新接触 Promise 的话,在网上能找到很多介绍 Promise 及其使用的文章(比如:ECMAScript 6 入门 / Promise 对象),这里就不赘述了,简而言之就是用来处理异步调用的一大利器。

微信小程序的API都可以传入函数 success,fail 和 complete 来实现异步回调。

样例一

// 显示”载入中”,在一秒后消失
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的一大原因,可以链式调用。

上面的例子如果用Promise封装之后的API来写,看起来就非常直观(样例三)

样例三

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。

比如 () => 5 就会 return 5

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"))
共有 人打赏支持
粉丝 73
博文 142
码字总数 172691
评论 (4)
Geomen
请问个初级的问题哦!
我把你的源码放到 utils/wsAPI.js里
在index.js里引入 var wsAPI = require('../../utils/wsAPI.js')
然后,使用点击事件触发
jumpTo: function(event){
console.log(event);
console.log(event.target.dataset.page)
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"))

},
报wsAPI.taskSequence is not a function;at "pages/index/index" page jumpTo function
我要怎么封装,怎么调用呢?
第九程序

引用来自“Geomen”的评论

请问个初级的问题哦!
我把你的源码放到 utils/wsAPI.js里
在index.js里引入 var wsAPI = require('../../utils/wsAPI.js')
然后,使用点击事件触发
jumpTo: function(event){
console.log(event);
console.log(event.target.dataset.page)
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"))

},
报wsAPI.taskSequence is not a function;at "pages/index/index" page jumpTo function
我要怎么封装,怎么调用呢?
你好,文章最后有几个封装案例代码,可以试试
alphasu
JS->JQUERY>ANGULAR->VUE->REACT->PROMISE,问下楼主,JS学到精了么
第九程序

引用来自“alphasu”的评论

JS->JQUERY>ANGULAR->VUE->REACT->PROMISE,问下楼主,JS学到精了么
初学者
×
第九程序
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: