为什么我的迭代器再次进入?
我有以下程序 – 我使用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({})
(我推荐后者)