2

この質問は typescript とはまったく関係ありませんが、コンテキストがなければ、なぜそのような動作が必要なのかは不明です。Typescript を知っているかどうかを理解するのは比較的簡単です。

Typescript には、次のようなダイアログ クラスの実装があります (関連するメソッドとフィールドのみを表示します)。

class BaseDialog{
     ...
     public dialogEl: JQuery;


     public AjaxLoadContent(route: string) { 
        if (this.dialogEl !== undefined)
           this.dialogEl.load(route);
        return this;
    }

    public HtmlLoadContent(html: string) { 
        if (this.dialogEl !== undefined)
           this.dialogEl.empty().html(html);
        return this;
    }

    public Show() { 
        if (this.dialogEl !== undefined)
            this.dialogEl.dialog("open");
    }
    ...
} 

次のように Show() への呼び出しをチェーンできるように、 andthisから戻ってきます。AjaxLoadContent()HtmlLoadContent()

var dialog = new BaseDialog();
dialog.AjaxLoadContent("/Account/Login").Show();  //Ajax call
dialog.HtmlLoadContent(someHtml).Show();          //Load from variable, no ajax call

この連鎖構文は非常にきれいで論理的だと思うので、それを使い続けたいのですが、ajax のシナリオでは、Show()ajax が完了する前に呼び出されるload()ため、ダイアログが開き、コンテンツが表示されるまでに遅延が生じます。load()内部で呼び出すのではなく、呼び出しに明示的にチェーンしたいので、コールバックを提供できませんShow()...したがって、ある種の同期メカニズムが必要です。

私は現在、Frame.js を調べて、ブラウザーを$.ajaxSetup({async: false;}). これがうまくいくと思っていた答えです:https://stackoverflow.com/a/10365952

ただし、次のコードにはまだ遅延があります。

 public AjaxLoadContent(route: string) { 
        if (this.dialogEl !== undefined){
             var that = this;
             Frame(function (next) { 
                 $.get(route, next);
             });
             Frame(function (next, response) { 
                 that.dialogEl.html(response);   //Breakpoint 1
             });
             Frame.init();
             return this;                            //Breakpoint 2
        }    
    }

ただし、定義した明示的な制御フローにもかかわらず、ブレークポイント 2 が最初にヒットするため、これは機能しないようです。Show()呼び出しは直後に発生しreturn this(したがって、空のダイアログが読み込まれます)、最終的にthat.jQueryDialog.html(response)2 番目のフレームから呼び出され、ダイアログが既に表示された後にコンテンツが読み込まれます (したがって、まだ遅延があります)。

この同期動作を実現するにはどうすればよいですか?

4

2 に答える 2

3

これはまさに(IMO)JQueryDeferredの目的です。Frame.js に別の依存関係を追加する必要なく、これをすべて使用できます。これを行う最も簡単な方法は、次のように、各 Async メソッドから JQueryPromise を返すことです。

///<reference path="./jquery.d.ts">

class BaseDialog{

     public dialogEl: JQuery;

     public AjaxLoadContent(route: string):JQueryPromise { 
            var deferred = $.Deferred();
            if (this.dialogEl !== undefined)
                this.dialogEl.load(route)
                    .done(() => deferred.resolve())
                    .fail(() => deferred.reject());

        return deferred.promise();
    }

    public HtmlLoadContent(html: string):void { 
        if (this.dialogEl !== undefined) {
            this.dialogEl.empty().html(html);
    }

    public Show():void { 
        if (this.dialogEl !== undefined)
            this.dialogEl.dialog("open");
    }
} 

var dialog = new BaseDialog();
dialog.AjaxLoadContent("something")
    .done(() => dialog.Show());

これはインターフェースとしてはそれほどきれいではありませんが、クラスが各 Deferred を FIFO キューにスローし、後続の各メソッドが実行を開始する前にキュー内の前の Deferred を待機するという非常に巧妙なコーディングを行うこともできます。確かに可能です。この API を大量の外部消費用に設計している場合は、実行する価値があるかもしれません。しかし、社内プロジェクトに使用するだけの場合は、作業とメンテナンスが多すぎるように思えます。(もちろん、私の意見です:-)。

(提案されたインターフェースのその他の問題: (1) ハンドラーに類似したエラーを処理する方法がありませんJQueryDeferred.fail()。(2) クラスへの呼び出しの間に外部処理を行う方法がありません。メソッドを呼び出す前にコンテンツを変換したい場合はどうすればよいでしょうShow()か?)

于 2013-01-22T03:07:02.063 に答える
1

「ただし、明示的な制御フローにもかかわらず、ブレークポイント 2 が最初にヒットするため、これは機能しないようです」

実際、フロー制御はあなたが書いたとおりに機能しています。Frame 関数内のものだけが Frame によって制御されます。コールバック内で return ステートメントを使用して、それらが呼び出し元の関数を返すことを期待することはできません。

ケンの答えは、jQuery Deferred を使用すると、上記の例で Frame が行うのと同じ目標を達成できるということです。フレームは、作成したものよりもはるかに長いシーケンス用に設計されています。どちらも同じように動作しますが、主な違いは構文です。

正直なところ、あなたが経験している遅延は、AJAX 呼び出しを行うのにかかる時間だと思います。あなたの質問を理解していないかもしれませんが、フレーム部分は正しく見えます。以下にいくつかの注意事項を示します。

public AjaxLoadContent(route: string) { 
    if (this.dialogEl !== undefined){
         var that = this;
         Frame(function (next) { 
             $.get(route, next); // great!
         });
         Frame(function (next, response) { // good use of passing variables!
             that.dialogEl.html(response); // yep, will happen synchronously!
             // return that; // unfortunately, this would only return 'that'
                             // to Frame, not to AjaxLoadContent.
                             // It's not possible to return the calling function
                             // from inside a callback.
             next(); // the callback should be called here
                     // to complete the Frame sequence.
         });
         Frame.init();
         return this; // notice that the return statement here is not in Frame?
    }    
}
于 2013-01-22T15:30:14.203 に答える