You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Dojo的REST Tree中禁用缓存?附完整复现代码

解决Dojo JsonRestStore树节点名称不更新的缓存问题

你碰到的这个问题我之前也遇到过——确实是dojox.data.JsonRestStore的内部引用缓存在搞鬼!当节点用$ref标识时,Store会把第一次加载的节点数据缓存起来,哪怕后续REST接口返回了新的名称,它也直接复用缓存里的对象,根本不更新属性。下面给你几个靠谱的解决办法:

方法1:全局禁用JsonRestStore的对象缓存

最简单的方式就是在初始化Store时直接关闭默认缓存,同时确保查询请求也禁用缓存:

this.store = new dojox.data.JsonRestStore({
    target: 'reproducing-REST.php',
    labelAttribute: "name",
    cacheByDefault: false // 全局关闭默认缓存
});

同时在Tree的Model配置里明确添加查询级的缓存禁用:

this.model = new dijit.tree.ForestStoreModel({
    store: this.store,
    deferItemLoadingUntilExpand: true,
    rootId: "products",
    rootLabel: "Products",
    query: { queryOptions: { cache: false } }, // 确保查询不使用缓存
    childrenAttrs: ['children']
});

方法2:手动清除Store的内部缓存

如果不想全局禁用缓存,可以在刷新树之前,手动清除Store里存储$ref对应对象的_index缓存:

function refresh2() {
    // 新增:清除Store的内部缓存
    if (prod.store && prod.store._index) {
        for (var key in prod.store._index) {
            delete prod.store._index[key];
        }
    }
    // 原有销毁重建逻辑不变
    delete prod.tree;
    delete prod.model;
    delete prod.store;
    dijit.byId('products_tree').destroy(true);
    prod.init();
    prod.tree = new dijit.Tree({ 
        model: prod.model, 
        query: {queryOptions:{preventCache:true}}, 
        persist: false 
    }, 'products_tree');
    prod.tree.startup();
}

方法3:更新缓存对象属性(推荐)

如果想保留缓存优势同时更新名称,可以监听Store的onItemLoad事件,手动同步缓存对象的属性并触发Tree更新:

this.store = new dojox.data.JsonRestStore({
    target: 'reproducing-REST.php',
    labelAttribute: "name"
});
// 监听节点加载事件,同步更新缓存对象的名称
dojo.connect(prod.store, "onItemLoad", function(item, request) {
    var newName = prod.store.getValue(item, "name");
    if (item.name !== newName) {
        item.name = newName;
        // 通知Tree模型数据变化,刷新节点UI
        prod.tree.model.onChange(item);
    }
});

为什么你的refresh2方法无效?

你之前的refresh2只是销毁了Tree、Model和Store实例,但JavaScript内存里之前缓存的节点对象还存在。重新创建Store时,JsonRestStore会复用相同$ref对应的缓存对象,所以必须显式清除缓存或者禁用缓存机制。


修改后的复现代码

reproducing_problem.php

<?php if(!isset($_SESSION)) { session_start(); } $_SESSION['keyA']=0; ?> 
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> 
<html> 
<head> 
<title>Reproducing Cache Problem</title> 
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 
<!--META HTTP-EQUIV="CACHE-CONTROL" CONTENT="NO-CACHE"--> 
<script type="text/javascript" src="../external/dojo/dojo.js" djConfig="parseOnLoad: true"></script> 
<script type="text/javascript"> 
dojo.require('dojox.data.JsonRestStore'); 
dojo.require('dijit.Tree'); 
dojo.require("dijit.form.Button"); 

var prod= { 
    store: null, 
    model: null, 
    tree: null, 
    init: function() { 
        this.store = new dojox.data.JsonRestStore({ 
            target: 'reproducing-REST.php', 
            labelAttribute: "name",
            cacheByDefault: false // 新增:全局禁用缓存
        }); 
        this.model = new dijit.tree.ForestStoreModel({ 
            store: this.store, 
            deferItemLoadingUntilExpand: true, 
            rootId: "products", 
            rootLabel: "Products", 
            query: {queryOptions:{cache:false}}, // 新增:查询禁用缓存
            childrenAttrs: ['children'] 
        }); 
    } 
}; 

function refresh1() { 
    tree=prod.tree 
    tree._itemNodesMap = {}; 
    tree.rootNode.state = "UNCHECKED"; 
    tree.model.root.children = null; 
    if (tree.rootNode) { 
        tree.rootNode.destroyRecursive(); 
    } 
    tree._load(); 
} 

function refresh2() {
    // 新增:清除Store内部缓存
    if (prod.store && prod.store._index) {
        for (var key in prod.store._index) {
            delete prod.store._index[key];
        }
    }
    delete prod.tree; 
    delete prod.model; 
    delete prod.store; 
    dijit.byId('products_tree').destroy(true); 
    prod.init(); 
    prod.tree = new dijit.Tree({ 
        model: prod.model, 
        query: {queryOptions:{preventCache:true}}, 
        persist: false 
    }, 'products_tree'); 
    prod.tree.startup(); 
} 

dojo.addOnLoad(function() { 
    prod.init(); 
    prod.tree = new dijit.Tree({ 
        model: prod.model, 
        persist: false 
    }, 'products_tree'); 
    prod.tree.startup(); 
}); 
</script> 
<style type="text/css"> 
@import "../external/dijit/themes/soria/soria.css"; 
@import "../external/dojo/resources/dojo.css"; 
</style> 
</head> 
<body class="soria"> 
<div dojoType="dijit.form.Button"> 
    Change name and refresh 
    <script type="dojo/event" event="onClick"> 
        refresh1(); 
    </script> 
</div> 
<div id="products_tree"></div> 
<div id="notes">notes</div> 
</body> 
</html>

reproducing-REST.php

<?php if(!isset($_SESSION)) { session_start(); } 
$keyA=$_SESSION['keyA']; 
$_SESSION['keyA']=$keyA+1; 

if (array_key_exists('PATH_INFO', $_SERVER)) { 
    $arr = null; 
    $resource = $_SERVER['PATH_INFO']; 
    $method = $_SERVER['REQUEST_METHOD']; 
    error_log(" resource: ".$resource." \n",3,"mylogfile.txt"); 

    if ($method == 'GET') { 
        if ($resource=='/'){ 
            $arr=array(); 
            $sameref='1234'; 
            $name="Changing".$keyA; 
            error_log(" name: ".$name." \n",3,"mylogfile.txt"); 
            array_push($arr,array('$ref' => $sameref, 'name' => $name, 'children' => true)); 
        } else{ 
            $aProduct = ltrim($resource, '/'); 
            $arr=array(); 
            $name="exploding"; 
            $child='2345'; 
            array_push($arr,array('name' => $name,'idq' => $child)); 
            $arr=array('idp' => $aProduct, 'name' => $name, 'children' => $arr); 
        } 
        $status = 'HTTP/1.1 200 OK'; 
    } 
    header($status); 
    echo json_encode($arr); 
} 
?>

内容的提问来源于stack exchange,提问作者Paul Ghobril

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 07:33:50