Express 4 - 链接 res.json 和 promise.then 不起作用
Express 4 - chaining res.json with promise.then does not work
我正在开发一个使用 mysql
和 sequelize
包的 express 4 应用程序。 Sequelize ORM 使用承诺从数据库中获取数据。我正在尝试在路由器中获取数据并发送 json 响应。当我尝试使用 res.json
链接 then
承诺的回调时,我在控制台中收到一条错误消息 Unhandled rejection TypeError: Cannot read property 'get' of undefined
// This works
employeeRouter.get("/:id", function(req, res){
Employee.findById(req.params.id).then(function(data){
res.json(data);
});
});
// Replacing above code with following doesn't work
employeeRouter.get("/:id", function(req, res){
Employee.findById(req.params.id).then(res.json);
});
错误堆栈:
Unhandled rejection TypeError: Cannot read property 'get' of undefined
at json (D:\Workstation\DataPro\CountryStats\node_modules\express\lib\response.js:241:21)
at tryCatcher (D:\Workstation\DataPro\CountryStats\node_modules\bluebird\js\release\util.js:16:23)
at Promise._settlePromiseFromHandler (D:\Workstation\DataPro\CountryStats\node_modules\bluebird\js\release\promise.js:504:31)
at Promise._settlePromise (D:\Workstation\DataPro\CountryStats\node_modules\bluebird\js\release\promise.js:561:18)
at Promise._settlePromise0 (D:\Workstation\DataPro\CountryStats\node_modules\bluebird\js\release\promise.js:606:10)
at Promise._settlePromises (D:\Workstation\DataPro\CountryStats\node_modules\bluebird\js\release\promise.js:685:18)
at Async._drainQueue (D:\Workstation\DataPro\CountryStats\node_modules\bluebird\js\release\async.js:138:16)
at Async._drainQueues (D:\Workstation\DataPro\CountryStats\node_modules\bluebird\js\release\async.js:148:10)
at Immediate.Async.drainQueues [as _onImmediate] (D:\Workstation\DataPro\CountryStats\node_modules\bluebird\js\release\async.js:17:14)
at processImmediate [as _immediateCallback] (timers.js:383:17)
models/employee.js
var Sequelize = require('sequelize'),
sequelize = require('../db-connect/sequelize');
(function(){
// Use Strict Linting
'use strict';
// Define Sequalize
var Employee = sequelize.define('employee', {
empNo: { field: 'emp_no', type: Sequelize.INTEGER, primaryKey: true, autoIncrement: true },
birthDate: { field: 'birth_date', type: Sequelize.DATE },
firstName: { field: 'first_name', type: Sequelize.STRING },
lastName: { field: 'last_name', type: Sequelize.STRING },
gender: { field: 'gender', type: Sequelize.ENUM('M', 'F') },
hireDate: { field: 'hire_date', type: Sequelize.DATE },
});
// Export
module.exports = Employee;
}());
db-connect/sequelize.js
var Sequelize = require('sequelize');
(function(){
// Use Strict Linting
'use strict';
// Sequalize Connection
var sequelize = null;
// Create Sequalize Connection
if(!sequelize){
sequelize = new Sequelize('employees', 'root', '', {
host: 'localhost',
dialect: 'mysql',
define: {
timestamps: false
}
});
}
module.exports = sequelize;
}());
routes/employees.js
var express = require('express'),
Employee = require('../models/employee');
(function(app){
// Use Strict Linting
'use strict';
// Create Router
var employeeRouter = express.Router();
// Home Page
employeeRouter.get("/", function(req, res){
res.json({employees: ['all']});
});
// Get Specific Employee
employeeRouter.get("/:id", function(req, res, next){
Employee.findById(req.params.id).then(function(data){
res.json(data);
});
});
// ----------------------------------
// Export
// ----------------------------------
module.exports = employeeRouter;
}());
当您将 res.json
作为函数传递时,res
对象会丢失,因此当 json()
执行时,它没有对象,您会得到您所看到的错误。您可以使用 .bind()
:
来解决这个问题
employeeRouter.get("/:id", function(req, res){
Employee.findById(req.params.id).then(res.json.bind(res));
});
这将确保 res
对象在执行方法时与您的方法保持一致。如上使用 .bind()
本质上等同于:
employeeRouter.get("/:id", function(req, res){
Employee.findById(req.params.id).then(function(data) {
return res.json(data);
});
});
事实上,.bind()
实际上创建了一个类似于上例中的匿名函数的存根函数。它只是为你做而不是让你做。
进一步举例,假设您有两个单独的 res
对象,res1
和 res2
来自两个单独的请求。
var x = res1.json;
var y = res2.json;
console.log(x === y); // true, no association with either res1 or res2 any more
这是因为引用 res1.json
只是得到对 .json
方法的引用。它使用 res1
来获取该方法(它是从 res1 原型中获取的,但它有一个方法,它只是一个指向该方法的指针,并且不再与包含该方法的对象关联。所以,当你将 res.json
传递给一个函数时,你不会得到 res
的附件。然后当你传递 res.json
的函数去实际调用你的函数时,它会这样调用它:
var z = res.json;
z();
并且,当调用 z()
时,json
中的 this
值最终变为 undefined
并且与 res
没有任何联系目的。使用 .bind()
创建一个存根函数,将其调用为 res.json(...)
以保持与对象的连接,并确保在执行该方法时正确设置 this
。
我正在开发一个使用 mysql
和 sequelize
包的 express 4 应用程序。 Sequelize ORM 使用承诺从数据库中获取数据。我正在尝试在路由器中获取数据并发送 json 响应。当我尝试使用 res.json
链接 then
承诺的回调时,我在控制台中收到一条错误消息 Unhandled rejection TypeError: Cannot read property 'get' of undefined
// This works
employeeRouter.get("/:id", function(req, res){
Employee.findById(req.params.id).then(function(data){
res.json(data);
});
});
// Replacing above code with following doesn't work
employeeRouter.get("/:id", function(req, res){
Employee.findById(req.params.id).then(res.json);
});
错误堆栈:
Unhandled rejection TypeError: Cannot read property 'get' of undefined
at json (D:\Workstation\DataPro\CountryStats\node_modules\express\lib\response.js:241:21)
at tryCatcher (D:\Workstation\DataPro\CountryStats\node_modules\bluebird\js\release\util.js:16:23)
at Promise._settlePromiseFromHandler (D:\Workstation\DataPro\CountryStats\node_modules\bluebird\js\release\promise.js:504:31)
at Promise._settlePromise (D:\Workstation\DataPro\CountryStats\node_modules\bluebird\js\release\promise.js:561:18)
at Promise._settlePromise0 (D:\Workstation\DataPro\CountryStats\node_modules\bluebird\js\release\promise.js:606:10)
at Promise._settlePromises (D:\Workstation\DataPro\CountryStats\node_modules\bluebird\js\release\promise.js:685:18)
at Async._drainQueue (D:\Workstation\DataPro\CountryStats\node_modules\bluebird\js\release\async.js:138:16)
at Async._drainQueues (D:\Workstation\DataPro\CountryStats\node_modules\bluebird\js\release\async.js:148:10)
at Immediate.Async.drainQueues [as _onImmediate] (D:\Workstation\DataPro\CountryStats\node_modules\bluebird\js\release\async.js:17:14)
at processImmediate [as _immediateCallback] (timers.js:383:17)
models/employee.js
var Sequelize = require('sequelize'),
sequelize = require('../db-connect/sequelize');
(function(){
// Use Strict Linting
'use strict';
// Define Sequalize
var Employee = sequelize.define('employee', {
empNo: { field: 'emp_no', type: Sequelize.INTEGER, primaryKey: true, autoIncrement: true },
birthDate: { field: 'birth_date', type: Sequelize.DATE },
firstName: { field: 'first_name', type: Sequelize.STRING },
lastName: { field: 'last_name', type: Sequelize.STRING },
gender: { field: 'gender', type: Sequelize.ENUM('M', 'F') },
hireDate: { field: 'hire_date', type: Sequelize.DATE },
});
// Export
module.exports = Employee;
}());
db-connect/sequelize.js
var Sequelize = require('sequelize');
(function(){
// Use Strict Linting
'use strict';
// Sequalize Connection
var sequelize = null;
// Create Sequalize Connection
if(!sequelize){
sequelize = new Sequelize('employees', 'root', '', {
host: 'localhost',
dialect: 'mysql',
define: {
timestamps: false
}
});
}
module.exports = sequelize;
}());
routes/employees.js
var express = require('express'),
Employee = require('../models/employee');
(function(app){
// Use Strict Linting
'use strict';
// Create Router
var employeeRouter = express.Router();
// Home Page
employeeRouter.get("/", function(req, res){
res.json({employees: ['all']});
});
// Get Specific Employee
employeeRouter.get("/:id", function(req, res, next){
Employee.findById(req.params.id).then(function(data){
res.json(data);
});
});
// ----------------------------------
// Export
// ----------------------------------
module.exports = employeeRouter;
}());
当您将 res.json
作为函数传递时,res
对象会丢失,因此当 json()
执行时,它没有对象,您会得到您所看到的错误。您可以使用 .bind()
:
employeeRouter.get("/:id", function(req, res){
Employee.findById(req.params.id).then(res.json.bind(res));
});
这将确保 res
对象在执行方法时与您的方法保持一致。如上使用 .bind()
本质上等同于:
employeeRouter.get("/:id", function(req, res){
Employee.findById(req.params.id).then(function(data) {
return res.json(data);
});
});
事实上,.bind()
实际上创建了一个类似于上例中的匿名函数的存根函数。它只是为你做而不是让你做。
进一步举例,假设您有两个单独的 res
对象,res1
和 res2
来自两个单独的请求。
var x = res1.json;
var y = res2.json;
console.log(x === y); // true, no association with either res1 or res2 any more
这是因为引用 res1.json
只是得到对 .json
方法的引用。它使用 res1
来获取该方法(它是从 res1 原型中获取的,但它有一个方法,它只是一个指向该方法的指针,并且不再与包含该方法的对象关联。所以,当你将 res.json
传递给一个函数时,你不会得到 res
的附件。然后当你传递 res.json
的函数去实际调用你的函数时,它会这样调用它:
var z = res.json;
z();
并且,当调用 z()
时,json
中的 this
值最终变为 undefined
并且与 res
没有任何联系目的。使用 .bind()
创建一个存根函数,将其调用为 res.json(...)
以保持与对象的连接,并确保在执行该方法时正确设置 this
。