产生的价值不能被视为承诺

时间:2016-03-12 04:24:53

标签: javascript ecmascript-6 bluebird koa

我正在使用Koa和Bluebird并正在尝试协同程序。我发现下面给出了一个错误。但是,如果我将yield initRouters()替换为initRouters()的内容,则可行。这是为什么?

'use strict';

const fs = require('fs');
const Promise = require('bluebird');
const readdir = Promise.promisify(fs.readdir);

let app = require('koa')();

let initRouters = function *() {
  const routerDir = `${__dirname}/routers`;
  let routerFiles = yield readdir(routerDir);
  return Promise.map(routerFiles, function *(file) {
    var router = require(`${routerDir}/${file}`);

    app
      .use(router.routes())
      .use(router.allowedMethods());
  });
}

Promise.coroutine(function *() {
  yield initRouters();

  const PORT = process.env.PORT || 8000;
  app.listen(PORT);
  console.log(`Server listening on ${PORT}`);
})();

我得到的错误是

Unhandled rejection TypeError: A value [object Generator] was yielded that could not be treated as a promise

    See http://goo.gl/MqrFmX

From coroutine:
    at Function.Promise.coroutine (/home/jiewmeng/Dropbox/expenses-app/node_modules/bluebird/js/release/generators.js:176:17)
    at Object.<anonymous> (/home/jiewmeng/Dropbox/expenses-app/src/app.js:21:9)
    at PromiseSpawn._continue (/home/jiewmeng/Dropbox/expenses-app/node_modules/bluebird/js/release/generators.js:145:21)
    at PromiseSpawn._promiseFulfilled (/home/jiewmeng/Dropbox/expenses-app/node_modules/bluebird/js/release/generators.js:92:10)
    at /home/jiewmeng/Dropbox/expenses-app/node_modules/bluebird/js/release/generators.js:183:15
    at Object.<anonymous> (/home/jiewmeng/Dropbox/expenses-app/src/app.js:27:3)
    at Module._compile (module.js:413:34)
    at Object.Module._extensions..js (module.js:422:10)
    at Module.load (module.js:357:32)
    at Function.Module._load (module.js:314:12)
    at Function.Module.runMain (module.js:447:10)
    at startup (node.js:141:18)
    at node.js:933:3

2 个答案:

答案 0 :(得分:6)

您已经遇到鸡蛋/鸡肉问题。

Promise.coroutine让你产生一个承诺:

  

返回一个可以使用yield来产生promises的函数。

这里的问题是你试图产生一个生成器函数,而不是一个承诺。这会导致错误:

  

Unhandled rejection TypeError: A value [object Generator] was yielded that could not be treated as a promise

<强>为什么吗

好吧,生成器函数返回一个promise,但是当你产生它时它只是一个promise。而且因为你不能产生生成器函数,所以你永远不会得到价值(承诺)。

您可以(并且应该)使用coroutineyield initRouters();但是initRouters()应该是一个返回promise而不是生成器函数的普通函数。

作为旁注,您不需要Promise.map(),因为您在.map内所做的一切都是同步的,所以您可以完美地做到:

let initRouters = function() {
  const routerDir = `${__dirname}/routers`;

  return readdir(routerDir).then(function (files) {
    files.map(function (file) {
      var router = require(`${routerDir}/${file}`);

      app
        .use(router.routes())
        .use(router.allowedMethods());
    })
  })
}

在这里,您将返回一个承诺,该承诺会在您产生它时解决。但正如你所看到的,你已经回复了一个承诺,这就是Promise.coroutine没有给你任何错误的原因。对于生成器,您不会返回承诺。

答案 1 :(得分:2)

initRouters()返回一个生成器。你不能yield Promise.coroutine initRouters,只允许你产生承诺(正如错误清楚地表明的那样)。

您需要将Promise.coroutine包裹在yield* initRouters(); 中,或使用

co

这样所有来自发电机的承诺都会产生,而不是发电机本身。请注意,与Bluebird相比,public class MainActivity extends FragmentActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); if (findViewById(R.id.fragment_container) != null) { // However, if we're being restored from a previous state, // then we don't need to do anything and should return or else // we could end up with overlapping fragments. if (savedInstanceState != null) { return; } // Create a new Fragment to be placed in the activity layout QuestionsFragment firstFragment = new QuestionsFragment(); firstFragment.setArguments(getIntent().getExtras()); // Add the fragment to the 'fragment_container' FrameLayout getFragmentManager().beginTransaction() .add(R.id.fragment_container, firstFragment).commit(); } } } 库确实允许这样的怪癖。