2

我目前在 Windows 8/WinRT 应用程序中读取文件时遇到问题。我有一个简单的导航风格应用程序,多个页面可以访问相同的数据,并且我有一个 data.js 文件,该文件定义了一个包含多个成员的命名空间(数据)。应用程序的一部分将项目保存到存储在应用程序本地数据文件夹中的 txt 文件中。但是在其他一些页面上,我需要阅读此内容或检查以前保存的项目列表中是否存在项目。为此,我在 data.js 文件中添加了另一种方法。问题是,当我调用此方法来检查项目是否存在时,由于异步性质,它不会立即返回值,但页面特定 js 文件中的其余代码似乎仍然在它之前执行跳回解析。这意味着检查项目的逻辑不 t 似乎工作。我觉得这取决于我对 .done 或 .then 的使用,但我的代码如下:

  DATA.JS
   var doesItemExist= function(item_id){

    var appFolder = Windows.Storage.ApplicationData.current.localFolder;
   //note I've tried this with and without the first "return" statement
   return  appFolder.getFileAsync(dataFile).then(function (file) {
        Windows.Storage.FileIO.readTextAsync(file).done(function (text) {
            try {
                var json = JSON.parse(text);
                if (json) {
                    for (var i = 0; i < json.items.length; i++) {
                        var temp_item = json.items[i];
                        if (temp_item.id === item_id) {
                            return true;
                            break;
                        }
                    }
                } else {
                    return false;
                }
            } catch (e) {
                return false;
                console.log(e);
            }
        }, function (e) { return false;console.log(e); });
    }, function (e) { // error handling
        return false;
        console.log(e);

    });
}
 WinJS.Namespace.define("Data", {
    doesItemExist: doesItemExist
}); //all of the above is wrapped in a self executing function

然后在 Page.js 我有以下内容:

    var add = document.getElementById('add');
        if (Data.doesItemExist(selected_item.id)) {
            add.style.display = 'block';
        } else {
            add.style.display = 'none';
        }

这里的所有变量都已分配,调试不会产生任何错误,控制似乎只是在它到达 getFileAsync 之后但在它甚至通过 for 循环之前返回到 if/else 语句。但随后它确实进入了 for 循环,但在 if 语句完成之后。我猜这取决于这一切的异步性质,但我不知道如何解决它。有任何想法吗?

谢谢

4

1 回答 1

3

Promise 应该在这里工作。

我创建了一个新的导航应用程序,并添加了一个包含以下代码的 Data.js 文件:

(function () {
    var appData = Windows.Storage.ApplicationData;

    function doesItemExist(item_id) {
        return new WinJS.Promise(
            function (completed, error, progress) {
                var exists = false;
                appData.current.localFolder.createFileAsync("data.txt", Windows.Storage.CreationCollisionOption.openIfExists).then(
                    function (file) {
                        Windows.Storage.FileIO.readTextAsync(file).then(
                            function (fileContents) {
                                if (fileContents) {
                                    if (fileContents = "foo!") {
                                        completed(true);
                                    }
                                    else {
                                        completed(false);
                                    }
                                }
                                else {
                                    completed(false);
                                }
                            }
                        );
                    },
                    function (e) {
                        error(e);
                    }
                );
            }
        );
    }

    WinJS.Namespace.define("Data", {
        doesItemExist: doesItemExist
    });
})();

请注意,我已经简化了用于检索和解析文件的代码,因为这与问题并不真正相关。重要的部分是,一旦您确定了该项目是否存在,您调用completed(exists)会触发您返回的 Promise 的 .then 或 .done 。请注意,如果发生异常,您将调用 error(e),就像我正在做的那样,如果调用 createFileAsync 有异常(当我希望能够创建文件时,我使用此调用而不是 getFileAsync不存在,如果存在则返回现有文件,使用 openIfExists 选项)。

然后,在 Home.js 中,我将以下代码添加到就绪处理程序中:

var itemExists;

var itemExistsPromise = Data.doesItemExist(42);
itemExistsPromise = itemExistsPromise.then(function (exists) {
    itemExists = exists;
    var content = document.getElementById("content");
    content.innerText = "ItemExists is " + itemExists;
});

itemExistsPromise.done(function () {
    var a = 42;
});

var b = 0;

上面的代码将变量 itemExistsPromise 设置为从 Data.js 中的函数返回的 Promise,然后使用 Promise 的 .then 函数中的匿名函数将变量 itemExists 设置为从 doesItemExist Promise 返回的布尔值,并抓取来自 Home.html的<p>标签(我添加了一个 id 以便我可以从代码中获取它)并设置其文本以指示该项目是否存在)。因为我调用的是 .then 而不是 .done,所以该调用返回另一个 promise,它被传递到 itemExistsPromise 变量中。

接下来,我调用 itemExistsPromise.done 来完成任何必须等到它上面的 .then 中执行的工作之后的工作。

如果您在“var a = 42”和“var b = 0”行(仅用于设置断点的目的)以及“itemExists = exists”行上设置断点,您应该会发现这给了您执行各个部分时所需的控制。

希望有帮助!

于 2012-08-14T15:59:19.330 回答