使用Promise之外的变量(在windows8 javascript开发中)

时间:2013-01-06 20:34:07

标签: javascript windows-8 promise

有一个代码:

var theContent;    
Windows.Storage.PathIO.readTextAsync(filepath).done(function (fileContent) {

                    theContent= fileContent;

                },

                function (error) {

                });

然后当我想在Windows.Storage.PathIO.readTextAsync之外使用'theContent'时, 它不起作用...... theContent变量根本不包含任何内容。

代码的哪一部分有误? 谢谢!


我把部分原因造成了麻烦。

global.js ,其中包含用于共享的命名空间数组变量。 (在a.js和b.js中)

WinJS.Namespace.define("GLOBAL", {
        theList: null
    });

a.js ,会在某个文件中加载文字。

function readTextFromFiles() {

        GLOBAL.theList= new WinJS.Binding.List();

        for (var i = 0; i < theFileList.length; i++) {

            if (theFileList.getAt(i).filepath !== null) {

Windows.Storage.PathIO.readTextAsync(theFileList.getAt(i).filepath).done(function (fileContent) {

                    var splitted = fileContent.split("\r\n");

                    for (var j = 0; j < splitted.length; j ++) {
                        GLOBAL.theList.push({
                            partA: splitted[j]
                        });
                    }


                },

                function (error) {

                });

            }
        }


    }

b.js 以各种方式使用GLOBAL.theList

ready: function (element, options) {

            new Windows.UI.Popups.MessageDialog("#2 length " + GLOBAL.theList.length, "MESSAGE").showAsync().then();
        },

这是问题所在。 当我调试 a.js 时,我看到 GLOBAL.theList 正确包含文件的文本。但是,当我将页面导航到 b.html(b.js)时,弹出消息显示“#2 length 0”,这意味着 GLOBAL.theList 不包含任何内容。

  • 在页面加载其他.js文件之前,我在default.html中包含了global.js.
  • 我测试过,当我没有使用Windows.Storage.PathIO ....承诺时,它工作正常。 (当我直接将数据放入GLOBAL.theList中时)

1 个答案:

答案 0 :(得分:3)

您要求theContent直线(程序)而不是回调的部分。

.done(function (content) { doStuff(content); });

或者,如果doStuff没有使用this并且您不需要对其执行任何其他操作,那么只有.done(doStuff);和doStuff会在内容时触发内容回来了。

loadImage = function () {}; // returns promise
showImage = function (image) {} // shows image

var imageLoading = loadImage("img/huge-img.bmp");

imageLoading.done(showImage);

或者为了使它更清晰,构建showImage以使用promises(在函数内部订阅它们的回调)。

function showImage(promise) {
    promise.done(function (img) { 
    document.body.appendChild(image);
 });

现在你有了

 var image = loadImage("huge-img.bmp");
 showImage(image);

使用承诺。看起来很自然。

编辑 re:命名空间


你仍然可能不想把事情放到列表中,这是你在回调中做的唯一事情。

什么是使用清单?

theList.push()是一个自定义函数,与[].push()具有相同的名称但是会有额外的东西吗?

或者只是一堆东西?

问题在于:
就像AJAX回调一样,承诺不会等待事情完成,然后继续下一件事。

因此,如果你的程序试图对那个数组做一些事情,在done之外(当数组最终会有数据时),那么这些函数将在一个空数组上工作。

相反,您应该使用方法(回调)来处理Promise的返回。

// these both do the same thing
/* ... */ .done(function (data) { NAMESPACE.module.callback(data); });
/* ... */ .done(NAMESPACE.Module.callback.bind(NAMESPACE.Module));

// if NAMESPACE.Module.callback ***does not use `this`*** you can write
/* ... */ .done(NAMESPACE.Module.callback);
// if you are unsure for even a second, do one of the other two calls

如果您需要对回调中的数据进行更多操作,那么只需执行以下操作:

/* ... */ .done(function (data) {
    var arr = doStuff(data);

    arr.forEach(function (obj) {
        NAMESPACE.Module.list.push(obj);
    });

    NAMESPACE.Module.callback_relying_on_list();
});

请注意,这里的2个键是:

  1. 确保回复中this正确无误
  2. 在承诺内部工作 - 他们的观点是,你不必设置定时器,看看是否有东西准备好了,但是...所以如果你只是设定价值而不告诉任何人他们准备好了,承诺没有做好自己的工作
  3. 编辑#2 re:source


    看看你在这里做了什么(简化):

    // a.js
    
    function getFiles () {
        GLOBAL.list = [];
        getAsyncData().done(function (text) {
            GLOBAL.list.push({ content : text });
        });
    }
    
    //b.js
    GLOBAL.Messages = {
        write : function (messages) {
            messages.forEach(/* ... */);
        },
        ready : function () { alert(GLOBAL.list.length); } }
    };
    
    // main program
    getFiles();
    GLOBAL.Messages.ready();
    GLOBAL.Messages.write(GLOBAL.list);
    

    我知道这不是你的确切代码,但请看一下这种简化的情况:

    如果我的getFiles功能运行正常但服务器没有将数据发回30秒会怎样?

    我的readywrite函数不会等待这种情况发生 我的getFiles完成后就会开火。

    所以在这里,你在错误的地方得到了这个承诺 这是100%被称为正确的方式,但为什么不这样做:

    // a.js
    function getFiles () {
        var filesLoaded = getAsyncData(); // I'm collecting the promise, not chaining it. 
        // again, simplified
        filesLoaded.done(function (text) { GLOBAL.list.push({ content : text}); });
    
        // ***super important part***
        return filesLoaded;
    }
    
    
    // b.js
    /* ... */ = {
    
        ready : function (promise) {
            promise.done(function () { alert(GLOBAL.list.length); });
        },
    
        write : function (promise) {
            promise.done(/* write the list */);
        }
    }
    

    现在你的主要看起来像这样:

    var files = getFiles(); // files is the promise
    // files.done, files.then, etc
    
    GLOBAL.Messages.ready(files); // giving the promise to the method
    // ready(promise) will subscribe to promise.done
    
    GLOBAL.messages.write(files); // so will write(promise);
    

    以这种方式处理promises时,请记住files我的示例与您在链中添加.done()的完全相同的对象。

    还要记住,有时你的函数会关心promise返回的值,有时候,函数只是想知道什么时候完成了promise,所以他们可以做一些事后需要发生的事情,而不是设置定时器检查。

    使用已清理的功能,只要您处理同步数据就可以接受承诺,现在您拥有:

    var files = readTextFromFiles();
    /* ... */.ready(promise);
    

    这是否意味着你还需要一个功能来处理这个ready正在做的事情以及旧的准备状态?

    嗯,是的......

    但是值得知道你的功能不会提前熄灭 它看起来很干净,没有巢,同时仍然100%同步。

    如果您匆忙,或者您无法编辑其他功能,那么您可能会做出错误的想法,这可能是在页面底部引导内容:

    (function (promise) { promise.done(function () {
        /* ... everything() ... */ });
    }(files));
    

    丑陋且难以挑选,需要在单独的页面上进行编辑,但至少它仍然是异步的,它仍然按顺序进行。

    仍然 意味着返回并收集并传递承诺。

    希望有所帮助。