【问题标题】:q promise resolved before completed?q 承诺在完成之前解决?
【发布时间】:2015-07-18 06:55:09
【问题描述】:

我认为我可能遗漏了有关承诺如何运作的基本知识,因为我似乎从未得到我期望的结果,所以希望有人能纠正我的想法。

在这种情况下,这是一个相对容易的调用。我有一个角度工厂,其中包括从 API 获取一些数据(调用 mongodb)。 由于有一个 $http 请求(它是异步的),我将 http 调用包装在一个 $q 函数中,如果成功则返回 resolve,如果出错则返回 reject。

factory.loadLayout = function (layoutName) {
    return $q(function(resolve, reject){
        $http.get('/api/getlayout/'+layoutName)
            .success(function (data) {
                layout = data;
                console.log("Got " + layout.name);
                resolve('OK');
            })
            .error(function(data,status,headers,config){
               reject(new Error( status));
            });


    });
}

然后我有另一个函数,它依赖于第一个函数中收集的数据,称为 getButtonId,但据我所知,即使它包含在 .then 中,它似乎之前被调用过承诺已解决。

var promise = padArea.loadLayout(layoutName);
    promise.then(padArea.getButtonId('A0'));

那么我错过了什么?

== 更新 == 所以使用 q.defer 尝试同样的事情

factory.loadLayout = function (layoutName) {
    var defer = $q.defer()
        $http.get('/api/getlayout/'+layoutName)
            .success(function (data) {
                layout = data;
                console.log("Got " + layout.name);
                defer.resolve('OK');
            })
            .error(function(data,status,headers,config){
               defer.reject(new Error( status));
            });
    return defer.promise;
}

仍然没有像我预期的那样工作,并且 .then 中的函数仍然在 http 完成之前被调用。

== 更新 2 == 好的,所以让它工作了(如果我只是在 .then 内部调用工厂中的函数,它会直接调用它,但是,如果我将它包装在如下函数中,它会突然起作用。谁能解释为什么,因为在我看来,将函数调用包装在函数内部应该与调用函数没有区别。

padArea.loadLayout(layoutName).then(function(result){
    padArea.getButtonId('A0')
});

奇怪的是,只要我将第二个调用包含在(在 .then 中的那个)中,我的原始代码也可以正常工作。

【问题讨论】:

  • $q 已经返回了一个已解决的承诺。
  • 那么我如何让它等到它假设解决承诺。
  • 我无法重现:plnkr.co/edit/rlvnuTvm1b0C1fh0Oabk?p=preview but $http 无论如何都会返回一个承诺,因此您可以删除所有 $q 功能并返回$http.get 调用,功能应该是相同的。

标签: angularjs q


【解决方案1】:

只需使用$http 承诺:

factory.loadLayout = function (layoutName) {
  return $http.get('/api/getlayout/'+layoutName)
        .success(function (data) {
            layout = data;
            console.log("Got " + layout.name);
            resolve('OK');
        })
        .error(function(data,status,headers,config){
           reject(new Error( status));
        });
}

然后使用它...

factory.loadLayout(param).then(function (response) { ... });

或

我明白你在做什么。而是从$q创建一个延迟的

factory.loadLayout = function (layoutName) {
  var defer = $q.defer();
    $http.get('/api/getlayout/'+layoutName)
        .success(function (data) {
            layout = data;
            console.log("Got " + layout.name);
            defer.resolve('OK');
        })
        .error(function(data,status,headers,config){
           defer.reject(new Error( status));
        });
  return defer.promise;
}

【讨论】:

  • 这些解决方案似乎都不起作用。 $q.defer 不会抛出任何错误,但是 .then 语句中的函数在调用 http.get 之前仍然运行(尝试使用带有解析和拒绝的 $http,只是得到了这些未定义的位置。(已更新上面的例子)。
  • 第二个有效,只要它被包装在一个函数中。
  • 您必须将其包装在一个函数中,因为.then 需要一个函数作为其参数。您的其他选择是.then(padArea.getButtonId.bind(padArea, 'A0'))
  • 非常感谢 Erik 抽出时间回答我的第一个和第二个问题:)
【解决方案2】:

你也可以使用 $q.defer():

deferred = $q.defer();

$http.get('/api/getlayout/'+layoutName)
    .success(function (data) {
        layout = data;
        deferred.resolve("OK");
    })
    .error(function (data,status,headers,config){
        deferred.reject(new Error(status));
    })

return deferred.promise;

如果您不只是执行 http 请求,这可能会更通用一些,并且可以让您控制返回。

【讨论】:

    猜你喜欢
    • 2018-01-21
    • 2015-06-24
    • 2019-05-29
    • 1970-01-01
    • 2018-03-22
    • 1970-01-01
    • 1970-01-01
    • 2019-04-13
    • 2021-08-11
    相关资源
    最近更新 更多