js優化阿里雲圖片加載(一)

  1. 獲取阿里雲圖片的過程
    服務器返回圖片地址——請求服務器返回圖片真實地址——獲取圖片

  2. 目前遇到的問題
    重複進行1的過程影響性能,實現圖片加速加載。

  3. 在實際開發中的表現

    ·滑動列表時滑出去的item再次顯示時會重複上述過程。
    ·反覆查看某張圖片。

  4. 實現過程
    4.1 已經完成的實現

let params = {pics: paths, process: 'image/resize,m_fixed,w_76,h_76'};

// network是封裝的聯網請求
let result = await network({
	type: "POST",
	url: '/mobile/oss/signForAppPic',
    param: params
     }, token);

let reSetResult = result.response ? result.response : result;
let realPaths = reSetResult.result;

       實現了在加載圖片之前,從服務器獲取真實的圖片地址realPaths,然後再交給Image組件展示。發現真實的圖片路徑:https://gysy-picture.oss-cn-beijing.aliyuncs.com/app/x61tnmfx/BGQZ/ba112d3b-d41c-438a-ae88-002069a71aac.jpg?Expires=1543212261&OSSAccessKeyId=**********&Signature=*********&x-oss-process=image%2Fresize%2Cm_fixed%2Cw_100%2Ch_100
       有一個參數Expires是該圖片在阿里雲失效的時間秒數。因此,出現了一個解決思路就是:緩存真實的圖片地址,每次加載圖片時先看是否有緩存,緩存的圖片是否在有效期內,如果是就直接加載圖片;否的話,獲取圖片真實地址,再加載圖片並緩存。

4.2 實現步驟

  • 圖片地址的緩存,實現包括:初始化緩存對象、獲取緩存中的值、設置緩存中的值。通過這幾個方式實現了緩存的管理。(見4.3使用)

  • 有效期的判斷,通過Expires與當前時間的對比。在已實現代碼前添加判斷,添加後:

let realPaths;

if (isValid(cacheRealPaths) && this.state ) {
	realPaths = cacheRealPaths;
   	return;
}

let params = {pics: paths, process: 'image/resize,m_fixed,w_76,h_76'};
// network是封裝的聯網請求,可以根據實際的聯網請求進行更改
let result = await network({
	type: "POST",
	url: '/mobile/oss/signForAppPic',
    param: params}, token);
let reSetResult = result.response ? result.response : result;

realPaths = reSetResult.result;

4.3 使用
       將使用的方法封裝到了ALiYunImageCache.js中。

/**
 * 初始化緩存對象
 * @param arr
 * @returns {*}
 */
let initCache = (arr) => {

    if (arr) {
        return new Array(arr.length);
    } else {
        return null;
    }

};

/**
 * 獲取緩存中的值
 * @param arr
 * @param index
 * @returns {*}
 */
let getCache = (arr, index) => {

    if (arr && arr.length > index) {
        return arr[index];
    } else {
        return arr;
    }

};

/**
 * 設置緩存中的值
 * @param arr
 * @param index
 * @param newItem
 * @returns {*}
 */
let setCache = (arr, index, newItem) => {
    if (arr && arr.length > index) {
        return arr[index] = newItem;
    } else {
        return newItem;
    }

};

/**
 * 驗證緩存是否有效
 * @param cacheRealPaths
 * @returns {boolean}
 */
let isValid = (cacheRealPaths) => {
    if (cacheRealPaths && cacheRealPaths.length > 0) {
        let start = cacheRealPaths[0].indexOf('=') + 1;
        let end = cacheRealPaths[0].indexOf('&');
        let validTime = parseInt(cacheRealPaths[0].substring(start, end));
        let curTime = (new Date().getTime()) / 1000;
        if (validTime > curTime) {
            return true;
        }
    }
    return false;
};


module.exports = {initCache, getCache, setCache, isValid};
  • 初始化
           構造方法裏和緩存對象變化時,使用其中的initCache(arr)方法,返回保存的變量。arr:緩存的對象是列表時,傳入對應的數組;否則傳服務器返回的圖片地址。
  • 獲取緩存對象
           給展示圖片的組件使用,getCache(arr, index)。arr是第一步保存的變量,index:緩存的對象是數組時,傳入list中對應的索引;否則不傳。
  • 更新緩存
           使用setCach(arr, index, newItem)。arr是第一步保存的變量,index:緩存的對象是數組時,傳入list中對應的索引;否則傳null。newItem:傳新需要緩存的圖片地址。
  1. 例子(一個列表每個item包含多張圖片)
export default class demo extends Component {

    constructor(props) {
        super(props);

        // 初始化
        this.cacheRealPaths = initCache(props.connectListData);

    }

    componentWillReceiveProps(props) {
        if (props.dataList !== this.props.dataList) {
	    	// 所對應list數據變化時,重新初始化緩存
            this.cacheRealPaths = initCache(props.dataList);
        }
    };

    renderItem = ({item, index}) => (
        <DemoItem
            index={index}
            data={item}
            cacheRealPaths={getCache(this.cacheRealPaths, index)}   				// 獲取該index對應的緩存 
            updateCacheRealPath={(index, arr) => setCache(this.cacheRealPaths, index, arr)}	// 設置index對應的緩存 
        />
    );

    render() {
        return (
            <View>
                <FlatList
                    data={this.props.dataList}
                    keyExtractor={(item) => this.keyExtractor(item)}
                    renderItem={this.renderItem}
                />
            </View>

        );
    }
}

class DemoItem extends Component {

    render() {
        return (
            <View>
                <PhotoHorizontalScroll 
                    paths={this.props.data.pictures}
                    cacheRealPaths={this.props.cacheRealPaths}
                    updateCacheRealPath={(arr) => this.props.updateCacheRealPath(this.props.index, arr)}
            </View>
        )
    }
}

export default class PhotoHorizontalScroll extends Component {
    // 構造
    constructor(props) {
        super(props);

        this.state = {
            paths: []
        };

        ...

        this.newPaths = null;
    }

    ...

    showPictures = async (paths, cacheRealPaths) => {

        this.newPaths = paths;
        if (paths && paths.length > 0) {

            // 添加有效判斷
            if (isValid(cacheRealPaths) && this.state ) {
                this.setState({paths: cacheRealPaths});
                return;
            }

            let userInfo = await getUserInfo();
            let token = '';
            if (userInfo) {
                token = userInfo.access_token;
            }

            let params = {pics: paths, process: 'image/resize,m_fixed,w_76,h_76'};
            let result = await network({
                type: "POST",
                url: '/mobile/oss/signForAppPic',
                param: params
            }, token);

            let reSetResult = result.response ? result.response : result;

	    // 通知父組件更新緩存
            this.props.updateCacheRealPath && this.props.updateCacheRealPath(reSetResult.result);

            if (this.newPaths === paths && this.state) {
                this.setState({
                    paths: reSetResult.result
                })
            }
        }
        else {

            if (this.state) {
                this.setState({
                    paths: []
                })
            }
        }
    };

    ...

    render() {
        return (
            <ScrollView style={[this.props.style]}
                        horizontal={true}
                        showsHorizontalScrollIndicator={false}
            >
                <View style={{flexDirection: 'row'}}>
                    {this.renderImages(this.state.paths)}
                </View>
            </ScrollView>
        );
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章