2

这个问题与打字稿并不完全相关,但如果没有上下文,就不清楚为什么我什至需要这种行为。应该相对直接地了解您是否了解 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");
    }
    ...
} 

我正在返回this,以便可以按如下方式链接对 Show() 的调用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)从第二个 Frame 调用,在对话框已经显示后加载内容(因此仍然存在延迟)。

我怎样才能完成这种同步行为?

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 语句并期望它们返回调用函数。

Ken 的回答是正确的,即使用 jQuery Deferred 将实现与 Frame 在上述示例中相同的目标。Frame 专为比您创建的序列长得多的序列而设计。两者的行为方式相同,主要区别在于语法。

老实说,我认为您遇到的延迟是进行 AJAX 调用所需的时间。也许我不理解您的问题,但 Frame 部分看起来正确。以下是一些注意事项:

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 回答