如何从调用异步函数的生成器返回结果?

时间:2017-02-06 10:20:56

标签: javascript ecmascript-6 generator koa node-postgres

我正在使用Koa框架和ES6。如何获得第一个将结果返回到需要yield的视图函数的方法?我试图在节点7.5应用程序中使用pg库,它使用异步调用。

pgrepo.listCities = function*() {
   pool.query('SELECT distinct(town) from public.property_uk', function(err, result) {
     console.log("result: " + JSON.stringify(result.rows));
     // What now?
   });
};

www.pgindex = function*() {
   let results = yield pgrepo.listCities();  // What now?

   console.log('handler: ' + results)

   yield this.render('pgindex', {
       items: results
   });
}

我理解发生了什么,yield正在推迟执行,因此函数运行并产生没有结果,然后查询触发并产生结果。

所以,我的问题是,如何重构这两个函数,以便将查询结果返回给想要将它们传递给视图的函数。

4 个答案:

答案 0 :(得分:0)

不想回答,因为我不知道Koa /发电机什么不是,但是你不能用简单的承诺来解决这个问题吗? (因为没有其他人发布,至少想要给你一些你可以解决它的方法)

此代码未经过测试,我不知道您的堆栈,所以这只是在这里作为可能的解决方案,以防您有更多的代码自由

// Since I have no idea why generators should be used here, let's remove the *
// if you really do need it, then this answer might not work (as I said, I never
// even touched generator functions, so I will just make this as arrow fn)

pgrepo.listCities = () => {
  // first let's return a promise to function call
  return new Promise((resolve, reject) => {
    pool.query('SELECT distinct(town) from public.property_uk', function(err, result) {
      // since this is in callback, we can be sure that this will be executed
      // when the query itself is finished. because this is a promise we
      // can now here resolve it here with results. but first check for
      // errors and reject if this query failed
      if (err) {
        reject(err);
      }
      resolve(result.rows);
    });
  });
};

www.pgindex = () => {
  // Since I have no idea why generators should be used here, let's remove the
  // yield...
  let results = pgrepo.listCities;  

  // now our results can call the listCities and get the promise
  // back as result. as soon as that promise is resolved we can enter into .then
  // and access values

  results()
    .then((results) => {
      // this console log should now have all the results from the query.
      console.log(results);

      // you can now do here what you want with the data. again not sure how
      // this can play with generators

      // also this (both this as next commented block and this as pointer) will
      // most likely fail due to arrow function changing context of this, so you
      // might wanna play around with that to be sure you have correct context
      // if it doesn't work out of the box. If you can't figure it you, you can
      // change this arrow function in normal 'function (results) {...}' and your
      // context will be fine and you will be able to call proper this (I think :) )
      this.render('pgindex', {
        items: results
      });
    }) // and ofc error handling
    .catch((err) => {
      console.log('Something went wrong and I am terrible error message ' + err);
    });
};

答案 1 :(得分:0)

您可能正在寻找的代码的共同例程版本通过隐藏其异步性质使您的承诺看起来像同步代码。相反.then承诺,你可以产生它们,并让你的代码看起来像这样:

let co = require('co');
let pg = require('co-pg')(require('pg'));

let connectionString = 'postgres://postgres:1234@localhost/postgres';

co(function* connectExample() {
    try {
        let client = new pg.Client(connectionString);
        yield client.connectPromise();

        let result = yield client.queryPromise('SELECT distinct(town) from public.property_uk');
        console.log(result);

        client.end();
    } catch (ex) {
        console.error(ex);
    }
});

这类似于async / await,但你今天可以使用它! (尽管在撰写本文时,async / await很快就会进入Node)

请注意,我已经宣传 pg模块,因此可以与co一起使用

答案 2 :(得分:0)

无需重新发明任何内容,pg-promise支持开箱即用的ES6生成器:

var pgp = require('pg-promise')(/*initialization options*/);
var db = pgp(/*your connection details*/);

function * getCities(t) {
    var cities = yield t.query('SELECT distinct(town) from public.property_uk');

    // do whatever you need here

    return cities;
}

function * Generator_Caller() {
    try {
        var cities = yield db.task(getCities);
        console.log(cities);
    }
    catch (error) {
        console.log(error);
    }
}

function Regular_Caller() {
    db.task(getCities)
        .then(function (cities) {
            console.log(cities);
        })
        .catch(function (error) {
            console.log(error);
        });
}

答案 3 :(得分:0)

感谢所有的帮助,我使用的最终代码是:

pgrepo.listTowns = function*() {
var results = yield pool.query('SELECT distinct(town) from public.property_uk');
return results;    };

www.pgindex = function*() {
const results = yield pgrepo.listTowns();

console.log("results: " + JSON.stringify(results.rows));

yield this.render('pgindex', {
    items: results.rows
});};