Javascript 动作方法执行序列

Javascript 动作方法执行序列,javascript,c#,jquery,asp.net-mvc,model-view-controller,Javascript,C#,Jquery,Asp.net Mvc,Model View Controller,我陷入了一个非常奇怪的境地。解释起来很复杂,但我会尽力的 我有一个带有4导航的UI 表单在MVC中使用Ajax.BeginForm构建 对于顶部的每个导航链接元素,我都有一个JavaScript函数 var LoadTabs = function (e, arg) { // This is to validate a form if one of the top links is clicked and form has incomplete fields... if (ar

我陷入了一个非常奇怪的境地。解释起来很复杂,但我会尽力的

我有一个带有4导航的UI

表单在MVC中使用Ajax.BeginForm构建

对于顶部的每个导航链接
元素,我都有一个JavaScript函数

var LoadTabs = function (e, arg) {  
    // This is to validate a form if one of the top links is clicked and form has incomplete fields...
    if (arg !== "prev" && arg !== "next") {
        if (!window.ValidateForm(false)) return false;
    }

    var url = $(this).attr('data'); // this contains link to a GET action method
    if (typeof url != "undefined") {
        $.ajax(url, { context: { param: arg } }).done(function (data) {                
            $('#partialViewContainer').html(data);
        });
    }
}
上面的函数绑定到页面加载时的每个顶部链接

$('.navLinks').on('click', LoadTabs);
我的“下一步”和“上一步”按钮基本上会触发单击事件,即
LoadTabs
功能

$('button').on('click', function () { 
        if (this.id === "btnMoveToNextTab") {
            if (!window.ValidateForm(true)) return false;                

            $.ajax({
                url: url,
                context: { param: 'next' },
                method: "GET",
                data: data,
                success: function(response) {
                    if (typeof response == 'object') {
                        if (response.moveAhead) {
                            MoveNext();
                        }
                    } else {
                        $('#mainView').html(response);
                    }
                    ScrollUp(0);
                }
            });
        } 

        if (this.id === "btnMoveToPreviousTab") {
            MoveBack();
        }
        return false;
    });


MoveNext() Implementation is as below:

function MoveNext() {        
    var listItem = $('#progressbarInd > .active').next('li');        

    listItem.find('.navLink').trigger('click', ['next']);
    ScrollUp(0);
}
问题是,由于某些原因,当导航链接3处于活动状态时,我点击下一步按钮-而不是首先通过form.submit()发布表单-导航4被触发-因此,导航4的GET在导航3的表单发布之前运行

我的ValidateForm方法基本上只是检查表单是否存在并且有效,然后提交,否则返回false。详情如下:

function ValidateForm(submit) {

    var form = $('form');

    // if form doesn't exist on the page - return true and continue
    if (typeof form[0] === "undefined") return true;

    // now check for any validation errors
    if (submit) {
        if (!$(form).valid()) {                
            return false;
        } else {
            $(form).submit();
        }
    } 
    else {
        return true;
    }

    return true;
}
我的推测是form.submit确实会被触发,但由于完成submit需要更长的时间,因此它会继续执行按钮
onclick
事件中的下一个代码块

我首先认为这是C#的问题,因为在文章中,我用几个循环保存了一大块数据,任何处理量大的代码块我都参与其中

var saveTask =  Task.Factory.StartNew(() => ControllerHelper.SomeMethod(db, model));
Task.WaitAll(saveTask);
WaitAll将等待并暂停执行,直到SomeMethod完成执行。我不确定如何用javascript锁定进程并等待它完成执行。因为我想如果我能在ValidateForm中锁定表单.submit(),直到它完成处理。。也许通过回调方法

如果有人能帮我找到正确的方向,我将非常感谢你的帮助。如果您需要更多信息,请让我知道我很乐意提供

编辑关于返回承诺的反模式 正如jfriend00所评论的,原始答案返回承诺的方式是反模式的,更好的方式是:

