Javascript Typescript-使用Frame.js的同步ajax调用(解决方案:jQueryFerred)

Javascript Typescript-使用Frame.js的同步ajax调用(解决方案:jQueryFerred),javascript,typescript,framejs,Javascript,Typescript,Framejs,这个问题与typescript并不完全相关,但如果没有上下文,就不清楚我为什么会要求这样的行为。应该比较直截了当地理解你是否知道打字脚本 我有一个Typescript中的对话类实现,看起来像这样,只显示相关的方法和字段: class BaseDialog{ ... public dialogEl: JQuery; public AjaxLoadContent(route: string) { if (this.dialogEl !== unde

这个问题与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");
    }
    ...
} 
我将从AjaxLoadContent和HtmlLoadContent返回此内容,以便我可以链接一个调用以显示以下内容:

var dialog = new BaseDialog();
dialog.AjaxLoadContent("/Account/Login").Show();  //Ajax call
dialog.HtmlLoadContent(someHtml).Show();          //Load from variable, no ajax call
我发现这种链接语法非常干净且合乎逻辑,因此我想继续使用它,但是,在ajax场景中,在ajax加载完成之前调用Show,这样对话框就会打开,然后在内容出现之前会有一个延迟。我无法提供要加载的回调,因为我想显式地将Show链接到调用上,而不是在内部调用它……因此,我需要某种同步机制

我现在正在研究Frame.js,以实现这种同步样式,而不必使用类似$.ajaxSetup{async:false;}的东西挂起浏览器。以下是我希望能奏效的答案:

但是,以下代码仍有延迟:

 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调用在返回this之后立即发生,因此加载一个空白对话框,然后最后从第二帧调用that.jQueryDialog.htmlresponse,在对话框已经显示之后加载内容,因此仍然存在延迟

如何实现这种同步行为?

这正是我的目的。您可以将其用于所有这些,而无需在Frame.js上添加另一个依赖项。最简单的方法是从每个异步方法返回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());
这并不是一个干净的接口,但另一种方法是做一些非常聪明的编码,你的类将每个延迟的方法抛出到FIFO队列中,然后每个后续方法在队列中等待前一个延迟的方法,然后再开始执行。当然是可能的,如果您正在为大量外部消费设计此API,那么它可能值得一做。但是,如果你只是打算在一些内部项目中使用它,对我来说,这听起来像是太多的工作和维护。当然,这只是我的意见:-

您建议的接口的其他问题:1它没有任何处理错误的方法,这对jQueryFerred.fail处理程序来说是一个危险的问题;在调用类之间,它没有任何方式进行任何外部处理。如果您想在调用Show方法之前对内容进行转换,该怎么办?

这正是我的目的。您可以将其用于所有这些,而无需在Frame.js上添加另一个依赖项。最简单的方法是从每个异步方法返回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());
这并不是一个干净的接口,但另一种方法是做一些非常聪明的编码,你的类将每个延迟的方法抛出到FIFO队列中,然后每个后续方法在队列中等待前一个延迟的方法,然后再开始执行。当然是可能的,如果您正在为大量外部消费设计此API,那么它可能值得一做。但是,如果你只是打算在一些内部项目中使用它,对我来说,这听起来像是太多的工作和维护。当然,这只是我的意见:-


您建议的接口的其他问题:1它没有任何处理错误的方法,这对jQueryFerred.fail处理程序来说是一个危险的问题;在调用类之间,它没有任何方式进行任何外部处理。如果您想在调用Show方法之前对内容进行转换,该怎么办?

然而,尽管有显式的控制流,但这似乎不起作用,因为断点2首先被命中

实际上,流控件的工作方式与您编写的完全相同。只有框架函数中的内容才由框架控制。您不能在回调中使用return语句并期望它们返回调用函数

Ken的回答是正确的,使用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?
    }    
}

然而,尽管有显式的控制流,但这似乎不起作用,因为首先命中断点2

实际上,流控件的工作方式与您编写的完全相同。只有框架函数中的内容才由框架控制。您不能在回调中使用return语句并期望它们返回调用函数

Ken的回答是正确的,使用jQuery 延迟将实现与上面示例中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?
    }    
}

谢谢你的回答+1也适用于失败处理程序和调用之间的外部处理的最后几点。这无疑使这个解决方案比我最初想要的更优越。刚刚有机会测试这个。从概念上讲,它非常有效。尽管我想指出记录加载没有.done或fail回调。您可以使用ajax{…}.done.fail或我使用success/error回调所做的操作来解析延迟:$.ajax{url:routeToLoad,success:htmlResponse:string=>{that.jQueryDialog.htmlhtmlhllResponse;deferred.resolve;},error:=>{deferred.reject;}};……无论如何,再次感谢。感谢您的出色回答。+1还感谢失败处理程序和调用之间的外部处理的最后几点。这无疑使此解决方案优于我最初想要的。刚刚有机会测试此解决方案。从概念上讲,效果很好。尽管我想指出的是,记录负载并不是这样拥有.done或fail回调。您可以使用ajax{…}.done.fail或我使用成功/错误回调所做的操作来解析延迟:$.ajax{url:routeToLoad,success:htmlResponse:string=>{that.jQueryDialog.htmlhtmlhlResponse;deferred.resolve;},错误:=>{deferred.reject;}};……无论如何,再次感谢。谢谢你的回答。我知道我在某种意义上误解了你的库不是为这个而设计的。不过,它看起来是一个很好的多功能插件,也许我以后会发现需要它。我会用它来加载模块,但Typescript在内部使用基于给定编译器的两个选项之一来处理flag:common.js或require.js。你应该指出Frame.js相对于require.js在向Typescript团队加载模块方面的优势,也许他们可以在未来的版本中选择使用它而不是require.js。此外,如果你愿意,你可以为Frame.js添加类型定义,或者甚至可以问Boris Yankov是否可以这样做。一切都很好。谢谢你的想法!我会研究一下。另外,说清楚一点,Frame完全能够完成你在这里所做的事情。它的工作原理与Deferred相同,而且我认为它的语法更可读。不是Frame不是为这个用途而设计的,而是Frame比Deferred更具可扩展性。再次感谢&祝你好运!usin如何g下一步,响应=>{},那么var=this;就不需要了谢谢你的回答。我知道我在某种意义上误解了你的库,它不是为这个而设计的。然而,它看起来是一个很好的多功能插件,也许我以后会发现需要它。我会用它来加载模块,但Typescript在内部使用基于给定c的两个选项之一来处理ompiler flag:common.js或require.js。您应该指出Frame.js在向Typescript团队加载模块方面优于require.js,也许他们可以在未来的版本中选择使用它而不是require.js。此外,如果您愿意,您可以为Frame.js添加类型定义,或者甚至可以询问Boris Yankov是否可以这样做。好吗最好的。谢谢你的想法!我会研究一下。另外,说得清楚,Frame完全能够完成你在这里所做的事情。它的工作原理与Deferred相同,而且我认为它的语法可读性更高。不是Frame不是为这个用途而设计的,而是Frame比Deferred更具可伸缩性。再次感谢&祝你好运!多么好啊使用next,response=>{},则不需要=this;的变量