none
非同期メソッドを同期的に処理したい

    質問

  • MetroアプリをHTML/Javascriptで開発しております。

    非同期の処理をファンクション分割してかつ同期的に処理を行う方法をご教授いただきたいです。

    現在、フォルダを階層的に作成する処理を行っているのですが、うまくできません。
    行いたい処理の流れは以下の通りです。

    ・作成したいフォルダ数分(3回)ループする。
    1.1回目のループでcreateFolderAsyncを使用しフォルダ1を作成します。作成したフォルダ情報を前回情報として変数に格納。
    2.2回目のループで前回作成したフォルダの配下にcreateFolderAsyncを使用しフォルダ2を作成します。作成したフォルダ情報を前回情報として変数に上書き。
    3.3回目も同様にフォルダ3を作成します。

    ループ処理の中でcreateFolderAsyncを呼び出しているのですが、
    前回作成したフォルダが取得できない時があります。

    「時がある」と記載しているのはDebugerを使用し処理をBreakしながら実行していくと正常に終了するのですが、
    一気に処理を実行するとエラー(前回情報がNull)になり正常に処理できません。

    フォルダ作成処理が非同期で実行されてしまい、ループの処理が先に進んでしまっているからだと思うのですが、
    1回目フォルダ作成の処理が完全に完了したら、次の処理を進めるといった、同期処理にすることは可能なのでしょうか?
    2012年4月2日 8:57

すべての返信

  • JavaScriptは非同期処理が基本です。同期的な考え方そのものを改めることをお勧めします。

    Completedイベントに必要な処理を含めましょう。

    2012年4月2日 9:30
  • 返信ありがとうございます。

    一点、質問内容に補足させていただきます。

    ・作成したいフォルダ数分(3回)ループする。

    と記載致しましたが、ここで言う作成「3回」はあくまで例であり、回数は動的に変わります。

    本題に戻らさせていただきますが、もちろん、基本的に非同期で処理を行うということは承知しております。

    が、今回は先に述べました通り、ループの回数は動的に変わる、かつ、前ループの中で作成したファイル情報を次のループ処理で使用するため、

    質問内容のような処理の流れになっております。

    勉強不足なため、的外れな質問なのかもしれませんが、なにかありましたらご教授いただけると幸いです。

    2012年4月2日 13:33
  • 例えばですけど、

    var counter = 0;
    function callback(){
      if(--counter == 0){
        // 全部完了したので実際にやりたい処理をする
      }
    }
    
    counter++;
    xxx.Completed = callback;
    

    みたいにしていけば、全てが完了した時点で処理できますよ。このロジックにも穴はありますから、その辺りは適切に対処してください。JSDeferred、jQuery.Deferred、dojo.Deferred、Pot.Deferredみたいにうまくまとめられたユーティリティなんかもありますが、問題の本質を理解しておくことをお勧めします。

    2012年4月4日 0:50
  • Lisp風味なこれはどうでしょう?ドキュメントライブラリの下にフォルダを堀る例です。

        function digFolder(parentFolder, depth, n) {
            if (depth === 0) {
                return;
            }
            parentFolder.createFolderAsync("f" + n).done(function (childFolder) { digFolder(childFolder, depth - 1, n + 1); }, function () { /* error */ });
        }
    
        var rootFolder = Windows.Storage.KnownFolders.documentsLibrary
    
        digFolder(rootFolder, 3, 1);

    2012年4月25日 12:19
  • 最初のコメントってさっぱり見当はずれでしたか…

    function createAllFoldersAsync(storageFolder, path) {
      var names = path.split('\\');
      var result = WinJS.Promise.wrap(storageFolder);
    
      while (names.length > 0)
        (function (name) {
          result = result.then(function (sf) {
            return sf.createFolderAsync(name);
          });
        })(names.shift());
      return result;
    }
    

    Metro開発環境を持っていないのでリファレンスだけを読んで書いてますが、こんな感じですか…?

    # 無名関数の引数として各ディレクトリ名を保持させておいて、ディレクトリ作成が完了する度に保持していたディレクトリ名で作成していく感じ。

    2012年4月26日 8:34
  • いい感じ!てか、完璧!!しかもリファレンスだけで!?すごいですね!

    2012年4月26日 10:16
  • 佐祐理さま、Takeshi Misuさま

    返信が遅くなり、大変申し訳ございません。

    佐祐理さまからご提示いただいた内容で試してみます。

    現在、今回ご質問させていただいた内容とは異なる案件に着手してしまっているため、結果の返信が遅くなる可能性がありますが、ご了承ください。

    ありがとうございました。

    2012年5月17日 5:49