gpt4 book ai didi

javascript - 如何在 Javascript 中强制同步循环执行?

转载 作者:行者123 更新时间:2023-12-03 03:31:40 25 4
gpt4 key购买 nike

我正在编写一个在 Google Chrome 上的 XAMPP 上运行的本地应用程序。它与 IndexedDB 交互(我使用 Jake Archibald 的 Promise 库)。这就是我的问题。

假设我有一个对象存储,有 2 个属性、日期和工资(当天赚的钱)。我要 console.log比如说一份报告的整个对象存储。这是代码片段:

//Report 4 days of work
for(Day = 1; Day <= 4; Day++) {
dbPromise.then(function(db) {
var tx = transaction("workdays", "readonly");
return tx.objectStore("workdays").get(Day);
}).then(function(val) {
console.log(val.day + '\t' + val.salary + '$\n';
})

我期望的是这样的:

1    100$
2 120$
3 90$
4 105$

但它实际上给出了一个错误,说“无法读取未定义的值日”。结果循环没有等待 dbPromise.then()...但异步继续,并且由于 IndexDB 请求很慢,当它们完成时,Day 计数器已经是 5,并且没有匹配和返回记录。

我挣扎了一段时间,然后通过输入 DayTemp 找到了解决方法在循环中捕获像这样的一天。

//Report 4 days of work
for(Day = 1; Day <= 4; Day++) {
DayTemp = Day;
dbPromise.then(function(db) {
var tx = transaction("workdays", "readonly");
return tx.objectStore("workdays").get(DayTemp);
}).then(function(val) {
console.log(val.day + '\t' + val.salary + '$\n';
})

效果很好。但后来还是不行。结果如下:

1    100$
4 105$
2 120$
3 90$

我需要它们井然有序。我需要做什么?非常感谢!

注意:情况比这个复杂一点,所以我不能使用 getAll()或光标之类的东西。我真的必须循环。我也有兴趣了解 Javascript 的同步/异步主题。我是初学者。

更新:我明白了,伙计们!首先是我第二次尝试 DateTemp 的结果实际上结果是这样的:

4    105$
4 105$
4 105$
4 105$

这基本上反射(reflect)了一开始同样的问题。这次唯一的区别是Date被捕获,因此它不会增加超过 4。但我终于找到了解决这一切的方法。让我用这个简单的 Javascript 片段进行演示:(1)

function dummy(day)
{
dbPromise.then(function(db) {
//Create transaction, chooose object stores, etc,..
objectStore.get(Day);
}).then(function(db) {
console.log(day + '\t' + salary + '\$n');
})
}
for(Day = 1; Day <= 4; Day++)
{
dummy(Day);
}

如果我像上面那样编写代码,我总是会得到正确的答案!

1    100$
2 120$
3 90$
4 105$

但是如果我这样写:(2)

for(Day = 1; Day <= 4; Day++)
{
dbPromise.then(function(db) {
//Create transaction, chooose object stores, etc,..
return objectStore.get(Day);
}).then(function(val) {
console.log(Day + '\t' + val.salary + '\$n');
})
}

Day 以来,我总是会收到错误消息当数据库请求完成事务创建并输入 get() 时,计数器已经为 5。使用 Day 的方法柜台!疯了吧?

似乎 Javascript 有一些东西来确定是否应该等待一条语句,这意味着它应该在其后面的其他语句开始执行之前完全执行。以(1)代码片段为例。输入 Day = 1 进入循环,在循环体内,Javascript 看到 dummy()已通过Day作为参数,并决定“如果不让dummy()先完成,我就不会继续循环,否则他会把自己搞砸的”。我得到了一个漂亮的结果。

但是在 (2) 代码片段中。 Javascript 进入循环,看到我调用了 then()dbPromise上面写着“好吧,正在执行大男孩,但我看不出有什么理由必须等你。哦,你在 Day 里面使用 then() 哈?我不在乎这个,只是看看外面抱歉。”当您执行请求时,我将增加 Day!”。事情变得一团糟。

这是我的第一点。我的第二点是,我还发现add() indexedDB 中的请求是异步的,即使每个 add()位于不同的事务中。但是get()是同步的,所以没问题。

现在希望您对我上面的更新答案发表意见。很肯定他们在某些令人尴尬的方面是错误的。关于 Javascript,我肯定错过了一些非常基础的、显而易见的事情。

最佳答案

我建议您了解以下主题:

  • 异步编程
  • Javascript 函数提升
  • 定义函数和调用函数的区别

作为一般规则,切勿在循环内定义函数。如果不在循环中定义函数,那么您将避免大部分复杂性。

如果您坚持在循环中定义函数,则可以使用立即执行函数表达式的技巧:

for(...) {
(function defined_plus_call(a, b, c) {
// operate on a and b and c here within this function's body
// do NOT use the variables arg1ToUseForA, arg2ToUseForB, etc
}(arg1ToUseForA, arg2ToUseForB, etc));
}

或者,如果您只为现代浏览器编写代码,并且已经熟悉 Promise 和异步编程,那么您可以使用新的 async/await 语法,以便编写命令式循环:

function get_helper_function(tx, Day) {
function executor(resolve, reject) {
var request = tx.objectStore("workdays").get(Day);
request.onsuccess = function() { resolve(request.result); };
request.onerror = function() { reject(request.error); };
}
return new Promise(executor);
}

async function foo(...) {
for(Day = 1; Day <= 4; Day++) {
var promise_result = await dbPromise;
var tx = promise_result.transaction("workdays", "readonly");
var val = await get_helper_function(tx, Day);
console.log(val.day + '\t' + val.salary + '$\n';
}
}

然后,如果您真的想编写更清晰的代码,我会更改其他一些内容。第一,这些都是基本读取,可以共享相同的数据库连接和相同的事务。第二,您可以使用 Promise.all 迭代多个 Promise。

function get_by_day(tx, day) {
function executor(resolve, reject) {
var request = tx.objectStore("workdays").get(day);
request.onsuccess = function() { resolve(request.result); };
request.onerror = function() { reject(request.error); };
}
return new Promise(executor);
}

function get_all(db) {
var db = await dbPromise;
var tx = db.transaction("workdays", "readonly");
var promises = [];
for(var day of days) {
var promise = get_by_day(tx, day);
promises.push(promise);
}

var all_promise = Promise.all(promises);
return all_promise);
}

get_all().then(function(resolutions) {
for(var val of resolutions) {
console.log(val.day + '\t' + val.salary + '$\n';
}
});

这样 get_all 可以以任意顺序同时解析各个 get promise ,至少在理论上是这样。

然后,如果您想尝试优化,请更进一步,查看函数 IDBObjectStore.prototype.getAll。不要显式获取每一天,而是在一个函数调用中加载一系列日期。

关于javascript - 如何在 Javascript 中强制同步循环执行?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46067704/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com