q 承诺在完成之前解决?

q promise resolved before completed?

我想我可能遗漏了一些关于 promise 如何运作的基本知识,因为我似乎从来没有得到我期望的结果,所以希望有人能纠正我的想法。

在这种情况下,这是一个相对容易的调用。我有一个 angular 工厂,除其他外,它从 API(调用 mongodb)获取一些数据。 由于有一个 $http 请求(异步),我将 http 调用包装在一个 $q 函数中,如果成功,该函数应该 return 一个 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 中的那个)中,我的原始代码也能正常工作。

只需使用$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():

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 请求,这可能会更通用一些,并且让您控制 return。