2014-02-14 4 views
0

Я пытаюсь создать простой плагин, чтобы получить данные от Mongo в объект, над которым я могу выполнять итерацию при рендеринге. Полный код находится в моем project, но суть его - неудачная попытка подражать примеру feedr. Я знаю, что мангуст материал работает в бревенчатых консоль работает, но получить содержимое, отправленное на объект DocPad побеждает меняDocpad: using extendTemplateData через обратный вызов mongoose

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() 

Использование узла-инспектора и запуска регенерации путем редактирования docpad.coffee, я могу видеть, что opts имеет поле templateData, но он пуст и сильно отличается от docpad.templateData, поэтому я собираю неправильный объект в плагине. Я вижу, что другие делали трюк по размещению имени в {}, но я не знаю, что это делает.

После завершения кода плагина я вижу, что мои данные базы данных становится аргументом обещания, поэтому, возможно, что там предполагается реинтеграция с docpad.config.templateData, но это, кажется, не происходит на практике

ответ

0

Итак, основная проблема заключается в том, что у нас есть асинхронная функция getGetsData, выполняемая внутри синхронной функции, вашего шаблонизатора. Это просто, не возможно, поскольку механизм шаблонов будет продолжаться и делать свое дело, в то время как синхронный материал происходит в фоновом режиме. Это просто проблема с простое написание node.js/асинхронного кода в целом.

Исправления для этого довольно просты.

  1. opts.templateData["getGigsData"] = @getGigsData() звонки getGigsData без прохождения через opts, так что, когда getGigsData пытается и использует Opts, он не может, так что бы бросить ошибку. Исправить это сделать @getGigsData(opts)

  2. opts.templateData["getGigsData"] = @getGigsData(opts) присваивает возвращаемое значение @getGigsData(opts) к данным шаблона, однако, результатом этого является результатом db.once вызова, так это то, что будет возвращено в этой области. Когда вы делаете return gigs, это фактически возвращаемое значение для обратного вызова (err, gigs) -> по вызову Gigs.find, а не возвращаемого значения для getGigsData. Все дело в области.

  3. Поскольку материал базы данных асинхронен, нам необходимо сделать асинхронным getGigsData. Чтобы сделать это, мы изменим extendTemplateData: (opts) -> к extendTemplateData: (opts,next) ->, чтобы сделать его асинхронно, и изменить opts.templateData["getGigsData"] = @getGigsData() просто return @getGigsData(opts,next)

  4. Теперь, когда у нас есть событие и называют асинхронным. Теперь нам нужно, чтобы определение getGigsData поддерживало его. Так позволяет изменить getGigsData: (opts) -> к getGigsData: (opts,next) -> принять в завершение обратного вызова (next), которые мы определили в шаге 3. А что мы будем делать, что мы будем называть рядом, где мы имеем return gigs, так что позволяет изменить return gigs к return next()

  5. It должен теперь работать. Но, как немного очистки, мы можем улучшить обработку ошибок, изменив 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 
     @ 
+0

Это замечательно. Для этого кода нужен еще один последний следующий(). –

Смежные вопросы