【问题标题】:A property not initialized... yet it should be?未初始化的属性......但它应该是?
【发布时间】:2014-10-23 14:35:46
【问题描述】:

我有一个包含文件夹的列表,我正在尝试获取这些文件夹中文件总数的计数。

我设法检索包含我的文件夹的 ListItemCollection。然后它开始变得……挑剔。

ctx 是我的 ClientContext,collection 我的 ListItemCollection。

function countFiles()
{
    var enumCollection = collection.getEnumerator();

    while(enumCollection.moveNext())
    {
        currentItem = enumCollection.get_current();

        var folder = currentItem.get_folder();

        if (folder === 'undefined')
            return;

        ctx.load(folder, 'ItemCount');
        ctx.executeQueryAsync(Function.createDelegate(this, function()
            {
                totalCount += folder.get_itemCount();
            }), Function.createDelegate(this, onQueryFailed));
    }
}

所以它起作用了……一半的时间。如果我的集合中有 6 个项目,我会得到 3 或 4 个“属​​性或字段 'ItemCount' 尚未初始化”异常,显然我的 totalCount 是错误的。我似乎无法理解为什么,因为 executeQueryAsync 不应该在文件夹实际加载之前发生。

我对 Javascript 很陌生,所以它可能看起来很可怕,并且缺少一些我认为不值得感兴趣的基本代码,请随时询问是否是这样。

【问题讨论】:

  • 您遇到了一个非常常见的异步回调和 JavaScript 闭包问题。
  • @Pointy 必须有一些解决方法。我的意思是,我不可能是唯一愿意做这种事的人,对吧?
  • 我同意;我不熟悉 .createDelegate() 的东西,但我想我知道它的作用。
  • 如果这能让你感觉更好,我对这些都不熟悉。我从工作场所的其他 .js 文件中复制了这些,因此它们可能是也可能不是可怕的做法 :)
  • 解决这个问题很容易,我怀疑你在回调中引用“文件夹”,但另一个复杂之处是你真的无法知道什么时候总计的过程项目计数完成。这些异步回调将在它们完成时完成,并且最终总数将是正确的。处理起来更复杂。

标签: javascript sharepoint initialization


【解决方案1】:

从异步回调中引用闭包变量(如本例中的folder)通常是一个大问题。值得庆幸的是,它很容易修复:

function countFiles()
{
    function itemCounter(folder) {
        return function() { totalCount += folder.get_itemCount(); };
    }

    var enumCollection = collection.getEnumerator();

    while(enumCollection.moveNext())
    {
        var folder = enumCollection.getCurrent().get_folder();

        if (folder === undefined) // not a string!
            return;

        ctx.load(folder, 'ItemCount');
        ctx.executeQueryAsync(itemCounter(folder), Function.createDelegate(this, onQueryFailed));
    }
}

(您不需要 .createDelegate() 调用,因为该函数不需要 this。)

现在,在那之后,您将面临知道该计数器何时最终更新的问题。那些异步回调最终会完成,但是什么时候呢?您可以保留一个单独的计数器,为您启动的每个查询保留一个计数器,然后在回调中递减该计数器。当它回落到零时,你就会知道你已经完成了。

【讨论】:

  • 请注意,我完全不熟悉该集合 API,因此我对其行为的假设可能是错误的。但是,名称中带有“异步”和成功/失败回调的函数几乎可以肯定是异步的。
  • 嗯,使用 SharePoint,您永远不会知道。关于计数器,我其实已经实现了,但不想让代码太繁重。现在,我并不真正了解内部函数的用处,因此您的解决方案会带来什么。 (再一次,我 = JS 初学者 D :) 只是为了传递引用,所以我们不使用实际的 folder 变量,所以它可以和平关闭?
  • @Kilazur 没错 - 如果没有那个额外的中间函数,同一个“文件夹”变量将被所有回调共享,事情就无法正常工作。
【解决方案2】:

由于SP.ClientContext.executeQueryAsync 是一个async 函数,因此循环可能会在第一次调用回调函数完成之前终止,因此指定代码的行为可能是意外的。

相反,我会推荐另一种更简洁的方法来使用 SharePoint JSOM 对文件(包括位于嵌套文件夹下的文件)进行计数。

如何使用JSOM统计List中的文件总数

下面的函数可以统计List中列表项的个数:

function getItemsCount(listTitle, complete){
    var ctx = SP.ClientContext.get_current();
    var list = ctx.get_web().get_lists().getByTitle(listTitle);
    var items = list.getItems(createQuery());
    ctx.load(items);
    ctx.executeQueryAsync(
      function() {
          complete(items.get_count());
      },
      function() {
         complete(-1);
      }   
    );

    function createQuery()
    {
        var query = new SP.CamlQuery();
        query.set_viewXml('<View Scope="RecursiveAll"><Query><Where><Eq><FieldRef Name="FSObjType" /><Value Type="Integer">0</Value></Eq></Where></Query></View>');
        return query;
    }
}

用法

getItemsCount('Documents', function(itemsCount){
    console.log(String.format('Total files count in Documents library: {0}',itemsCount));
});

【讨论】:

  • 谢谢,因为这对教育目的很有帮助,但我的问题更多是关于 Pointy... 在他的 cmets 中指出的内容,而不是计数项目的实际事实。
猜你喜欢
  • 1970-01-01
  • 2016-05-23
  • 2011-07-17
  • 1970-01-01
  • 1970-01-01
  • 2019-12-02
  • 2021-06-21
  • 2017-03-03
  • 2012-05-26
相关资源
最近更新 更多