前端大牛程序员

Promise.all 应用一例

2018-03-29  本文已影响31人  lip2up

在做小程序地图开发的时候,需要在地图上放置不同图标的 markers,而这些图标又来自网络,恰恰由于微信小程序的限制,不支持网络图片作为 markersiconPath

微信小程序文档

但注意到也支持临时路径这句话,则可以先通过 wx.downloadFile 将图片先下载下来,恰好 wx.downloadFile 返回的是一个临时路径

基本的思路有了,但实践发现,微信小程序的 map 组件,实现有 bugmarkers 不能频繁更新,否则 markerios 下会莫名消失

因此,应该将全部的网络图片全部下载下来后,再整体设置 markersPromise.all 是完成这类任务,最好的工具之一

1、首先对 wx.downloadFile 进行 Promise 改造

代码如下:

// 下载网络文件到本地,即使失败,也要用默认值 defVal resolve
const downloadFile = (url, defVal) => {
    return new Promise((resolve, reject) => {
        wx.downloadFile({
            url,
            success(res) {
                resolve(res.tempFilePath)
            },
            fail() {
                // 即使失败,也要 resolve
                resolve(defVal)
            }
        })
    })
}

这里设计为,即便图片下载失败,也要用一个默认图标 resolve,上述代码,理论上不会 reject

2、下载所有图标,并制作对应关系 Map

假设 list 是全部的图标列表数组,数组中的每一项的数据结构为:

{
    id: 1,                                // 图标 ID
    lng: 166.8888,                        // 经度
    lat: 28.8888,                         // 维度
    img: 'https://.../xxx.jpg',           // 图标图片网址
}

列表中的 img 有重复的,所以第一步,我们获取所有 img 并虑重:

const allImgList = list.map(it => it.img).filter(it => !!it)
const imgList = unique(allImgList)

unique 是一个工具函数,用来数组虑重,这里就不展示了

接着,调用 downloadFile 下载所有所有图片,并用 Promise.all 等待所有图片被下载下来:

Promise.all(imgList.map(it => downloadFile(it, '../../images/food.png')))
.then(pathList => {
    const imgMap = combine(imgList, pathList)
    return imgMap
})

combine 是另外一个工具函数,功效与 phparray_combine 相同,它接受两个数组参数,用第一个数组的每一项做 key,第二个数组的每一项为 value,组成一个新对象

可以看出,这个新对象就是我们所需要的,img 网络地址,到微信小程序临时路径的映射 Map

这里的要点是,Promise.all 会按照数据源的顺序返回结果

3、一次性设置 markers

代码很简单,主要是按照微信小程序文档加工数据:

// 这一段是重复上面的代码
Promise.all(imgList.map(it => downloadFile(it, '../../images/food.png')))
.then(pathList => {
    const imgMap = combine(imgList, pathList)
    return imgMap
})
// 以下才是本节演示代码
.then(imgMap => {
    // 按照微信小程序文档加工数据
    const markers = list.map(({ id, lng, lat, img }) => {
        return {
            id,
            longitude: lng,
            latitude: lat,
            iconPath: imgMap[img],
            width: 36,
            height: 36,
        }
    })

    this.setMarkers(markers)
}

this.setMarkers 是具体设置 makers 的代码,无非是调用微信小程序的 setData,这里就不展示了

如果裸写微信小程序(即不用任何高层框架),它对 Promise 支持并不好,需要引入 Promise 外部库,建议大家用美团开源的框架 mpvue

4、结语

Promise 是非常伟大的发明,虽然,你也可以用其他代码,实现 Promise 的效果,但既然 Promise 从 n 个优秀异步方案中脱颖而出,成为 javascript 的标准,其魅力自是锐不可当,你又何必非要自己造轮子呢?

这里推荐一篇关于 Promise 的好文章(需要翻墙,下同):https://developers.google.com/web/fundamentals/primers/promises

当然,Promise 并不是最优方案,窃以为,异步函数(async function)才是未来,但它是以 Promise 为基础的,同样一篇好文章推荐给大家:
https://developers.google.com/web/fundamentals/primers/async-functions

整篇完。欢迎转载,转载请注明出处:
简书作者:lip2up
微信公众号:前端大牛

上一篇下一篇

猜你喜欢

热点阅读