【问题标题】:Why does it work correct with an array but not with an object?为什么它适用于数组但不适用于对象?
【发布时间】:2015-07-01 16:01:05
【问题描述】:

我正在开发一个 AngularJS 应用程序并发现以下行为。

我的服务中有两个功能。第一个函数返回存储在数据库中的所有类别,第二个函数通过其 id 返回一个类别。

这是我的服务:

angular.module('categoriesRepository', [])
.service('categoriesRepository', ['$cordovaSQLite', 'sqliteHelper',
    function ($cordovaSQLite, sqliteHelper) {
        //this works - returns an array with all categories
        this.getAll = function () {
            var categories = [];

            $cordovaSQLite.execute(sqliteHelper.getDb(),
                "SELECT * FROM categories;")
                .then(function (res) {
                    for (var i = 0; i < res.rows.length; i++) {
                        categories.push(res.rows[i]);
                    }
                });

            return categories;
        }

        //this works not - returns undefined
        this.getById = function (id) {
            var category;

            $cordovaSQLite.execute(sqliteHelper.getDb(),
                "SELECT * FROM categories WHERE id = ?;", [id])
                .then(function (res) {
                    category = res.rows[0];
                });

            return category;
        }

    }]);

我知道我可以使用 Angulars $q 异步运行函数,并在完成处理时使用它们的值。

为什么getById函数直接返回category,getAll等到数组填满?

编辑

我把 getAll 函数贴错了。 $cordovaSQLite.execute之前没有return语句

【问题讨论】:

    标签: javascript angularjs


    【解决方案1】:

    更新:- 在您的问题更新后。

    1. 在第一个示例中,您首先通过执行 var categories = []; 创建一个数组,然后在完成异步调用之前返回此数组。当您的异步调用完成时,它只是将某些元素推送到数组中,因此 不会 破坏对数组 (categories ) 变量的引用。当它返回时,如果你要调试它,你会发现函数返回一个空数组,稍后当异步调用成功时,数组才会被填充。

    2. 在第二个示例中,您只创建一个变量,然后在异步调用完成之前返回它。但是随后异步调用完成,您将变量分配给一个新值。从而破坏了之前的引用。

    解决方案:- 虽然不是使其工作的首选方法。您将必须维护类别变量引用。为此,您可以使用 angular.copyangular extend

    所以你的代码的第二部分应该像 this.getById = function (id) { 变量类别;

            $cordovaSQLite.execute(sqliteHelper.getDb(),
                "SELECT * FROM categories WHERE id = ?;", [id])
                .then(function (res) {
                    angular.copy(res.rows[0], category);
                    //now the reference to the category variable 
                    //will not be lost
                });
    
            return category;
        }
    

    更好的实践:- 您开发此应用程序的方式是错误的。不应以这种方式处理异步调用。我之前问了一个问题,只是为了澄清在 Angular 应用程序、工厂和控制器 please have a look here 中处理异步调用和状态的方式。它提供了两种处理状态和异步调用的方法。那里可能有更多的做法,但这两个最适合我。

    【讨论】:

    • 我把函数贴错了……在$cordovaSQLite.execute之前实际上没有返回。这两个函数之间的唯一区别只是返回一个数组或一个对象。
    【解决方案2】:

    不幸的是,这种方法似乎“奏效”了,因为它是由修改返回的数组对象“在某个未指定的时间”之后引起的它被退回

    在使用中,数组在1异步调用修改后被访问/观察。由于(意外的)异步延迟观察,这使它看起来正常运行。

    如果观察是在 SQLite 操作实际完成之前 - 例如在 getAll 函数调用之后 - 它会显示一个 empty 数组。

    两个函数都写错了,第一个不小心releases Zalgo(或者他的兄弟)。

    更多详情请见How do I return the response from an asynchronous call?

    1 Chrome 的 console.log 可能会令人困惑,因为它的工作方式与 console.dir 类似,因此可能会显示 当前 值,而不是调用时的值。

    【讨论】:

      【解决方案3】:

      如前所述,这是一种不好的方法。您不能在函数返回后立即使用它的结果。

      但是我没有看到您的确切问题的答案:为什么他们的行为不同

      发生这种情况是因为使用数组会返回对对象的引用(数组类型)。稍后您使用相同的引用来修改对象的内容,即将新项目推送到数组中。

      但是,在第二个函数中,您修改了引用本身。你让你的局部变量categories 指向一个新对象。因此旧对象(返回到外部范围的引用)保持不变。为了让它以你应该写的方式工作

      category.row = res.rows[0];
      

      【讨论】:

        【解决方案4】:

        您在第一种情况下返回执行结果,而在第二种情况下返回变量,很可能尚未填充。

        【讨论】:

          猜你喜欢
          • 2017-05-08
          • 1970-01-01
          • 2016-12-16
          • 2022-07-30
          • 2023-04-11
          • 1970-01-01
          • 1970-01-01
          • 2011-05-22
          • 1970-01-01
          相关资源
          最近更新 更多