我正在尝试构建一个简单的插件,以便从Mongo获取数据到一个对象,我可以在渲染时迭代它。完整代码在我的project中,但其实质是尝试模拟feedr示例失败。我知道mongoose的东西正在运行,因为控制台日志工作,但获取发送到docpad对象的内容正在打败我
class mongoPlugin extends BasePlugin
name: 'mongo'
# Fetch list of Gigs
getGigsData: (opts) ->
mongoose.connect ('mongodb://localhost/test')
db = mongoose.connection;
db.on 'error', console.error.bind(console, 'connection error:')
db.once 'open', () ->
gigsSchema = mongoose.Schema {
date : String,
location : String
}
Gigs = mongoose.model 'Gigs', gigsSchema
Gigs.find {}, (err, gigs) ->
mongoose.connection.close()
if err then console.error "db error"
else
console.dir gigs
opts["getGigsData"] = gigs
opts.templateData["getGigsData"] = gigs
return gigs
extendTemplateData: (opts) ->
opts.templateData["getGigsData"] = @getGigsData()
使用node-inspector并通过编辑docpad.coffee触发重新生成,我可以看到opts有一个字段templateData,但是它是空的,与docpad.templateData非常不同,所以我选择了错误的对象插件。我可以看到其他人做了一个在{}中放置名字的技巧,但我不知道那是什么。
在完成插件代码之后,我看到我的数据库数据成为了promise的参数,所以也许这就是它应该与docpad.config.templateData重新集成的地方,但实际上似乎没有发生
答案 0 :(得分:0)
所以这里的主要问题是我们在同步函数内部执行异步函数getGetsData
,即模板引擎。这简单,这是不可能的,因为模板引擎将继续并做它的事情,而同步的东西发生在后台。这只是编写node.js /异步代码的一个问题。
修复此问题非常容易。
opts.templateData["getGigsData"] = @getGigsData()
调用getGigsData
而没有通过opts
,因此当getGigsData
尝试并使用opts时,它不能,因此会抛出@getGigsData(opts)
一个错误。解决此问题的方法是opts.templateData["getGigsData"] = @getGigsData(opts)
@getGigsData(opts)
将db.once
的返回值分配给模板数据,但是,结果是return gigs
调用的结果,因为这将是在那个范围内返回。当您执行(err, gigs) ->
时,这实际上是Gigs.find
调用getGigsData
回调的返回值,而不是getGigsData
的返回值。这都是关于范围的。
由于数据库内容是异步的,我们需要使extendTemplateData: (opts) ->
异步。为此,我们将extendTemplateData: (opts,next) ->
更改为opts.templateData["getGigsData"] = @getGigsData()
以使其异步,并将return @getGigsData(opts,next)
更改为getGigsData: (opts) ->
现在我们有了事件并调用异步。我们现在需要让getGigsData的定义支持它。因此,我们将getGigsData: (opts,next) ->
更改为next
以接受我们在第3步中定义的完成回调(return gigs
)。我们将要做的是,我们将在下一个地方调用{{ 1}},所以我们将return gigs
更改为return next()
现在应该可以了。但是,只需稍加清理,我们就可以通过将if err then console.error "db error"
更改为return next(err) if err
来更好地进行错误处理。您需要修复缩进,因为我们需要移除else
块。
考虑到这一切,并且应用了更多的清洁工具,你最终会得到这个:
class mongoPlugin extends BasePlugin
name: 'mongo'
config:
hostname: 'mongodb://localhost/test'
# Fetch list of Gigs
getGigsData: (opts={}, next) ->
config = @getConfig()
docpad = @docpad
mongoose.connect(config.hostname)
db = mongoose.connection
db.on 'error', (err) ->
docpad.error(err) # you may want to change this to `return next(err)`
db.once 'open', ->
gigsSchema = mongoose.Schema {
date: String,
location: String
}
Gigs = mongoose.model('Gigs', gigsSchema)
Gigs.find {}, (err, gigs) ->
mongoose.connection.close()
return next(err) if err
return next(null, gigs)
# Chain
@
extendTemplateData: (opts,next) ->
@getGigsData null, (err, gigs) ->
return next(err) if err
opts.templateData.gigs = gigs
# Chain
@