假设我有一个名为openShapeFile
的函数,它读取一个文件,并生成一个Promise,它包含一个具有read
函数的源对象,该函数返回一个Promise,它将实际值包装在Shapefile,并且有一个.done
布尔值,可用于判断文件的末尾是否已到达。
实际上,shapefile.open
来自此处:
https://www.npmjs.com/package/shapefile
如果我现在想要将文件读入数据库,我可以说:
openShapeFile(`shapefile.shp`).then((source) => source.read()
.then(function log(result) {
if (result.done) {
return
} else {
let query = `INSERT INTO geodata(geometry, id, featcode) VALUES(ST_GeomFromGeoJSON('${
JSON.stringify(Object.assign({}, result.value.geometry, {coordinates: result.value.geometry.coordinates.map(JSON.stringify)}))
}'), '${
result.value.properties.ID
}', ${
result.value.properties.FEATCODE
});`
query = query.split('"[[').join('[[').split(']]"').join(']]')
return pool.query(query).then((result) => {
return source.read().then(log)
})
}
})).then(() => console.log(dirCount)).catch(err => 'Problem here')))
这只是工作,但有一个递归的Promise(怪异)
因此,作为练习和/或看看它是否会产生更多的清晰度,我决定将其重写为生成器,产生类似的东西:
function *insertQuery(query) {
const result = pool.query(query)
return result
}
const shapeFileGenerator = co.wrap(function* (source) {
while (true) {
const result = yield source.read()
if (result.done) {
return yield {}
} else {
let query = `INSERT INTO geodata(geometry, id, featcode) VALUES(ST_GeomFromGeoJSON('${
JSON.stringify(Object.assign({}, result.value.geometry, {coordinates: result.value.geometry.coordinates.map(JSON.stringify)}))
}'), '${
result.value.properties.ID
}', ${
result.value.properties.FEATCODE
});`
query = query.split('"[[').join('[[').split(']]"').join(']]')
yield* insertQuery(query)
}
}
})
openShapeFile(`shapefile.shp`).then((source) => {
const s = shapeFileGenerator(source)
})))
现在这个有效!它读取所有数据!
但是,我讨厌无限循环,我从不直接调用.next。我该如何重做呢?用发电机做这样的事情的惯用方法是什么?看来我应能够用s.next()
编写一个合适的生成器,从而产生source.read()
?
答案 0 :(得分:0)
我会写
async function readFileToDB(filename) {
const source = await openShapeFile(filename);
for (let {value, done} = await source.read(); !done; {value, done} = await source.read()) {
const query = `INSERT INTO geodata(geometry, id, featcode) VALUES(ST_GeomFromGeoJSON('${
JSON.stringify(value.geometry)
}'), '${
value.properties.ID
}', ${
value.properties.FEATCODE
});`
const result = await pool.query(query);
}
console.log(dirCount);
}
readFileToDB(`shapefile.shp`).catch(err => console.error('Problem here', err));
艰难我认为递归解决方案没有任何问题。
似乎我应该能够使用
s.next()
编写一个合适的生成器,从而产生source.read()
?
不,发电机是同步的。您可能希望查看async iteration proposal。
答案 1 :(得分:-1)
您可以将逻辑编码为同步,并通过顺序执行器nsynjs执行。以下是在this file上测试的略微修改的工作示例:
main.js:
var nsynjs = require('nsynjs');
var shapefile = require('shapefile');
function synchrobousCode(shapefile /*, pool */) {
var source = shapefile.open('UScounties.shp').data;
var result = source.read().data;
while(result && !result.done) {
var query = "INSERT INTO geodata(geometry, id, featcode) VALUES('" +
JSON.stringify(Object.assign({}, result.value.geometry, {coordinates: result.value.geometry.coordinates.map(JSON.stringify)})) +
"'), '" +
result.value.properties.ID +
"'," +
result.value.properties.FEATCODE +
"')";
console.log(query.length);
// uncomment line below to sequentially insert to the DB
// var queryRes = pool.query(query).data;
result = source.read().data;
}
}
nsynjs.run(synchrobousCode,null,shapefile /*, pool */ ,function () {
console.log('all done');
})
Nsynjs会自动检测某些函数调用是否返回promise。如果是,它将等待承诺解析,将结果放到data
属性,然后继续下一个表达式。