function ValidateForm(){
    // do your logic
    if (pass) {
        return $.post("urlToPost");
    else {
        return $.Deferred().reject(xxx).promise();
    }
}
更多信息,请结帐

原始答案 我将尝试想象您的问题:

您需要的是,首先在表单通过时运行
ValidateForm
(例如,当表单发布完成时),然后执行
MoveNext

您的问题是,
MoveNext
ValidateForm
完成之前被调用

如果我是正确的,那么原因是Javascript本质上是异步编程的,因此在完成某些操作时使用回调来触发

所以在你的情况下,你需要用承诺来实现它

基本上,您需要做的是:

  • ValiateForm
    返回承诺
  • 仅在
    ValidateForm
    完成后执行
    MoveNext
  • 所以代码应该是这样的:

    function ValiateForm(){
        var dfd = jQuery.Deferred();
    
        // do your logic
        if(pass){
            $.post("urlToPost"
        } else {
            // also failed
            dfd.reject();
        }
    
        // return the promise
        return dfd.promise();
    }
    
    然后你的“下一步”按钮会是

    $('button').on('click', function () { 
            if (this.id === "btnMoveToNextTab") {
    
                $.when(window.ValidateForm(true)).then(function(){
                // after success post form
                $.ajax({
                            url: url,
                            context: { param: 'next' },
                            method: "GET",
                            data: data,
                            success: function(response) {
                                if (typeof response == 'object') {
                                    if (response.moveAhead) {
                                        MoveNext();
                                    }
                                } else {
                                    $('#mainView').html(response);
                                }
                                ScrollUp(0);
                            }
                        });
                if (this.id === "btnMoveToPreviousTab") {
                    MoveBack();
                }
            } 
            return false;
            });                
    
    
    });
    
    更多关于承诺结帐的信息

    完成后跑步

    编辑关于退货承诺的反模式 正如jfriend00所评论的,原始答案返回承诺的方式是反模式的,更好的方式是:

    function ValidateForm(){
        // do your logic
        if (pass) {
            return $.post("urlToPost");
        else {
            return $.Deferred().reject(xxx).promise();
        }
    }
    
    更多信息,请结帐

    原始答案 我将尝试想象您的问题:

    您需要的是,首先在表单通过时运行
    ValidateForm
    (例如,当表单发布完成时),然后执行
    MoveNext

    您的问题是,
    MoveNext
    ValidateForm
    完成之前被调用

    如果我是正确的,那么原因是Javascript本质上是异步编程的,因此在完成某些操作时使用回调来触发

    所以在你的情况下,你需要用承诺来实现它

    基本上,您需要做的是:

  • ValiateForm
    返回承诺
  • 仅在
    ValidateForm
    完成后执行
    MoveNext
  • 所以代码应该是这样的:

    function ValiateForm(){
        var dfd = jQuery.Deferred();
    
        // do your logic
        if(pass){
            $.post("urlToPost"
        } else {
            // also failed
            dfd.reject();
        }
    
        // return the promise
        return dfd.promise();
    }
    
    然后你的“下一步”按钮会是

    $('button').on('click', function () { 
            if (this.id === "btnMoveToNextTab") {
    
                $.when(window.ValidateForm(true)).then(function(){
                // after success post form
                $.ajax({
                            url: url,
                            context: { param: 'next' },
                            method: "GET",
                            data: data,
                            success: function(response) {
                                if (typeof response == 'object') {
                                    if (response.moveAhead) {
                                        MoveNext();
                                    }
                                } else {
                                    $('#mainView').html(response);
                                }
                                ScrollUp(0);
                            }
                        });
                if (this.id === "btnMoveToPreviousTab") {
                    MoveBack();
                }
            } 
            return false;
            });                
    
    
    });
    
    更多关于承诺结帐的信息

    完成后跑步


    我把这篇文章发给Alan,因为它是多行代码,我无法让它在评论中可读。为了避免有时运行异步操作,有时不运行异步操作时出现promise反模式,可以使用以下方法:

    function ValidateForm(){
        // do your logic
        if (pass) {
            return $.post("urlToPost");
        else {
            return $.Deferred().reject(xxx).promise();
        }
    }
    

    这样,你总是回报一个承诺。在一个例子中,承诺来自
    $.ajax()
    。在另一种情况下,您只是返回了一个被拒绝的承诺,因为操作已经失败。

    我将这篇文章发给Alan,因为它是多行代码,我无法让它在注释中可读。为了避免有时运行异步操作,有时不运行异步操作时出现promise反模式,可以使用以下方法:

    function ValidateForm(){
        // do your logic
        if (pass) {
            return $.post("urlToPost");
        else {
            return $.Deferred().reject(xxx).promise();
        }
    }
    

    这样,你总是回报一个承诺。在一个例子中,承诺来自
    $.ajax()
    。在另一种情况下,您只是返回一个被拒绝的承诺,因为操作已经失败。

    非常感谢@Alan-我会尝试一下,让您知道!再次感谢@Alan。我最终解决了所有问题,遇到了延迟实现的小问题,但它也得到了解决。谢谢快乐编码:)这里的第一个代码块是。由于
    $.post()
    已经返回了一个承诺,因此不需要在它周围再包装一个承诺/延迟。您只需返回
    $.post()
    已经返回的承诺,而无需创建自己的承诺。@jfriend00感谢您提供的信息。只是想进一步澄清一下最佳实践。因为OP提到它将验证表单和post-因此我的理解是它可能会在发布前失败客户端验证-因此承诺拒绝
    if(pass)
    失败。因此,从
    $.post()
    返回承诺是不可能的,因为它可能没有发生。在这种情况下,它仍然是反模式的吗?或者,有什么更好的方法来实现这一点?再次感谢您指出这一点,只是想确保在编辑我的答案供将来参考之前得到正确答案。我发布了一个避免这种反模式的方法,作为另一个答案。非常感谢@Alan-我会尝试一下,让您知道!再次感谢@Alan。我终于弄明白了一切,遇到了一个