寻找 node.js 的 Promise bluebird 代码审查

Look for Promise bluebird code review for node.js

何时何地需要使用new Promise(Function<Function resolve, Function reject> resolver) -> Promise

我的示例代码:

userInfo.js

var Promise = require('bluebird');
var winston = require('winston');
var _ = require('lodash');
var request = Promise.promisify(require("request"));

exports.getWeather = function (data) {
    var cityName = data.userProfile.city;
    return request("http://0.0.0.0:3003/api/Weather/byCity?city=" + cityName).spread(function (res, body) {
        var result = JSON.parse(body).data;
        return _.merge(data, result);
    });
};

exports.getUserProfile = function (userId) {
    return new Promise(function (resolve, reject) {
        request("http://0.0.0.0:3003/api/UserProfile/getUserProfile?id=" + userId).spread(function (res, body) {
            var result = JSON.parse(body).data;
            resolve(result);
        });
    })

};

exports.getEvents = function (data) {
    var cityName = data.userProfile.city;
    return request("http://0.0.0.0:3003/api/Events/byCity?city=" + cityName).spread(function (res, body) {
        var result = JSON.parse(body).data;
        return _.merge(data, result);
    });
};

exports.getFashion = function (data) {
    var gender = data.userProfile.gender;
    return request("http://0.0.0.0:3003/api/Fashion/byGender?gender=" + gender).spread(function (res, body) {
        var result = JSON.parse(body).data;
        return _.merge(data, result);
    });
};

exports.displayDetail = function (data) {
    console.log(data);
};

上面的代码我尝试以 2 种方式调用 promise

getUserProfile.js

var userInfo = require('./userInfo');
    module.exports = function(){
       return userInfo.getUserProfile(3)
                    .then(userInfo.getFashion)
                    .then(userInfo.getEvents)
                    .then(userInfo.getWeather)
                    .then(userInfo.displayDetail)
                    .catch(function (e) {
                        console.log('Error:');
                        console.error(e.stack)
                    })
                    .finally(function () {
                        console.log('done');
                    });

    }

第二种方式:

getUserInformation.js

var userInfo = require('./userInfo');
     module.exports = function () {
        return new Promise(function (resolve, reject) {

             resolve(3);
        })
            .then(userInfo.getUserProfile)
                .then(userInfo.getFashion)
                .then(userInfo.getEvents)
                .then(userInfo.getWeather)
                .then(userInfo.displayDetail)
                .catch(function (e) {
                    console.log('Error:');
                    console.error(e.stack)
                })
                .finally(function () {
                    console.log('done');
                });
    };

getDetails.js

var userInfo = require('./getUserInformation');
    userInfo()
    .then(function(){
            console.log('getDetails done')
        })
        .catch(function (e) {
            console.log('Error:');
            console.error(e.stack)
        })
        .finally(function () {
            console.log('done');
        });

请告诉我有什么区别,使用这些方式有什么问题吗?

第一种方式更具可读性,并且像第二种方式一样以 returns 常量的承诺开始链没有任何好处。

他们都有效地做同样的事情,有一个警告:在你的第二个例子中(用承诺启动链),getUserProfile 调用将在下一个滴答时 运行 (类似如果你把它扔在 setTimeout 0) 而不是原子地。

exports.getUserProfile = function (userId) {
    return new Promise(function (resolve, reject) {
        request("http://0.0.0.0:3003/api/UserProfile/getUserProfile?id=" + userId).spread(function (res, body) {
            var result = JSON.parse(body).data;
            resolve(result);
        });
    })
};

Please don't do this。只是 return 来自回调,return 由 then 创建的承诺,就像您在其他三种方法中所做的那样。

return userInfo.getUserProfile(3)
.then(…)

vs.

return new Promise(function (resolve, reject) {
    resolve(3);
})
.then(userInfo.getUserProfile)
.then(…)

好吧,第一个更具可读性和简洁性。除了 getUserProfile 确实同步抛出的情况外,它们几乎是等价的,无论如何它都不应该。同样在第一种情况下 getUserProfile 作为方法 on userInfo 被调用,而在第二种情况下它只是一个回调函数, this 在调用会有所不同。

通过使用 Promise.resolve 而不是 new Promise 构造函数,可以极大地简化第二个模式:

return Promise.resolve(3)
.then(userInfo.getUserProfile)
.then(…)

这完全没问题,并且与链的其余部分更好地对齐。说到这,……

.then(userInfo.getFashion)
.then(userInfo.getEvents)
.then(userInfo.getWeather)

where each of the functions returns a promise that resolves with additional data merged into its argument

并不是解决这个问题的最佳方法。是的,它确保这三个函数在彼此之后被调用,并且。但是,在您的情况下,您将 request 调用与 API 的参数提取和结果合并混合在同一个函数中;通过关注点分离,您不应该这样做。而是让函数变得纯粹

exports.… = function (arg) {
    return request("http://0.0.0.0:3003/api/…?…=" + arg).spread(function (res, body) {
        return JSON.parse(body).data;
    });
};

现在您可以分别组合它们 - 不仅可以按顺序组合,还可以并行组合:

userInfo.getUserProfile(3)
.then(function(data) {
    var p = data.userProfile;
    return Promise.prop({
         userProfile: 0,
         fashion: userInfo.getFashion(p.gender), // `\
         events: userInfo.getEvents(p.city),     //   }=> execute requests in parallel
         weather: userInfo.getWeather(p.city)    // ./
    });
})
.then(userInfo.displayDetail)
.catch(function (e) {
     console.error('Error:', e.stack)
});