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