【问题标题】:javascript code execution and ajax asyncjavascript代码执行和ajax异步
【发布时间】:2013-01-16 06:50:14
【问题描述】:

我已经阅读了有关函数表达式与声明、回调、提升的分配,并且我对其中的大部分内容有了大致的了解,但我想由于下面的代码,我无法完全理解这个概念,让我发布代码和然后问真正的问题。

    var url = "beverages.txt";


   var GridModel = function () {
        this.items = ko.observableArray();
        var me = this;
        $.ajax({
            datatype: 'json',
            url: "beverages.txt"
        }).done(function (data) {
            debugger;
            var jsonData = $.parseJSON(data);
            me.items(jsonData);
        });
    };


    var model = new GridModel();

    // prepare the data
    var source =
    {
        datatype: "observablearray",
        datafields: [
            { name: 'name' },
            { name: 'type' },
            { name: 'calories', type: 'int' },
            { name: 'totalfat' },
            { name: 'protein' },
        ],
        id: 'id',
        localdata: model.items
    };

    var dataAdapter = new $.jqx.dataAdapter(source);

    $("#grid").jqxGrid(
    {
        width: 670,
        source: dataAdapter,
        theme: 'classic',
        columns: [
          { text: 'Name', datafield: 'name', width: 250 },
          { text: 'Beverage Type', datafield: 'type', width: 250 },
          { text: 'Calories', datafield: 'calories', width: 180 },
          { text: 'Total Fat', datafield: 'totalfat', width: 120 },
          { text: 'Protein', datafield: 'protein', minwidth: 120 }
        ]
    });

    ko.applyBindings(model);
});

好的,这段代码工作正常,它通过 var model = new GridModel(); 调用 ajax 请求。问题是,如果我添加一个调试器; var model = new GridModel(); 之后的语句它失败。此外,ajax 请求中的调试器语句也不会触发,但是如果我在 var model = new GridModel(); 之后删除调试器语句然后 ajax 触发,我可以调试请求。为什么附加调试器会失败,是因为 var GridModel 是一个表达式。

基本上我想做的是创建一个我可以调用的声明函数,当 ajax 请求完成时,我返回 observableArray。如果我像这样更改功能

  function GridModel (param1,param2) {
            this.items = ko.observableArray();
            var me = this;
            $.ajax({
                datatype: 'json',
                url: "beverages.txt"
            }).done(function (data) {
                debugger;
                var jsonData = $.parseJSON(data);
                me.items(jsonData);
            });
            return me
        };

然后我希望能够像这样调用该函数 var myitems = GridModel(param1,param2) 并期望 myitems 现在将保存 ajax 请求的结果。我只是不完全理解代码执行流程是如何工作的,如果有人能解释为什么底部功能不起作用以及如何让它工作,我将不胜感激。

谢谢, 丹

【问题讨论】:

    标签: javascript jquery ajax mvvm


    【解决方案1】:

    如果您有一个异步操作(如 Ajax 请求),并且其他一切都取决于它的结果,从回调中恢复您的程序流程。不能使用return 语句,它只适用于同步代码。

    您可能需要修改 GridModel 构造函数以将回调作为参数:

    var GridModel = function (callback) {
        this.items = ko.observableArray();
        $.ajax({
            datatype: 'json',
            url: "beverages.txt"
        }).done(callback);
    };
    

    然后从回调内部恢复您的程序流程:

    function resumeMyProgramFlow(data) {
        // Now you can use the data, resume flow from here
        debugger;
        var jsonData = $.parseJSON(data);
        model.items(jsonData);
        // etc.
    }
    

    然后像这样实例化GridModel

    var model = new GridModel(resumeMyProgramFlow);
    

    【讨论】:

    • 我想我明白你在说什么,我只是在代码中尝试过,但我遇到了同样的问题。 var model = new GridModel(resumeMyProgramFlow);模型是一个空对象。另外,如果我在 var model = new GridModel(resumeMyProgramFlow); 之后添加调试器语句然后ajax永远不会执行。对不起,我不明白,谢谢你的帮助!
    • Model 将是一个空的 GridModel 实例,里面有一个空的 observableArray。我不确定 Ajax 请求是否由调试器持有,但可能是这种情况。我的原始代码有一个我刚刚修复的错误。除此之外,我认为您的所有其余代码(在 var model... 之后)都应该放在回调中。
    • 模型在回调中,所以它还没有定义。现在尝试弄清楚并按照您的建议将代码放入回调中
    • 它被定义在范围的顶部(因为提升)。并且回调只会在 var model 行之后运行;到那时,它已经被分配了一个值,并且可以通过闭包提供给回调(我知道,这很混乱)
    • 好的,第一个问题是我的 resumeProgramFlow 在另一个 js 文件中,而不是在主 js 文件中。我移动了它,现在定义了模型。只是想解决这个问题。所以 var model 最初定义为一个空的 GridModel 因为提升,然后当回调函数被触发时,我可以用数据填充模型。想我终于明白了。我应该能够将附加参数传递给 new GridModel(resumeMyProgramFlow);像 GridModel(param1,param2,resumeMyProgramFlow);正确的?再次感谢您的帮助
    【解决方案2】:

    $.ajax(...).done(...) 返回时,程序流程继续。

    但是 ajax 调用还没有完成,因为它在后台向服务器发送数据并等待响应。这是异步部分。当响应最终从服务器到达时,执行.done(...) 中的部分

    function (data) {
        debugger;
        var jsonData = $.parseJSON(data);
        me.items(jsonData);
    }
    

    这是处理返回数据的位置和时间。

    您用var myitems = GridModel(param1,param2) 描述的是一个同步 方法。它调用服务器停止进一步处理并等待响应。

    虽然这是可能的,但它也会阻塞整个程序流程。这就是为什么 ajax 调用是异步的并且响应在回调函数中处理的原因。

    你想同步做什么

    var myitems = GridModel(param1,param2);
    // do something with myitems
    

    以这种方式异步完成

    $.ajax(...).done(function(data) {
        // 1. do something with myitems
    });
    
    // 2. this will run usually *before* number 1. above
    

    【讨论】:

    • 好的,有道理。我想要完成的是使 var GridModel = 函数更通用,这样我只定义了一个函数,我可以将参数传递给例如返回 ko 可观察数组的 url,然后我可以将其传递到源,source目前是硬编码的,但我还将有一个函数返回我想在 model.items 中传递的源。希望这是有道理的
    • @dan 我试图用一些代码来解释它。请查看更新的答案。
    • 谢谢,是的,我明白我试图不必将所有代码都放在 done 函数中,感谢您的解释
    最近更新 更多