$q defer 和 promises 以及如何使用它们在视图呈现之前为控制器加载数据

Posted

技术标签:

【中文标题】$q defer 和 promises 以及如何使用它们在视图呈现之前为控制器加载数据【英文标题】:$q defer and promises and how to use them to load the data for a controller before the view is rendered 【发布时间】:2012-08-31 17:04:23 【问题描述】:

这是我发现的最相关的东西:https://***.com/a/11972028/110233

当我只想返回一个东西时,它似乎工作正常,但是当其他东西依赖于第一件事时,我不确定如何返回多个东西。

由于这有点迟钝,这里有一个关于我目前正在做的事情的小例子:

window.EventRosterCtrl = ($scope, subevent) ->
    $scope.subevent = subevent

EventRosterCtrl.resolve = 
    subevent: (SubEvent, $route) ->
        deferred = $q.defer()

        SubEvent.get subevent_id: $route.current.pathParams.subevent_id, (subevent) ->
            deferred.resolve subevent

        return deferred.promise

这是我想做的一个例子:

window.EventRosterCtrl = ($scope, subevent, addresses) ->
    $scope.subevent = subevent
    $scope.addresses = addresses

EventRosterCtrl.resolve = 
    subevent: (SubEvent, $route) ->
        deferred = $q.defer()

        SubEvent.get subevent_id: $route.current.pathParams.subevent_id, (subevent) ->
            deferred.resolve subevent

        return deferred.promise

    addresses: (User) ->
        deferred = $q.defer()

        # how do you get subevent called first and how would you access it here?
        for participant in subevent.participants
            User.get user_id: participant.user, (user) ->
                addresses[participant._id] = user.address

        deferred.resolve addresses

        return deferred.promise

【问题讨论】:

【参考方案1】:

您需要使用 .then() 链接承诺

var promise = firstOperation(); 承诺 = promise.then(函数(值) // 做更多的工作 返回值; // 它可以是另一个promise ); 回报承诺; // 当两个步骤都解决时,这一个将被解决

【讨论】:

@Justen,我不知道 Coffescript,但是您示例的最后一行可能类似于 return deferred.promise.then(function(value) return value; ),即 promise.then() 返回一个新的承诺。 那行不通。解析是一个将键映射到函数的对象,子事件中的延迟将无法在另一个键映射中访问【参考方案2】:

好的,因此您无法以这种方式控制它,但想到的解决方法(当一个解决方案首先取决于另一个完成时)只需将所有内容放在一个对象中并解决它。最终对我最有效的是提供服务,但要遵循我原来的例子:

window.EventRosterCtrl = ($scope, info) ->
    $scope.subevent = info.subevent
    $scope.addresses = info.addresses

EventRosterCtrl.resolve = 
    info: (SubEvent, User, $route, $q) ->
        deferred = $q.defer()
        resolvedInfo = 

        SubEvent.get subevent_id: $route.current.pathParams.subevent_id, (subevent) ->
            resolvedInfo.subevent = subevent

            for participant in subevent.participants
                User.get user_id: participant.user, (user) ->
                    addresses[participant._id] = user.address

                    if addresses.length is subevent.participants.length
                        resolvedInfo.addresses = addresses
                        deferred.resolve resolvedInfo

        return deferred.promise

【讨论】:

【参考方案3】:

EventRosterCtrl 仅在子事件准备好时才被初始化,所以以下应该可以工作:

window.EventRosterCtrl = ($scope, subevent) ->
    $scope.subevent = subevent

    for participant in subevent.participants
        User.get user_id: participant.user, (user) ->
            $scope.addresses[participant._id] = user.address

EventRosterCtrl.resolve = 
    subevent: (SubEvent, $route) ->
        deferred = $q.defer()

        SubEvent.get subevent_id: $route.current.pathParams.subevent_id, (subevent) ->
            deferred.resolve subevent

        return deferred.promise

【讨论】:

这仍然会有闪烁,因为$scope.addresses 在控制器和页面渲染之后解析。

以上是关于$q defer 和 promises 以及如何使用它们在视图呈现之前为控制器加载数据的主要内容,如果未能解决你的问题,请参考以下文章

angularJS $q

如何使用 .success 和 .error 在 Angularjs 中扩展 $q 承诺

deferred对象和promise对象

angularJs 之deferred

nodeJS 中关于 promise 的使用

Q Promise 啥时候执行?