【问题标题】:How to create asynchronous callbacks in node js?如何在节点 js 中创建异步回调?
【发布时间】:2017-01-09 14:49:19
【问题描述】:
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 语句在其他函数有机会返回值之前运行并返回一个未定义的变量。

   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 语句在以下语句执行之前执行,可以返回一个值。

            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 语句在 GET 请求下面定义的函数有机会完成执行之前执行,结果 res.json 返回一个未定义的变量。我知道我必须在我的应用程序中实现异步功能(可能是承诺?),但我完全不知道该怎么做!

【问题讨论】:

    标签: javascript node.js express asynchronous


    【解决方案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)
    

    然后将接受参数“doc”并执行res.json(doc)的回调函数传递给您的数据库职能。例如:

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

    注意:您只需将 'callback' 从 #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() 的更改由您决定。祝你好运!

    【讨论】:

      【解决方案2】:

      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)});
          });
      }
      

      并像这样使用:

      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);
             });
         });
      });
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-02-12
        • 2023-04-02
        • 2020-03-30
        • 2015-07-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多