美文网首页前端大牛程序员
Promise.all 应用一例

Promise.all 应用一例

作者: lip2up | 来源:发表于2018-03-29 15:19 被阅读31次

    在做小程序地图开发的时候,需要在地图上放置不同图标的 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
    微信公众号:前端大牛

    相关文章

      网友评论

        本文标题:Promise.all 应用一例

        本文链接:https://www.haomeiwen.com/subject/aidycftx.html