为什么我的迭代器又被推进了?
Why is my iterator being advanced again?
我有以下程序 - 我使用 genny.js 来处理异步流控制 - 我用 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
现在,如果我用以下函数替换 fetchList,它就可以正常工作:
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
这很奇怪 - 我不明白。请比我聪明的人解释一下。
更新
我已经更改了代码以在没有回调的情况下调用条带方法,或者
迭代器恢复函数。现在它起作用了。但是 - 奇怪的是 - 查看 "results" 处的控制台。我不明白为什么。所以现在它不调用 fetchList 迭代器的 next() 函数 "a second time" - 但我什至没有看到它在哪里被调用一次!?
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')
})
这个returns
> node --harmony genny.js
Before run {
fetchCharges {
fetchList {
} fetchList
} fetchCharges - found 10
} after run
results
您遇到的问题源于两种异步方法的混合。
Every resource method accepts an optional callback as the last argument.
Additionally, every resource method returns a promise.
work seamlessly with Node callback conventions and promises
这就是你的错误:在行
var results = yield stripe.charges.list({}, done())
您确实同时隐含地使用了两者。 done()
确实创建了一个传递给 stripe 的回调,但该调用也产生了一个被 yield 的 promise,并且 genny/suspend 在其上注册了另一个回调。这会导致您正在观察的Error: callback already called
。
您可以选择解决问题的方式:
不兑现承诺
var results = yield void stripe.charges.list({}, done())
// ^^^^
不传递回调
var results = yield stripe.charges.list({})
(我推荐后者)
我有以下程序 - 我使用 genny.js 来处理异步流控制 - 我用 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
现在,如果我用以下函数替换 fetchList,它就可以正常工作:
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
这很奇怪 - 我不明白。请比我聪明的人解释一下。
更新
我已经更改了代码以在没有回调的情况下调用条带方法,或者 迭代器恢复函数。现在它起作用了。但是 - 奇怪的是 - 查看 "results" 处的控制台。我不明白为什么。所以现在它不调用 fetchList 迭代器的 next() 函数 "a second time" - 但我什至没有看到它在哪里被调用一次!?
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')
})
这个returns
> node --harmony genny.js
Before run {
fetchCharges {
fetchList {
} fetchList
} fetchCharges - found 10
} after run
results
您遇到的问题源于两种异步方法的混合。
Every resource method accepts an optional callback as the last argument.
Additionally, every resource method returns a promise.
work seamlessly with Node callback conventions and promises
这就是你的错误:在行
var results = yield stripe.charges.list({}, done())
您确实同时隐含地使用了两者。 done()
确实创建了一个传递给 stripe 的回调,但该调用也产生了一个被 yield 的 promise,并且 genny/suspend 在其上注册了另一个回调。这会导致您正在观察的Error: callback already called
。
您可以选择解决问题的方式:
不兑现承诺
var results = yield void stripe.charges.list({}, done()) // ^^^^
不传递回调
var results = yield stripe.charges.list({})
(我推荐后者)