為什么使用Promise如果新接觸 Promise 的話,在網(wǎng)上能找到很多介紹 Promise 及其使用的文章(比如:ECMAScript 6 入門 / Promise 對(duì)象),這里就不贅述了,簡(jiǎn)而言之就是用來處理異步調(diào)用的一大利器。微信小程序的API ...
為什么使用Promise
如果新接觸 Promise 的話,在網(wǎng)上能找到很多介紹 Promise 及其使用的文章(比如:ECMAScript 6 入門 / Promise 對(duì)象),這里就不贅述了,簡(jiǎn)而言之就是用來處理異步調(diào)用的一大利器。
微信小程序的API都可以傳入函數(shù) success,fail 和 complete 來實(shí)現(xiàn)異步回調(diào)。
樣例一
// 顯示”載入中”,在一秒后消失
wx.showLoading({
title: "載入中",
success: function () {
setTimeout(function () {
wx.hideLoading()
}, 1000)
},
fail: function(){},
complete: function(){}
});
原生的 success,fail 和 complete 已能夠滿足基本的異步回調(diào)了,但是如果遇到多個(gè)連續(xù)的阻塞任務(wù),會(huì)造成多層嵌套(如樣例二所示),就很奔潰。
樣例二
// 顯示“保存中”,一秒后隱藏,半秒后顯示“載入中”,一秒后隱藏
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)
}
})
上面的例子有七個(gè)阻塞任務(wù):顯示“保存中”,停頓一秒,隱藏,停頓半秒,顯示“載入中”,停頓一秒,隱藏。從直覺上來思考,這些任務(wù)應(yīng)該是以隊(duì)列的形式存在,一個(gè)完成了再開始下一個(gè),而非層層嵌套,這也是使用Promise的一大原因,可以鏈?zhǔn)秸{(diào)用。
上面的例子如果用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 的箭頭函數(shù),相當(dāng)于 function(A){B},箭頭函數(shù)不用顯式 return。
比如 () => 5 就會(huì) return 5
console.log((() => 5)()) // 5
封裝實(shí)現(xiàn)
wsAPI的源代碼實(shí)現(xiàn)如下:
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 用于阻塞一段時(shí)間;taskSequence 是一個(gè)空的 Promise,讓代碼看起來更整齊美觀,可讀性更好(樣例四);stop 用于停止任務(wù)序列進(jìn)行下去(樣例五)
樣例四
// 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,第一個(gè)promise就和下面的不對(duì)齊
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"))
工作日 8:30-12:00 14:30-18:00
周六及部分節(jié)假日提供值班服務(wù)