Co 和 co.wrap 在 Node.js 中表现不同
Co and co.wrap behave differently in Node.js
虽然我有点弄清楚 Koa 流程机制是如何工作的(我认为),但我似乎无法理解 co 和 co.wrap 之间的所有区别。这是给出意外行为的代码:
"use strict";
var co = require("co");
function ValidationError(message, obj, schema) {
Error.call(this, "Validation failed with message \"" + message + "\".");
this.name = "ValidationError";
this.object = obj;
this.schema = schema;
}
ValidationError.prototype = Object.create(Error.prototype);
function ValidatorWithSchema(properties, schema) {
this.properties = properties;
this.schema = schema;
}
ValidatorWithSchema.prototype.validate = function* (obj) {
var validatedObj = obj;
for (let schemaKey in this.schema) {
validatedObj = yield this.properties[schemaKey](validatedObj, this.schema[schemaKey]);
}
return validatedObj;
};
var typeGen = function* (obj, type) {
console.log("Checking against "+ type.name);
var primitives = new Map([
[String, "string"],
[Number, "number"],
[Boolean, "boolean"]
]);
if (!((obj instanceof type) || (primitives.has(type) && (typeof obj === primitives.get(type))))) {
var error = new ValidationError("Given object is not of type " + type.name, obj);
throw error;
}
return obj;
};
var validator = new ValidatorWithSchema({type: typeGen}, {type: String});
var runWrap = r => {
console.log(r);
console.log("### WRAP ###");
var validate = co.wrap(validator.validate);
validate(11).then(console.log, console.error);
};
co(function* () {
yield validator.validate(11);
}).then(runWrap, runWrap);
此代码的输出如下:
Checking against String
{ [ValidationError] name: 'ValidationError', object: 11, schema: undefined }
### WRAP ###
11
你可以看到我包装了 co.wrap 的使用,以便它在简单的共同使用之后。现在很明显 typeGen
在第二次尝试中没有被调用,但为什么会这样呢?这两个结果不应该是一样的吗?
这只是很常见的problem of calling "unbound" methods。
您仍然需要在 validator
实例上将包装函数作为方法调用。例如,您可以在 validate
函数上使用 call
:
var validate = co.wrap(validator.validate);
validate.call(validator, 11).then(console.log, console.error);
或者,您需要.bind()
方法:
var validate = co.wrap(validator.validate.bind(validator));
validate(11).then(console.log, console.error);
或者更好的是,只需将生成器函数包装在它的定义点,这样该方法总是 returns 立即承诺:
ValidatorWithSchema.prototype.validate = co.wrap(function* (obj) {
…
});
…
validator.validate(11).then(console.log, console.error);
虽然我有点弄清楚 Koa 流程机制是如何工作的(我认为),但我似乎无法理解 co 和 co.wrap 之间的所有区别。这是给出意外行为的代码:
"use strict";
var co = require("co");
function ValidationError(message, obj, schema) {
Error.call(this, "Validation failed with message \"" + message + "\".");
this.name = "ValidationError";
this.object = obj;
this.schema = schema;
}
ValidationError.prototype = Object.create(Error.prototype);
function ValidatorWithSchema(properties, schema) {
this.properties = properties;
this.schema = schema;
}
ValidatorWithSchema.prototype.validate = function* (obj) {
var validatedObj = obj;
for (let schemaKey in this.schema) {
validatedObj = yield this.properties[schemaKey](validatedObj, this.schema[schemaKey]);
}
return validatedObj;
};
var typeGen = function* (obj, type) {
console.log("Checking against "+ type.name);
var primitives = new Map([
[String, "string"],
[Number, "number"],
[Boolean, "boolean"]
]);
if (!((obj instanceof type) || (primitives.has(type) && (typeof obj === primitives.get(type))))) {
var error = new ValidationError("Given object is not of type " + type.name, obj);
throw error;
}
return obj;
};
var validator = new ValidatorWithSchema({type: typeGen}, {type: String});
var runWrap = r => {
console.log(r);
console.log("### WRAP ###");
var validate = co.wrap(validator.validate);
validate(11).then(console.log, console.error);
};
co(function* () {
yield validator.validate(11);
}).then(runWrap, runWrap);
此代码的输出如下:
Checking against String
{ [ValidationError] name: 'ValidationError', object: 11, schema: undefined }
### WRAP ###
11
你可以看到我包装了 co.wrap 的使用,以便它在简单的共同使用之后。现在很明显 typeGen
在第二次尝试中没有被调用,但为什么会这样呢?这两个结果不应该是一样的吗?
这只是很常见的problem of calling "unbound" methods。
您仍然需要在 validator
实例上将包装函数作为方法调用。例如,您可以在 validate
函数上使用 call
:
var validate = co.wrap(validator.validate);
validate.call(validator, 11).then(console.log, console.error);
或者,您需要.bind()
方法:
var validate = co.wrap(validator.validate.bind(validator));
validate(11).then(console.log, console.error);
或者更好的是,只需将生成器函数包装在它的定义点,这样该方法总是 returns 立即承诺:
ValidatorWithSchema.prototype.validate = co.wrap(function* (obj) {
…
});
…
validator.validate(11).then(console.log, console.error);