nodejs mssql并承诺混淆

我是非常新的承诺在JavaScript中,所以这个问题是帮助我弄清楚为什么我得到一个错误(以奇怪的顺序)使用承诺。 最重要的是,我正在忙于使用ms-sql回购,sinonjs和第一次restify,所以也没有帮助

这个问题和我之前问过的有关

在上面的问题中,我需要在@robertklep的帮助下完成我成功完成的SQL DB。 然而,作为一个完整的检查,我想检查终点是否仍然像以前那样返回我期望的数据,所以我解开了残局。 现在我收到以下错误,我不知道为什么:

[错误:发送后无法设置标题。]

testing:

'use strict'; var expect = require('chai').expect, request = require('supertest'), chance = require('chance').Chance(), server = require('../server'), sinon = require('sinon'), select = require('../../helpers/data_access/select'), read_file = require('../../helpers/read_file'); describe("/account_types", function () { // before(function (done) { // sinon // .stub(select, "query_list") // .returns([{id: "test"}]); // // sinon // .stub(select, "query_single") // .returns({id: "test"}); // // sinon // .stub(read_file, "get_file_contents") // .returns("Some content to get excited about"); // // done(); // }); // // after(function (done) { // select // .query_list // .restore(); // select // .query_single // .restore(); // read_file // .get_file_contents // .restore(); // // done(); // }); it('GET 200 List', function (done) { request(server.baseURL) .get('/api/v1/account_types') .set('Accept', 'application/json') .expect('Content-Type', 'application/json') .expect(200) .end(function (err, res) { /* istanbul ignore if */ if (err) return done(err); expect(res.body).to.not.be.null; expect(res.body).to.not.be.undefined; expect(res.body).to.be.an('Array'); expect(res.body.length).to.be.above(0); //expect(select.query_list).to.have.been.calledOnce; return done(); }); }); it('GET 200 Single', function (done) { //var param = chance.random(); request(server.baseURL) .get('/api/v1/account_type/' + 1) .set('Accept', 'application/json') .expect('Content-Type', 'application/json') .expect(200) .end(function (err, res) { /* istanbul ignore if */ if (err) return done(err); expect(res.body).to.not.be.null; expect(res.body).to.not.be.undefined; expect(res.body).to.be.an('Object'); expect(res.body.toString().length).to.be.above(0); return done(); }); }); it('POST 200 Single', function (done) { var param = chance.random(); request(server.baseURL) .post('/api/v1/account_type') .set('Accept', 'application/json') .send({id: param}) .expect('Content-Type', 'application/json') .expect(200) .end(function (err, res) { /* istanbul ignore if */ if (err) return done(err); expect(res.body).to.be.an('object'); expect(res.body).to.include.keys('result'); expect(res.body.result).to.equal('post account_type : ' + param.toString()); return done(); }); }); it('PUT 200 Single', function (done) { var param = chance.random(); request(server.baseURL) .put('/api/v1/account_type') .set('Accept', 'application/json') .send({id: param}) .expect('Content-Type', 'application/json') .expect(200) .end(function (err, res) { /* istanbul ignore if */ if (err) return done(err); expect(res.body).to.be.an('object'); expect(res.body).to.include.keys('result'); expect(res.body.result).to.equal('put account_type : ' + param.toString()); return done(); }); }); it('DELETE 200 Single', function (done) { var param = chance.random(); request(server.baseURL) .delete('/api/v1/account_type/' + param) .set('Accept', 'application/json') .expect('Content-Type', 'application/json') .expect(200) .end(function (err, res) { /* istanbul ignore if */ if (err) return done(err); expect(res.body).to.be.an('object'); expect(res.body).to.include.keys('result'); expect(res.body.result).to.equal('delete account_type : ' + param.toString()); return done(); }); }); }); 

终点:

 var select = require('../helpers/data_access/select'), read_file = require('../helpers/read_file'), format = require('string-format'); const db_config_name = 'db.goaml'; module.exports = function (server) { server.get('/api/v1/account_types', function (req, res, next) { var query = read_file.get_file_contents('path to query'); select.query_list(db_config_name, query, function (err, records) { console.log('test 1'); if (err != null) { return next(err); } res.send(records); //return next(); <-- EDIT: Removed as per Mike Perrenoud answer }); //return next(); <-- EDIT: Removed as per Mike Perrenoud answer }); server.get('/api/v1/account_type/:id', function (req, res, next) { var query = format(read_file.get_file_contents('path to query'), req.params.id); select.query_single(db_config_name, query, function (err, records) { console.log('test 2'); if (err != null) { return next(err); } res.send(records[0]); //return next(); <-- EDIT: Removed as per Mike Perrenoud answer }); //return next(); <-- EDIT: Removed as per Mike Perrenoud answer }); server.post('/api/v1/account_type', function (req, res, next) { res.send({'result': 'post account_type : ' + req.body.id}); return next(); }); server.put('/api/v1/account_type', function (req, res, next) { res.send({'result': 'put account_type : ' + req.body.id}); return next(); }); server.del('/api/v1/account_type/:id', function (req, res, next) { res.send({'result': 'delete account_type : ' + req.params.id}); return next(); }); }; 

select.js:

 var sql = require('mssql'), config = require('./configs/config'); module.exports = { query_list: function (config_name, sql_query, callback) { return query(config_name, sql_query, true, callback); }, query_single: function (config_name, sql_query, callback) { return query(config_name, sql_query, false, callback); } }; function query(config_name, sql_query, isList, callback) { var db_config = config.get(config_name), connection = new sql.Connection(db_config); connection.connect(function () { new sql.Request(connection) .query(sql_query) .then(function (records) { console.log('test 3'); callback(null, isList ? records : records[0]); connection.close(); }) .catch(function (err) { console.log('test 4'); console.log(err); callback(err, null); }); }); // EDIT for answer: // This catch is not allowed. IE the connection isn't a promise. Thus // when the code responded with something valid, it reached this part // after that and realised this is an illegal statement. As a result // it throws an error after the res.send was already hit and showing the // initial error I reported. // .catch(function (err) { // console.log('test 5'); // callback(err, null); // }); } 

当我运行gulp任务来testing上面提到的代码时,我得到以下输出:

 C:\Code\JS\general_admin_service>gulp test [16:12:47] Using gulpfile C:\Code\JS\general_admin_service\gulpfile.js [16:12:47] Starting 'test'... [16:12:47] Finished 'test' after 62 ms /account_types 1) GET 200 List 2) GET 200 Single test 3 test 1 test 4 [Error: Can't set headers after they are sent.] test 1 √ POST 200 Single test 3 test 2 test 4 [Error: Can't remove headers after they are sent.] test 2 √ PUT 200 Single √ DELETE 200 Single 3 passing (400ms) 2 failing 1) /account_types GET 200 List: Error: expected 200 "OK", got 500 "Internal Server Error" at Test._assertStatus (C:\Code\JS\general_admin_service\node_modules\supertest\lib\test.js:232:12) at Test._assertFunction (C:\Code\JS\general_admin_service\node_modules\supertest\lib\test.js:247:11) at Test.assert (C:\Code\JS\general_admin_service\node_modules\supertest\lib\test.js:148:18) at assert (C:\Code\JS\general_admin_service\node_modules\supertest\lib\test.js:127:12) at C:\Code\JS\general_admin_service\node_modules\supertest\lib\test.js:124:5 at Test.Request.callback (C:\Code\JS\general_admin_service\node_modules\superagent\lib\node\index.js:831:3) at Stream.<anonymous> (C:\Code\JS\general_admin_service\node_modules\superagent\lib\node\index.js:1049:12) at Unzip.<anonymous> (C:\Code\JS\general_admin_service\node_modules\superagent\lib\node\utils.js:108:12) 2) /account_types GET 200 Single: Error: expected 200 "OK", got 500 "Internal Server Error" at Test._assertStatus (C:\Code\JS\general_admin_service\node_modules\supertest\lib\test.js:232:12) at Test._assertFunction (C:\Code\JS\general_admin_service\node_modules\supertest\lib\test.js:247:11) at Test.assert (C:\Code\JS\general_admin_service\node_modules\supertest\lib\test.js:148:18) at assert (C:\Code\JS\general_admin_service\node_modules\supertest\lib\test.js:127:12) at C:\Code\JS\general_admin_service\node_modules\supertest\lib\test.js:124:5 at Test.Request.callback (C:\Code\JS\general_admin_service\node_modules\superagent\lib\node\index.js:831:3) at Stream.<anonymous> (C:\Code\JS\general_admin_service\node_modules\superagent\lib\node\index.js:1049:12) at Unzip.<anonymous> (C:\Code\JS\general_admin_service\node_modules\superagent\lib\node\utils.js:108:12) events.js:142 throw er; // Unhandled 'error' event ^ Error: 2 tests failed. 

让我感到困惑的是,如果我看一下console.log's输出,很明显代码会进入sql.request的“成功”, then调用callbacksql.request 。 我可以确认,如果我添加一个console.log来检查logging参数的值,实际上有数据回来。

在这一点上, res.send get命中,但是在sql.querycatch块中捕获到一个错误,在这里就是混淆的地方:

如果有一个成功的回报,为什么渔获?

哪部分代码正在响应testing。 IE浏览器为什么设置后改变了标题? ( next(err)也许有什么关系呢?)

如前所述,这个问题与我以前的问题有很大关系。 为了满足我的unit testing,我必须修改代码。 但是,我觉得有必要做一个健全的检查,确保数据仍然按照预期的方式返回,在这一点上,我认为ms-sql使用的Promise框架阻碍了将值返回给testing。 (我不是在质疑Promise框架的价值)。

我希望有人知道我做错了什么。

编辑:

所以我对这是怎么回事有点困惑。 就像这样的代码,如果我取消注释before部分的testing,testing失败,看起来它与callback有关。

如果我完全删除callback,并返回在sql.Request然后throw err ,然后我的testing通过。

但是,如果我直接testing不存在残留,则此设置不会返回值。

这是因为你正在执行return next(); 从SQL Servercallback完成之前。 造成这个问题的原因是因为虽然它本质上是asynchronous的,但是您正在执行一组同步的操作。

发生什么事是res.send(records); 失败,因为next()已经被调用,并且服务器已经返回了200

最后,你不需要return next(); 之后res.send(records); 因为res.send(records); 结束进程并返回响应。