vue中promise的使用
promise是處理異步的利器,在之前的文章《ES6之promise》中,我詳細介紹了promise的使用, 在文章《js動畫實現&&回調地獄&&promise》中也提到了promise的then的鏈式調用, 這篇文章主要是介紹在實際項目中關於異步我遇到的一些問題以及解決方法,由此來加深對promise的進一步理解。
背景
進入商品頁,商品頁的左側是分類,右側是具體的商品,一旦進入商品頁,就把所有分類的商品請求出來,注意: 必須要按照順序。
實現思路
在商品頁, created 鈎子函數觸發獲取分類的http請求,請求到結果后,開始請求所有的具體商品並渲染。
遇到的問題
- 由於請求商品分類是異步的, 怎么判斷異步請求完成, 也就是說請求具體商品的時機是什么時候。
- 獲取到所有的商品必須發送請求,請求時異步的,怎么保證能夠按照順序獲取到。
解決問題 --- 問題一
針對問題一,最好的方式還是使用promise,大致實現如下:
getClassify: function () { var that = this; // 使用promise處理異步。 this.updateKinds().then(function () { console.log("獲取分類結束!"); that.updateAllContent(); }); },
其中getClassify是在created時就會調用的,而updateKinds是actions中的方法,我們先看看actions中是怎么寫的:
updateKinds ({commit, state}) { return new Promise(function (resolve, reject) { axios.get('/bbg/shop/get_classify', { params: { sid: 13729792 } }) .then(function (response) { if (response.data.code == 130) { commit(UPDATE_KINDS, response.data.data) console.log(response.data.data); resolve() } }).catch(function (error) { console.log(error); }); });
即返回一個promise,當請求到數據,並且commit之后,我們就額可以resolve()了,這樣,就可以在then中執行獲取所有內容的方法了。
雖然實現起來比較簡單,但是這個思想更好。
解決問題 --- 問題二
在問題一中,我們看到resolve之后就可以調用updateAllContent() 了,那么這個應該怎么寫呢?
首先可以確定的是: 因為需要請求的分類不只一個,所以要使用promise, 並且一定要返回一個promise,這樣才能繼續鏈式調用,其中一部分如下:
ar items = state.items; function getItemPromise(id) { return new Promise(function (resolve, reject) { var content = { "isSingle": 1, "sbid": 13729792, "catalog3": id, "offset": 0, "pageSize": 10 }; axios.post('/bbg/goods/get_goods_list_wechat', qs.stringify({"data": JSON.stringify(content)})) .then(function (response) { if (response.data.code == 626) { for (let i = 0; i < response.data.data.length; i++) { commit(UPDATE_ALL_CONTENT, response.data.data[i]); } resolve(); } }).catch(function (error) { console.log(error); }); }); }
即調用這個函數,傳入一個分類的id,然后就可以發送請求了,獲取到數據之后,就把數據插入到 內容的數組中, 最后resolve()還告訴then可以執行了。
注意: 如何更新一個數組呢?
[UPDATE_ALL_CONTENT] (state, item) { state.contentItems = [...state.contentItems, Object.assign({}, item)]; },這樣就相當於push了。
上面的這個函數的意義在於封裝請求,那么對於請求多個時,如何做到呢?
我之前嘗試了下面兩種方法:
FIRST
// first method var promise = getItemPromise(items[0].id) for (let j = 1; j < items.length; j++) { promise.then(function () { return getItemPromise(items[j].id); }) }
思路就是先請求第一個分類,然后循環,實際上和下面的效果是一樣的:
var promise = getItemPromise(items[0].id); promise.then(function () { console.log("1", window.performance.now()); return getItemPromise(items[1].id); }); promise.then(function () { console.log("2", window.performance.now()); return getItemPromise(items[2].id); }); promise.then(function () { console.log("3", window.performance.now()); return getItemPromise(items[3].id); }); promise.then(function () { console.log("4", window.performance.now()); return getItemPromise(items[4].id); }); promise.then(function () { console.log("5", window.performance.now()); return getItemPromise(items[5].id); }); promise.then(function () { console.log("6", window.performance.now()); return getItemPromise(items[6].id); });
問題: 通過這樣的方法最終請求的數據是可以請求到的,但是順序並沒有按照我們預想的思路來執行,因為這樣的執行方式會在getItemPromise執行之后就立即同時執行后面幾個then,所以最終得到的順序是不能確定的。
方法二:
// second method var somePromise = getItemPromise(items[0].id); for (let k = 1; k < items.length; k++) { somePromise = somePromise.then(function () { return getItemPromise(items[k].id); }); }
這種方法的結構類似於下面這樣:
getItemPromise(items[0].id) .then(function () { console.log("1", window.performance.now()); return getItemPromise(items[1].id); }) .then(function () { console.log("2", window.performance.now()); return getItemPromise(items[2].id); }) .then(function () { console.log("3", window.performance.now()); return getItemPromise(items[3].id); }) .then(function () { console.log("4", window.performance.now()); return getItemPromise(items[4].id); }) .then(function () { console.log("5", window.performance.now()); return getItemPromise(items[5].id); }) .then(function () { console.log("6", window.performance.now()); return getItemPromise(items[6].id); }) .then(function () { console.log("7", window.performance.now()); return getItemPromise(items[7].id); }) .then(function () { return getItemPromise(items[8].id); }) .then(function () { return getItemPromise(items[9].id); }) .then(function () { return getItemPromise(items[10].id); }) .then(function () { return getItemPromise(items[11].id); })
這樣請求得到的順序就是相同的了。 但是通過for循環,不論分類有多少,我們都可以請求到。
也就是說,通過鏈式調用的方式,即.then().then()這樣才會在一個異步執行完之后執行下一個,值得注意。