我想使用递归函数,但每个函数都应在prevuse完成后运行。 所以我写这段代码:
var service = ['users', 'news'],
lastSync = {
'users' : false,
'news' : false
};
db.transaction(function (tx) {
lastSyncFunc(tx,service,0).then(function(){
console.log(lastSync);
});
});
function lastSyncFunc(tx,service,index){
deferred = $q.defer();
tx.executeSql("SELECT time FROM last_sync WHERE fService = ? ORDER BY id DESC LIMIT 1", [service[index]], function (tx, result) {
if (result.rows.length > 0) {
lastSync[service[index]] = result.rows.item(0).fTime;
}
return ++index<service.length ? lastSyncFunc(tx,service,index) : deferred.resolve();
});
return deferred.promise;
}
现在我的程序返回false
lastSync.users
和lastSync.users
,因为在函数完全运行之前运行此部分。
答案 0 :(得分:3)
手动多重异步调用处理并不总是最佳决策
您可以尝试使用$q.all()
。
简单来说,第二步应该为单个查询编写promisified版本:
const pDbExec = (tx, sql, params = []) => {
let deferred = $q.defer();
tx.executeSql(sql, params, (tx, res) => deferred.resolve(res));
return deferred.promise();
}
第一步应该是“检查我使用的图书馆/方法的有效版本是否存在”。
然后,只需拨打$q.all
,将您的服务列表映射到承诺:
const SQL_SvcLastSync = `SELECT time FROM ... LIMIT 1`;
db.transaction(tx => {
$q.all(service.map(svc => pDbExec(tx, SQL_SvcLastSync, [svc])))
.then(results =>
results.map(res =>
res.rows.length > 0 ? res.rows.item(0).fTime : null))
.then(results => console.log(results));
});
要将结果格式化为键/值对,您有两个选择:
.then(results =>
results.reduce((acc, res, i) => (acc[service[i]]=res, acc), {}))
添加参数的简单解决方案,用于在递归调用之间保存相同的延迟对象:
尝试这样的事情:
function lastSyncFunc(tx,service,index, def){
var deferred = def || $q.defer();
tx.executeSql(
"SELECT time FROM last_sync WHERE fService = ? ORDER BY id DESC LIMIT 1",
[service[index]],
function (tx, result) {
if (result.rows.length > 0) {
lastSync[service[index]] = result.rows.item(0).fTime;
}
return ++index<service.length ?
lastSyncFunc(tx,service,index, deferred) :
deferred.resolve();
});
return deferred.promise;
}
我只是提供延迟到maxdepth,我们可以在那里解决它。
答案 1 :(得分:1)
事实上这样做的方法是避免在“The Collection Kerfuffle”标题下的here所述的递归。
主张模式可以使用db.transaction(function() {...})
结构中的所有内容进行编码,但更清楚的是将tx.executeSql(...)
拉出并在单独的函数中进行宣传。
你最终会得到这样的东西:
var service = ['users', 'news'],
lastSync = {
'users' : false,
'news' : false
};
db.transaction(function (tx) {
return service.reduce(function(promise, serviceItem) {
return promise.then(function() {
return executeSqlPromisified(tx, serviceItem).then(function(fTime) {
if(fTime !== null) {
lastSync[serviceItem] = fTime;
}
});
});
}, $q.when(null)).then(function() {
console.log(lastSync);
});
});
function executeSqlPromisified(tx, serviceItem) {
var deferred = $q.defer();
tx.executeSql("SELECT time FROM last_sync WHERE fService = ? ORDER BY id DESC LIMIT 1", [serviceItem], function (tx, result) {
if (result.rows.length) {
deferred.resolve(result.rows.item(0).fTime);
} else {
deferred.resolve(null);
}
});
return deferred.promise;
}
对于未经训练的人来说,这将是非常难以理解的,但相信我,你可以习惯这种模式。