我有以下代码注册了一系列socketio命名空间。逻辑的PArts依赖于数据库调用(通过sequelize),因此我需要使用promises。当所有构造函数调用逻辑完成时,我希望complete
promise得到解决。我的问题是complete
承诺在emitInitialPackage()
函数解决之前解析。
export class demoClass {
public complete: Promise<boolean>;
server: any;
constructor(io: any) {
this.server = io;
this.complete = Promise.resolve(db.Line.findAll()).then(lines => {
// do some mapping to generate routes and cells
this.registerEndPoints(routes, [], cells);
}).catch(err => console.log(err))
}
registerEndPoints(routes: Array<string>, nsps: Array<any>, cells: Array<string>) {
for (let i = 0; i < routes.length; i++) {
nsps.push(this.server.of('/api/testNamespace/' + routes[i]));
let that = this;
const nsp = nsps[i];
nsp.on('connection', function (socket) {
that.emitInitialPackage(nsps[i], routes[i], cells[i]);
});
}
}
emitInitialPackage(nsp: any, name: string, cell: any) {
return db.Line.find({/* Some sequelize params*/}).then(results => {
nsp.emit('value', results);
}).catch(err => console.log(err));
}
}
如何在emitInitialPackage
结算之前确保complete
已完成?
答案 0 :(得分:1)
要等待registerEndPoints
中的所有操作完成,此方法应返回Promise
操作后可以链接的db.Line.findAll()
:
export class demoClass {
public complete: Promise<boolean>;
server: any;
constructor(io: any) {
this.server = io;
this.complete = Promise.resolve(db.Line.findAll()).then(lines => {
// return promise created by registerEndPoints method
return this.registerEndPoints(routes, [], cells);
}).catch(err => console.log(err))
}
registerEndPoints(routes: Array<string>, nsps: Array<any>, cells: Array<string>) {
const endPointPromises = routes.map((route, index) => {
// for each endpoint create Promise that gets resolved
// only when all work for endpoint is done
return new Promise((resolve) => {
nsps.push(this.server.of('/api/testNamespace/' + route));
const nsp = nsps[index];
nsp.on('connection', (socket) => {
// resolve promise when emitInitialPackage did its part of the work
this.emitInitialPackage(nsps[index], route, cells[index]).then(resolve);
});
});
});
return Promise.all(endPointPromises);
}
emitInitialPackage(nsp: any, name: string, cell: any) {
return db.Line.find({/* Some sequelize params*/}).then(results => {
nsp.emit('value', results);
}).catch(err => console.log(err));
}
}
答案 1 :(得分:0)
有几个问题需要解决:
this.registerEndPoints
返回的承诺,因此this.complete
只会在该承诺结算时解决; []
参数传递的nsps
参数没有用作参数,因此您也可以一起跳过该参数; .on('connection', ...)
函数应该被包装以返回一个promise; for
循环应该创建这些承诺,然后将它们传递给Promise.all
以获得最终结果。 map
可以用于此目的; routes
,cells
和nsps
),它们具有相同索引的相关数据。一个更好的结构是你有一个对象数组,其中每个对象有三个属性:(route
,cell
和nsp
); 以下是一些未经测试的代码:
constructor(io: any) {
this.server = io;
// *** bluebird is promises/A+ compliant, no need to convert it:
this.complete = db.Line.findAll().then(lines => {
// do some mapping to generate routes and cells
// *** return the promise!
// *** removed [] argument: not needed
return this.registerEndPoints(routes, cells);
}).catch(err => console.log(err))
}
// *** Remove the nsps parameter
registerEndPoints(routes: Array<string>, cells: Array<string>) {
// *** Create a promise-version of the `.on('connection', ...)` method
function nspConnect(nsp) {
return new Promise( resolve => nsp.on('connection', resolve) );
}
let that = this;
// *** Combine each route, cell, and nsp in one object, and put in array:
const data = routes.map( (route, i) => ({
nsp: that.server.of('/api/testNamespace/' + route),
route,
cell: cells[i]
}) );
// *** Map the array of objects to promises
const proms = data.map( ({nsp, route, cell}) =>
nspConnect(nsp).then(that.emitInitialPackage.bind(that, nsp, route, cell)) );
// *** Return a promise that resolves when all these have resolved
return Promise.all(proms);
}
要进行一些调试,您可以将nspConnect
功能扩展为:
function nspConnect(nsp) {
return new Promise( resolve => {
console.log('creating promise');
return nsp.on('connection', socket => {
console.log('resolving');
resolve();
});
});
}