寻找node.js的承诺蓝鸟代码审查

Look for Promise bluebird code review for node.js

本文关键字:蓝鸟 代码审查 承诺 node js 寻找      更新时间:2023-09-26

何时何地需要使用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');
                    });
    }

方式2:

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');
        });

请让我知道使用这些方式有什么不同,有没有什么问题?

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);
        });
    })
};

请不要这样做。从回调中取出return,并返回由then创建的承诺,就像您在其他三个方法中所做的那样。

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

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

嗯,第一个更容易读,更简洁。它们几乎是等价的,除了getUserProfile确实同步抛出,这本来就不应该。同样在第一种情况下,getUserProfile作为 userInfo的方法被调用,而在第二种情况下,它只是一个回调函数,调用中的this将是不同的。

第二个模式可以通过使用Promise.resolve而不是new Promise构造函数来极大地简化:
return Promise.resolve(3)
.then(userInfo.getUserProfile)
.then(…)

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

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

,其中每个函数返回一个承诺,该承诺解析为附加数据合并到参数

并不是解决这个问题的最佳方法。是的,它确保了这三个函数是依次调用的,并且在这种情况下是一种可接受的模式。然而,在你的情况下,你混合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)
});

第一种方法更具可读性,并且与第二种方法一样,使用返回常量的承诺开始链没有任何好处。

它们都有效地做同样的事情,但有一点需要注意:在第二个示例中(用Promise启动链),getUserProfile调用将在下一个tick上运行(类似于在setTimeout 0中抛出它),而不是自动运行。