【问题标题】:How do I make a promise resolve as an object in the view?如何使承诺在视图中解析为对象?
【发布时间】:2018-12-20 02:47:18
【问题描述】:

我正在尝试包装第三方库以返回一个对象,该对象解析为可以在视图中显示的对象,类似于 $resource() 的工作方式。我知道我可以在 promise 上手动执行 .then() 然后设置值,但我希望结果能够无缝返回,类似于我可以执行的操作:

this.Value = $resource("/someresource").get();

如何更改以下 SomeThirdPartyFunction() 以返回在视图中解析的对象。

这是我正在尝试做的一个示例:

angular.module('testApp', []).controller('TestController', function ($timeout, $q) {
    var TestController = this;
    var SomeThirdPartyFunction = function () {
        var Deferred = $q.defer();
        var Promise = Deferred.promise;

        $timeout(function () {
            Deferred.resolve("abcd");
        }, 3000);

        return Promise;
    };

    TestController.Value = SomeThirdPartyFunction();

    /* I don't want to do this:
    SomeThirdPartyFunction().then(function(Value) {
      TestController.Value = Value;
    });*/
});

这是一个笨蛋:https://plnkr.co/edit/HypQMkaqXmFZkvYZXFXf?p=preview

我看到的每个使用 Promise 的示例都只是包装了 $http 调用,但我还没有看到任何调用第三方库的示例,这些库返回解析为对象的 Promise。

【问题讨论】:

  • $resource 服务仅在数据为对象或数组时有效。它不适用于示例中的字符串等原语。
  • 是的,我只是以字符串为例。我的具体用途是对象。

标签: angularjs angular-promise ngresource


【解决方案1】:

来自AngularJS document

重要的是要意识到调用 $resource 对象方法 立即返回一个空引用(对象或数组取决于 是数组)。一旦数据从服务器返回,现有的 参考是用实际数据填充的。

因此,您可以执行以下操作,而不是返回承诺:

  var SomeThirdPartyFunction = function() {
    var getAComplextObject = function() {
      return {
        number: 42,
        method: function() {
          return this.number + 1;
        }
      };
    };

    var returnValue = {};

    $timeout(function() {
      console.log("Resolved!");
      Object.assign(returnValue, getAComplextObject());
    }, 1000);

    return returnValue;
  };

你可以将它包装在一个 Promise 中,并让 Promise 成为返回值的一部分,这样做你可以使它成为 thenable(又名 Promise)

【讨论】:

  • 如果我需要返回一个带有方法的更复杂的对象而不是 1234,这将如何工作。我是否需要手动循环并复制每个属性/值?
  • 您不必克隆该对象,只需将其分配给 returnValue,类似于 returnValue.Value = complex_Object
  • 检查一个来自你的一个分支的例子plnkr.co/edit/NaiGN25iWh0YBZdUozdE?p=preview
  • 我不想将我的所有代码都更改为 Object.Value.Property。我希望我的视图能够使用 Object.Property
  • 所以棘手的部分是使用Object.assign,我已经更新了答案中的示例
【解决方案2】:

在后台,$resource 使用 angular.copy

function myResourceGet(params) {
    var emptyObj = {};
    emptyObj.$resolved = false;
    emptyObj.$promise = $http.get(url, {params:params})
      .then(function(response) {
        angular.copy(response.data, emptyObj);
    }).finally(function() {
        emptyObj.$resolved = true;
    });
    return emptyObj;
}

来自文档:

angular.copy 概述

创建source 的深层副本,它应该是一个对象或数组。

  • 如果提供了目标,则会删除其所有元素(对于数组)或属性(对于对象),然后将源中的所有元素/属性复制到它。

$resource 服务仅在数据为对象或数组时有效。它不适用于字符串或数字等原语。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-03-03
    • 1970-01-01
    • 1970-01-01
    • 2018-01-18
    • 2020-09-03
    • 1970-01-01
    • 2017-01-20
    • 1970-01-01
    相关资源
    最近更新 更多