2016-02-04 64 views
0

我很確定我的問題與使用Koa或SQLite3沒有直接關係,但更多的是對JavaScript的一般使用。等到數據庫查詢完成

我有以下server.js

var http = require('http'); 
var koa = require('koa'); 
var route = require('koa-route'); 
var app = koa(); 
var sqlite3 = require('sqlite3').verbose(); 
var dbFile = 'coc.db'; 
var db = new sqlite3.Database(dbFile); 

var members = []; 

var printMembers = function(name){ 

     db.each(query, [name], function(err, row){ 
      members.push(row); 
     }); 

    return members; 

} 


app.use(route.get('/', index)); 


function *index() { 

    this.body = printMembers("name"); 

} 


app.listen(8008); 
console.log('Koa listening on port 8008'); 

當我啓動服務器,並參觀localhost:8008首次,我只得到一個空的Array([])作爲響應。這是變量members的內容。當我重新加載時,我按預期得到了我的SQLite查詢結果。

原因可能是因爲我的查詢比腳本執行時間要長。當然,第二次填寫的是members。但與第一次查詢的結果!
另外var members = []應在printMembers內聲明。

在我看來,我需要確保一點,index()正在等待db.each()完成。但我怎麼能做到這一點?

回答

3

由於Koa 1.x的核心抽象是在路由中使用控制流 的生成器,因此您必須使用yield等待某件事完成。

興亞使用https://github.com/tj/co引擎蓋下,所以當試圖 互操作與沒有爲興亞建庫,作爲興亞開發人員,你 基本上只需要弄清楚如何修改/包異步庫 使你可以yield他們在你的路線。

你可以基本yield生成器和承諾。

這個工作最常用的工具是用 包裝一個函數Promise。在創建Promise(new Promise(fn))時,您必須將 函數fn傳遞給函數和reject

您經常可以找到Co特定的庫,其中某人已經以允許您的yield其功能/方法的方式包裝了一個受歡迎的 庫。

例如,檢查出https://www.npmjs.com/package/co-sqlite3。 (我不知道它有多好,但幸運的是,如果事實證明它不好,很容易自動換行)

或者,有些庫可以採用回調式模塊(即大多數Node模塊) 幷包裝它,使其返回承諾,您可以yield

例如,bluebird有一個promisifyAll函數可以做到這一點,儘管說實話我從來沒有用過藍鳥。

// (Untested) 
var Promise = require('bluebird'); 
var sqlite3 = require('sqlite3').verbose(); 
var db = Promise.promisifyAll(new sqlite3.Database(':memory:')); 

function* printMembers(name) { 
    var query = '...'; 
    return yield db.allAsync(query, [name]); 
} 

function* index() { 
    // promisifyAll adds an {fnName}Async version of all the functions 
    // to the module you call it on, so now we can call `allAsync`. 

    var members = yield db.allAsync(query, ['name']); 
    // or 
    var members = yield printMembers('name'); 

    this.body = members; 
} 

但我給你一些承諾,包裝的例子,因爲它是這樣一個基本 工具,在你的包。

在這裏我重寫printMembers函數返回一個承諾,你 然後yield從您的路徑:

var printMembers = function(name) { 
    var query = '...'; 
    return new Promise(function(resolve, reject) { 
    var rows = []; 
    db.each(query, [name], function(err, row){ 
     if (err) return reject(err); 
     rows.push(row); 
    }); 
    resolve(rows); 
    }); 
} 

雖然注意到sqlite3的有Database#all 功能,所有的行一次返回到你這麼您不必手動創建數組:

var printMembers = function(name) { 
    var query = '...'; 
    return new Promise(function(resolve, reject) { 
    db.all(query, [name], function(err, rows){ 
     if (err) return reject(err); 
     resolve(rows); 
    }); 
    }); 
} 

現在,這裏是你的路線是什麼樣子:

function *index() { 
    var members = yield printMembers('name'); 
    this.body = members; 
} 

如果承諾打那reject(err)路徑,然後承諾放於拒絕 狀態,將引發你可以try/catch語句,如果你想在這裏你產生 承諾的錯誤。

如果諾言命中resolve(members)路徑,那麼這就是產生 並分配給members變量。

+0

哇,這是一個完美的答案! a)現在我知道JS的哪塊lego磚丟失了,b)您給出了多種解決方案,c)您甚至給出了一個工作示例。非常感謝!當你遇到問題時,它很難,但不知道要搜索什麼! – cvoigt