为什么我的迭代器再次进入?

我有以下程序 – 我使用genny.js来处理asynchronousstream量控制 – 我已经尝试与suspend.js相同 – 类似的错误。

我正在使用Stripe nodejs API。

我的迭代函数似乎被调用两次 – 这是造成一个错误 – 我不明白为什么被调用两次。 这一定是一个简单的思维把戏,我没有看到。

var genny = require('genny') genny.longStackSupport = true var stripe = require("stripe")("sk_live_....") fetchCharges = genny.fn(function* (d) { console.log("Before fetchCharges") var charges = yield fetchList(d()) console.log("After fetchCharges - found ", charges.length) return true }) fetchList = genny.fn(function* (done) { console.log("before fetchList") var results = yield stripe.charges.list({}, done()) console.log("after fetchList") return results.data }) genny.run(function* (resume) { console.log('before run') yield fetchCharges(resume()) console.log('after run') }) 

控制台输出是:

 > node --harmony genny.js before run Before fetchCharges before fetchList after fetchList After fetchCharges - found 10 after run /Volumes/dev/ingest/node_modules/genny/index.js:50 else throw e; ^ Error: callback already called at resume (/Volumes/dev/ingest/node_modules/genny/index.js:154:39) at throwAt (/Volumes/dev/ingest/node_modules/genny/index.js:49:30) at resume (/Volumes/dev/ingest/node_modules/genny/index.js:153:28) at tryProcessPending (/Volumes/dev/ingest/node_modules/genny/index.js:41:28) at resume (/Volumes/dev/ingest/node_modules/genny/index.js:164:17) at null._onTimeout (/Volumes/dev/ingest/node_modules/stripe/lib/StripeResource.js:87:34) at Timer.listOnTimeout (timers.js:110:15) From generator: at /Volumes/dev/ingest/genny.js:22:26 

现在,如果我用下面的函数replacefetchList,它工作正常:

 fetchList = genny.fn(function* (done) { console.log('before doTimeout') console.log('1sec break ...') yield setTimeout(done(), 1000); console.log('after doTimeout') return [] }) 

控制台输出是:

 > node --harmony genny.js before run Before fetchCharges before doTimeout 1sec break ... after doTimeout After fetchCharges - found 0 after run 

为了进一步说明itertor的next()方法被调用两次的事实 – 我有另一个(非工作)版本的程序。

 var genny = require('genny') genny.longStackSupport = true var stripe = require("stripe")("sk_live_...") fetchCharges = genny.fn(function* (d) { console.log("Before fetchCharges") var charges = yield fetchList(function(err, cb) { console.log("callback") }) console.log("After fetchCharges - found ", charges.length) return true }) fetchList = genny.fn(function* (done) { console.log("before fetchList") var results = yield stripe.charges.list({}, done()) console.log("after fetchList") return results.data }) genny.run(function* (resume) { console.log('before run') yield fetchCharges(resume()) console.log('after run') }) 

它的控制台输出在这里:

 > node --harmony genny.js before run Before fetchCharges before fetchList after fetchList callback callback 

这很奇怪 – 我不明白。 请有人比我更聪明请解释一下。

UPDATE

我改变了代码来调用没有callback或迭代器恢复function的条带方法。 现在它工作。 但是 – 好奇地 – 在“结果”看控制台。 我不明白为什么。 所以现在它不会再次调用fetchList迭代器的next()函数 – 但是我不知道它甚至会被调用一次!

 var results = yield stripe.charges.list() 

这里是更新完整的程序。

 var genny = require('genny') genny.longStackSupport = true var stripe = require("stripe")("sk_live_i6TrEk5lSRM1CmbSZZPsQzKc") fetchCharges = genny.fn(function* (d) { console.log(" fetchCharges {") var charges = yield fetchList(d()) console.log(" } fetchCharges - found ", charges.length) return true }) fetchList = genny.fn(function* (done) { console.log(" fetchList {") var results = yield stripe.charges.list({}, function(err, results) { console.log("results ") }) console.log(" } fetchList") return results.data }) genny.run(function* (resume) { console.log('Before run {') yield fetchCharges(resume()) console.log('} after run') }) 

这返回

 > node --harmony genny.js Before run { fetchCharges { fetchList { } fetchList } fetchCharges - found 10 } after run results 

您遇到的问题源于两种asynchronous方法的混合。

条纹API文档提到

每个资源方法接受一个可选的callback作为最后一个参数。
另外,每个资源方法都会返回一个承诺。

然而, genny和suspend都这样做

节点callback约定承诺无缝工作

在这里,你的错误就在于此

 var results = yield stripe.charges.list({}, done()) 

同时隐式使用两者done()确实创build了一个被传递给stripe的callback函数,但是这个调用也产生了一个承诺,而genny / suspend会注册另一个callback函数。 这导致Error: callback already called您正在观察的Error: callback already called

你可以select你想要解决的问题:

  • 不要承诺

     var results = yield void stripe.charges.list({}, done()) // ^^^^ 
  • 不要传递callback

     var results = yield stripe.charges.list({}) 

(我推荐后者)