You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

AngularJS工厂调用Parse Server报错:Cannot read property 'then' of undefined

问题分析与解决方案

这个错误TypeError: Cannot read property 'then' of undefined的核心原因很明确:你的ProductsFactory.getProducts()函数没有返回一个Promise对象——你把return product_dfd.promise写在了qr.get()的success回调函数内部,而getProducts本身执行完异步的qr.get()后就直接返回了undefined,自然没法调用.then()方法。

问题代码的关键缺陷

当你调用ProductsFactory.getProducts()时,函数会立即执行qr.get()(这是一个异步操作,不会等待回调执行),然后函数本身没有任何返回值,默认返回undefined。你写的return product_dfd.promise是在回调函数里的,只有当qr.get()成功后才会执行,但这时候getProducts早就执行完了,返回值已经是undefined了。

修正后的工厂代码

我们需要让getProducts直接返回一个Promise,把整个异步逻辑包裹在Promise的处理流程中,这里用AngularJS的$q来实现:

sebetimapp.factory('ProductsFactory', ['$q', function($q){
  Parse.initialize('MY_APP_ID', 'JS_KEY');
  Parse.serverURL = 'https://parseapi.back4app.com/';
  let fac = {};

  fac.getProducts = function(cat, lmt) {
    // 直接返回由$q创建的Promise
    return $q(function(resolve, reject) {
      let Category = Parse.Object.extend('Category'),
          qr = new Parse.Query(Category);

      qr.get(cat, {
        success: function (categoryRes) {
          // 类别查询成功后,执行产品查询
          let Product = Parse.Object.extend('Product'),
              query = new Parse.Query(Product);
          query.include('category');
          query.equalTo('category', categoryRes);
          if (lmt) {
            query.limit(lmt);
          }
          query.find({
            success: function(productResults) {
              resolve(productResults); // 解析产品查询结果
            },
            error: function(productErr) {
              reject(productErr); // 传递产品查询错误
            }
          });
        },
        error: function(object, categoryErr) {
          reject(categoryErr); // 传递类别查询错误
        }
      });
    });
  };

  return fac;
}]);

更进一步的简化(利用Parse的Promise支持)

其实Parse Server的查询方法本身是支持返回Promise的,我们可以用$q.when()把Parse的Promise转换成AngularJS的Promise(确保回调在Angular的digest cycle中执行,避免视图不更新的问题),代码会更简洁:

sebetimapp.factory('ProductsFactory', ['$q', function($q){
  Parse.initialize('MY_APP_ID', 'JS_KEY');
  Parse.serverURL = 'https://parseapi.back4app.com/';
  let fac = {};

  fac.getProducts = function(cat, lmt) {
    let Category = Parse.Object.extend('Category'),
        qr = new Parse.Query(Category);

    // 链式处理Promise:先查类别,再查对应产品
    return $q.when(qr.get(cat))
      .then(function(categoryRes) {
        let Product = Parse.Object.extend('Product'),
            query = new Parse.Query(Product);
        query.include('category');
        query.equalTo('category', categoryRes);
        if (lmt) {
          query.limit(lmt);
        }
        return $q.when(query.find()); // 返回产品查询的Promise
      })
      .catch(function(err) {
        // 统一处理所有错误
        console.error('查询失败:', err);
        throw err; // 继续向上抛出错误,让控制器捕获
      });
  };

  return fac;
}]);

控制器代码无需修改

你的控制器代码是正确的,只要工厂方法返回了Promise,.then()就能正常执行:

sebetimapp.controller('productsCtrl', ['$scope', '$log', '$location', '$q', 'ProductsFactory', function($scope, $log, $location, $q, ProductsFactory) {
  let params = $location.search(); // 从URL获取类别ID
  ProductsFactory.getProducts(params.cat, 20).then(function(response) {
    $log.log('Successfully retrieved products.');
    $scope.products = response; // 记得把结果赋值给scope,更新视图
  }, function(error) {
    $log.log('Unable to get products.', error);
  });
}]);

总结

核心问题就是工厂方法没有返回Promise,把return语句写在了异步回调内部导致函数返回undefined。只要让getProducts直接返回一个Promise对象,就能正常使用.then()进行链式调用了。

内容的提问来源于stack exchange,提问作者N'Bayramberdiyev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 03:29:08