2016-09-01 19 views
3
var express = require('express'); 
var GoogleUrl = require('google-url'); 
var favicon = require('serve-favicon'); 
var mongo = require('mongodb').MongoClient; 
var app = express(); 
var db; 
var googleUrl = new GoogleUrl({key: 'AIzaSyB5i1sdnt6HwzrvsPTBu0FbPiUZrM_BCsk'}); 
var PORT = 8080; 

mongo.connect('mongodb://localhost:27017/url-shortener', function(err, newDb){ 
    if(err){ 
     throw new Error('Database failed to connect'); 
    } else{ 
     console.log('Successfully connected to MongoDB on port 27017'); 
    } 
    db=newDb; 
    db.createCollection('sites', { 
     autoIndexID: true 
    }); 
}); 

app.use(favicon(__dirname+'/public/favicon.ico')); 

app.get('/new/*', function(req, res){ 
    var doc; 
    console.log('This is the url: '+req.params[0]); 
    googleUrl.shorten(req.params[0], function(err, shortUrl){ 
     if(err){ 
      console.log(err); 
     }else{ 
      console.log(shortUrl); 
     } 
     doc = check_db(req.params[0], shortUrl, db); 
    }); 

以下のres.json文が実行され、他の関数が値を返す前に未定義の変数を返します。ノードjsで非同期コールバックを作成する方法は?

res.json(doc); 
}); 


app.listen(process.env.PORT, function(){ 
    console.log('Express listening on: '+PORT); 
}); 

function check_db(longUrl, shortUrl, db){ 
    db.collection('sites').findOne({ 
     'longUrl': longUrl, 
     'shortUrl': shortUrl 
    }, function(err, doc){ 
     if(err){ 
      console.log(err); 
     }if(doc){ 

res.json文は、以下の文を実行して値を返す前に実行されます。 GETリクエストの下に定義された関数がres.jsonは、未定義の変数を返し、その結果、実行を完了する機会を持つ前に、上記のコードで

  console.log('This site already exists on the database'); 
      return doc; 
     }else{ 
      save_db(longUrl, shortUrl, db); 
     } 
    }); 

} 

function save_db(longUrl, shortUrl, db){ 
    db.collection('sites').insert({ 
     'longUrl': longUrl, 
     'shortUrl': shortUrl 
    }, function(err, doc){ 
     if(err){ 
      throw err 
     }else{ 
      console.log(doc); 
     } 
     db.close(); 
    }); 
} 

は、res.jsonステートメントが実行されます。私は私のアプリに非同期機能を実装しなければならないことを知っています(潜在的に約束していますか?)。しかし、私はそうする方法を完全に失っています!

答えて

1

コールバックは、関数呼び出しで、そう

googleUrl.shorten(req.params[0], function(err, shortUrl){ 
    if(err){ 
     console.log(err); 
    }else{ 
     console.log(shortUrl); 
    } 
    doc = check_db(req.params[0], shortUrl, db); 
}); 
res.json(doc); 

だけ引数です

のように動作します
foo(a, b); 
bar(); 
#googleUrl.shorten()はすぐに( #のres.jsonに通話が続いている)へのあなたの呼び出しは、単に #foo()への呼び出しのようにすぐにコールが続いている

#bar()

あなたのコールバック関数:

function(err, shortUrl){ 
    if(err){ 
     console.log(err); 
    }else{ 
     console.log(shortUrl); 
    } 
    doc = check_db(req.params[0], shortUrl, db); 
} 

は、それが通常の制御フローを中断しないという意味、非同期に実行されます。 #res.json(doc)のような文の実行を延期する必要がある場合は、その実行も通常の制御フローから取り除かれていることを確認する必要があります。これを行うには、#check_db()#save_db()の両方でコールバック引数を受け入れる必要があります。新しい関数のシグネチャは次のようになります。

function save_db(longUrl, shortUrl, db, callback) 

function check_db(longUrl, shortUrl, db, callback) 

その後、コールバック関数を渡す引数「ドキュメント」を受け入れる、とres.json(ドキュメントを実行しをdb関数に追加します。例えば:

doc = check_db(req.params[0], shortUrl, db, function(doc){ 
    res.json(doc); 
}); 

:あなたは単に#check_db()から#save_db()に 'コールバック' を渡します。

最後に、非同期関数の実行が完了したら、値を返すのではなく、コールバックを呼び出します。例えば:

db.collection('sites').findOne({ 
    'longUrl': longUrl, 
    'shortUrl': shortUrl 
}, function(err, doc){ 
    if(err){ 
     console.log(err); 
    }if(doc){ 
     console.log('This site already exists on the database'); 
     callback(doc); 
    }else{ 
     save_db(longUrl, shortUrl, db, callback); 
    } 
}); 

私はあなた次第#save_db()への変更を残してきました。がんばろう!

0

変更check_dbsave_db

function check_db(longUrl, shortUrl, db, cb){ 
    db.collection('sites').findOne({ 
     'longUrl': longUrl, 
     'shortUrl': shortUrl 
    }, function(err, doc){ 
     if(err){ 
      console.log(err); 
      process.nextTick(function(){cb(err)}); 
     }else if(doc){ 
      console.log('This site already exists on the database'); 
      process.nextTick(function(){cb(null, doc)}); 
     }else{ 
      save_db(longUrl, shortUrl, db, cb); 
     } 
    }); 

} 

function save_db(longUrl, shortUrl, db, cb){ 
    db.collection('sites').insert({ 
     'longUrl': longUrl, 
     'shortUrl': shortUrl 
    }, function(err, doc){ 
     db.close(); 
     process.nextTick(function(){cb(err, doc)}); 
    }); 
} 

asyncを指定そして、このように使用する:

app.get('/new/*', function(req, res){ 
    var doc; 
    console.log('This is the url: '+req.params[0]); 
    googleUrl.shorten(req.params[0], function(err, shortUrl){ 
     if(err){ 
      console.log(err); 
     }else{ 
      console.log(shortUrl); 
     } 
     check_db(req.params[0], shortUrl, db, function(err, doc){ 
      if(err) return res.json(err); 
      res.json(doc); 
     }); 
    }); 
}); 
関連する問題