在我的课程中,我一直在学习indexeddb以及如何处理异步。为了扩展自己并学习更多知识,我一直在尝试在我的代码中使用函数范例。
之前我一直在使用游标,但我意识到我的代码不是完全不可变的或无状态的,这让我很困扰。我想知道是否有办法使用游标而不必求助于将元素推送到数组。
目前,我使用的是:
async function getTable(){
return new Promise(function(resolve, reject){
const db = await connect();
const transaction = await db.transaction(["objectStore"], "readonly");
const store = await transaction.objectStore("objectStore");
var myArray = [];
store.openCursor().onsuccess = function(evt) {
var cursor = evt.target.result;
if (cursor) {
myArray.push(cursor.value);
//I don't want to use push, because it's impure. See link:
cursor.continue();
} else {
resolve(myArray);
}
}
}
//link: https://en.wikipedia.org/wiki/Purely_functional_programming
它工作正常。但它不纯粹,它使用推。如果有的话,我想学习另一种方法。
谢谢!
答案 0 :(得分:0)
你可以根据函数式编程的精神做一些事情,但在JavaScript中可能不值得。
例如,要实现不变性数组,至少在精神上,您只需在每次要向数组添加元素时创建并返回一个新数组。我想如果我正确地回忆起我的方案,那么这个函数被称为cons
。
function push(array, newValue) {
const copy = copyArray(array);
copy.push(newValue);
return copy;
}
function copyArray(array) {
const copy = [];
for(const oldValue of array) {
copy.push(oldValue);
}
return copy;
}
// Fancy spread operator syntax implementation if you are so inclined
function copyArray2(inputArray) {
return [...inputArray];
}
现在不是改变输入数组,而是创建它的修改副本。请记住,这绝对是可怕的表现,你可能永远不会想在真正的应用程序中这样做。
你可以更进一步,并使用一些基于堆栈的方法。同样,这是非常糟糕的,但它基本上会创建一个返回函数的push函数。当你追加项目时,堆栈的大小会增加,然后当你展开它时,它会展开成一个值数组。
我的第二点是,您可以通过使用indexedDB的更新,记录不足的功能来完全避免此阵列构建。具体而言,IDBObjectStore.prototype.getAll。这个函数会为你创建不透明的数组,如果它是不透明的,你永远不会知道它的抽象中隐藏的任何FP反模式,因此不会破坏规则。
function getTable(){
return new Promise(function(resolve, reject){
const db = await connect();
const transaction = await db.transaction(["objectStore"], "readonly");
const store = await transaction.objectStore("objectStore");
const request = store.getAll();
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(request.error);
}
}
我的第三点很简单,使用db.transaction("objectStore", "readonly");
代替db.transaction(["objectStore"], "readonly");
。数组参数是可选的,最好保持简单。
我的第四点很简单,使用db.transaction("objectStore");
代替db.transaction(["objectStore"], "readonly");
。 "只读"是事务的默认模式,因此无需指定它。通过不指定参数可以充分清楚地传达代码的目的,省略参数的详细程度较低。
我的第五点是你在函数定义中使用async
说明符(?)。你不需要在这里使用它。您有一个同步函数返回Promise
的实例。如果有的话,指定异步会导致对代码正在做什么的混淆。相反,您可能希望在使用函数时使用async限定符。
我的第六点是你在致电connect()
时违反了一些FP原则。什么是connect
连接到?隐含的全球状态。这完全违反了函数式编程的精神。因此,您的连接参数必须是函数本身的参数,因此您不必依赖于使用哪个数据库的隐含知识。
我的第七点是您正在使用数据库。功能程序员在数据库,或任何I / O或与外界的交互方面存在很多问题,他们似乎想假装没有这样的东西。因此,如果您想使用功能方法,您可能根本就不应该使用数据库。
我的八点是,在承诺(呼叫和等待connect
)内的联系绝对是一种反模式。目标是链接承诺,以便一个接一个地开始。呼叫者必须呼叫连接并then
呼叫getTable
,或getTable
必须呼叫connect
,然后执行其余承诺。
我的第九点是我甚至不确定这是如何执行的。传递给Promise
构造函数的执行程序函数未被限定为async
。因此,您在非限定函数中使用await
修饰符。这应该是一个错误。从技术上讲,承诺吞噬了异常,这意味着这个承诺应该总是拒绝。
我的第十点是你到处使用async
。我不知道发生了什么,除非你的connect
函数返回某种包装器库,但对IDBDatabase.prototype.transaction
和IDBTransaction.prototype.objectStore
的调用是同步的。你等待他们的原因毫无意义。他们不回报承诺。'
我的第十一点是你没有注意到错误。发生错误时不会回叫request.onsuccess
。这可能会导致你的承诺永远不会解决。您还需要考虑失败案例。
我的第12点是你似乎错过了onsuccess处理函数的右括号。我不确定这个代码是如何成功解释的。