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()这样才会在一个异步执行完之后执行下一个,值得注意。