0

コードがあります:

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) {

                });

            }
        }


    }

さまざまな方法でGLOBAL.theListを使用するb.js

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)に移動すると、ポップアップメッセージに「#2length 0」と表示されます。これは、GLOBAL.theListに何も含まれていないことを意味します。

  • ページが他の.jsファイルをロードする前に、default.htmlにglobal.jsを含めました。
  • テストしたところ、Windows.Storage.PathIO....promiseを使用しなかったときに機能しました。(データを直接GLOBAL.theListに任意に入れた場合)
4

1 に答える 1

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);

または、さらにクリーンにするために、promiseshowImageを使用するようにビルドします(関数内のコールバックをサブスクライブします)。

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

今、あなたは持っています

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

約束を使用します。完全に自然に見えます。

再編集 :名前空間


コールバック内で行う唯一のこととして、リストに物事をプッシュしたくないでしょう。

リストを使用しているのは何ですか?

theList.push()と同じ名前のカスタム関数はありますが、余分[].push()なものはありますか?

それとも単なる配列ですか?

問題は次のとおりです
。AJAXコールバックと同様に、Promiseは、次の処理に進む前に、処理が終了するのを待ちません。

したがって、プログラムがその配列で何かを行おうとしている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. 約束の範囲内で作業します-それらのポイントは、準備ができているかどうかを確認するためにタイマーを設定する必要がないようにすることです...したがって、値を設定しているだけで、誰にもそれらが準備できていることを伝えていない場合準備ができて、約束はその仕事をしていません

編集#2 re:ソース


ここで行っていることを見てください(簡略化):

// 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);

このようにpromiseを操作するときは、私の例はチェーン filesに追加したものとまったく同じオブジェクトであることを忘れないでください。.done()

また、関数がpromiseが返す値を気にする場合もあれば、promiseがいつ実行されるかを関数が知りたいだけなので、タイマーを設定してチェックする代わりに、後で発生する必要があることを実行できることも覚えておいてください。 。

そして、同期データを処理しているときはいつでも約束をとるクリーンアップされた関数を使用すると、次のことが可能になります。

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

readyこれが行っていることと古い準備ができていることの間に位置するために、もう1つの機能が必要であることを意味しますか?

まあ、そうだろう...

しかし、あなたの機能が早く消えないことを知っておく価値はあります。
そして、それは100%同期している間、ネストなしで本当にきれいに見えます。

急いでいる場合、またはこれらの他の関数を編集できない場合は、ページの下部にあるものをブートストラップするという悪い考えを行う可能性があります。

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

醜くて区別するのが難しく、別々のページで編集する必要がありますが、少なくともそれはまだ非同期であり、それでも順番に物事を行っています。

しかし、それでも、約束を返して収集し、渡すことを意味します。

お役に立てば幸いです。

于 2013-01-06T21:00:13.870 に答える