在解析之前返回的延迟对象

时间:2015-03-01 05:02:43

标签: javascript node.js promise deferred when-js

我正在使用带有Node js的when库。我创建了一个deffered对象,将解析放在一个封装的Mongoose findOne()函数中,并在外面返回promise。但似乎我的承诺总是在检索数据之前返回。

User.prototype.getProfile = function(criteria) {
    var deferred = when.defer();
    var options = {
        criteria: criteria,
        select: 'name id email'
    };
    this.User.load(options, function(err, data) {
        if (data) {
            this.name = data.name;
            this.email = data.email;
            this.id = data.id;
        } else {
            return false;
        }
        console.log(data);
        deferred.resolve();
    });
    console.log('returning promise');
    return deferred.promise;
};

呼叫者

User.getProfile(req.query).then(
        function success(data) {
            res.send('Hello ' + User.name);// Hello ''
        }
    );

'returning promise'

之前输出data

3 个答案:

答案 0 :(得分:4)

是的,promise将返回给调用者而不是数据,这就是我们如何利用异步函数。这是处理异步调用的常见操作序列,

  1. 拨打异步电话。

  2. Promise返回给来电者。

  3. 此时,来电者不必等待结果。它可以简单地定义一个then函数,它知道数据准备好后要做什么,然后继续下一个任务。

  4. 稍后的时间点,当您从异步调用中获得结果时,解析(或拒绝,如果失败)承诺。

  5. 使用异步调用的结果执行then对象上的Promise函数。

  6. 所以,你的代码必须稍微修改一下,比如

    User.prototype.getProfile = function(criteria) {
        var deferred = when.defer();
        var options = {
            criteria: criteria,
            select: 'name id email'
        };
        this.User.load(options, function(err, data) {
            if (err) {
                // Reject, if there is an error
                deferred.reject(err);
            } else {
                // Resolve it with actual data
                deferred.resolve(data);
            }
        });
        return deferred.promise;
    };
    

    然后你的来电者会做这样的事情

    userObject.getProfile()
        .then(function(profileObject) {
            console.log(profileObject);
            // Do something with the retrieved `profileObject`
        })
        .catch(function(err) {
            console.err("Failed to get Profile", err);
        });
    
    // Do something else here, as you don't have to wait for the data
    

    在这里,调用者只需调用getProfile并附加一个函数,该函数说明如何处理返回的数据并继续。


    编辑如果您想要更新相同的对象,那么您可以简单地使用类似的代码,但是您需要在其他变量中保留this,因为{{{}的绑定1}}在运行时发生。

    this

答案 1 :(得分:2)

promises的工作原理。

由于您的异步任务需要一些时间,并且JavaScript是单线程语言,因此您不希望阻止代码并等待异步操作自行完成 - 否则没人会使用JavaScript !!

那你做什么?您创建了promise并继续使用代码 您向promise添加回调,并在解析承诺时调用回调。

没有使用when库但您想要做的是这样的:

User.prototype.getProfile = function(criteria){
    var deferred = when.defer();
    var options = {
        criteria : criteria,
        select : 'name id email'
    };
    this.User.load(options, function(err, data) {
        if (data) {
            this.name = data.name;
            this.email = data.email;
            this.id = data.id;
            console.log(data);
             // the callback will invoke after the deferred object is resolved.
             deferred.promise.then(function(o){ console.log('resolved!!!'); });
             deferred.resolve(data);
        }else{
            deferred.reject('something bad occured');
            return false;
        }

    });

    return deferred.promise;
};

答案 2 :(得分:0)

尽量避免使用延迟模式(see here)。

when.js支持The Revealing Constructor Pattern,这也会带来更易读的代码。

User.prototype.getProfile = function(criteria) {

    var self = this;
    var options = {
        criteria: criteria,
        select: 'name id email'
    };

    return when.promise(function(resolve, reject) {
        self.User.load(options, function(err, data) {

            if (err) {
                reject(err);
            }

            self.name = data.name;
            self.email = data.email;
            self.id = data.id;

            resolve(); // or resolve(data)
        });
    });
};

下一步

userObject.getProfile()
.then(function() {
    // data loaded
})
.catch(function(err) {
    // something went wrong, process the error
});