Javascript中的回调执行序列,从IndexeddB检索
Callback execution sequence in Javascript, Retrieving from IndexeddB
如果我有这样的代码:
testJSCallbacks();
function testJSCallbacks(){
var i = 0;
for (i = 0; i < 5; i++){
console.log("Step 1 "+i);
foo(i, myCB);
}
}
function foo(key, fnCB){
//retrieve png image blob from indexedDB for the key 'key'. Assume that the database is
//created and started properly
var getRequest = transaction.objectStore("store").get(key);
getRequest.onsuccess = function (event) {
var result = event.target.result;
if(result){
console.log("Step 2 " + key + " Found");
}else{
console.log("Step 2 " + key + " not Found"); //for the same 'key' value this happens before the above result is valid. i.e. key found
}
fnCB(result);
}
}
myCB = function (result){
console.log("Step 3 "+result);
}
实际输出(仅举例):
Step 1 0
Step 1 1
Step 1 2
Step 1 3
Step 1 4
Step 2 0 Found
.
.
Step 3 <result>
.
.
.
所需输出: Step 1 0
Step 2 0 Found
Step 3 <result value of key 0 goes here>
在我的代码中,我试图从IndexedDB读取png blobs,这已经存储在前面。但是,当读取/搜索特定blob时,需要很长时间才能获得结果,同时,即使先前的搜索尚未完成,也会发生对第二个blob的搜索。
如果你需要在循环中多次调用异步函数并且回调需要很长时间,谁能建议你做什么/如何做?我的代码是正确的,有逻辑意义,或者这不是javascript是怎么做的?我是一个嵌入式C背景的新手。
问题是getRequest。Onsuccess函数是异步的,而for循环是同步执行的。这就是为什么它会先结束…实际上,当您执行testJsCallbacks时,在当前执行上下文结束并将控制返回给javascript事件队列之前不会执行任何其他操作,因为浏览器中的javascript执行上下文是单线程的。
要做你想做的,我建议使用promise库。然后你可以写这样的代码(参见使用Q.js库的jsfiddle):
testJSCallbacks();
function testJSCallbacks(){
var i = 0,
promise;
for (i = 0; i < 5; i++) {
//Make initial promise if one doesn't exist
if (!promise) {
promise = Q.fcall(getStep(i));
}
//Append to existing promise chain
else {
promise = promise.then(getStep(i));
}
//then function returns another promise that can be used for chaining.
//We are essentially chaining each function together here in the loop.
promise = promise.then(function (key) {
//Log the output of step here
console.log("Step 1 " + key);
return key;
})
//then function takes a callback function with one parammeter (the data).
//foo signature meets this criteria and will use the resolution of the last promise (key).
.then(foo)
//myCB will execute after foo resolves its promise, which it does in the onsuccess callback
.then(myCB);
}
}
function getStep(step) {
return function () {
return step;
}
}
function foo(key) {
//retrieve png image blob from indexedDB for the key 'key'. Assume that the database is
//created and started properly
var getRequest = transaction.objectStore("store").get(key),
//Need to return a promise
deferred = Q.defer();
getRequest.onsuccess = function (event) {
var result = event.target.result;
if(result){
console.log("Step 2 " + key + " Found");
}else{
console.log("Step 2 " + key + " not Found"); //for the same 'key' value this happens before the above result is valid. i.e. key found
}
deferred.resolve(result);
}
return deferred.promise;
}
function myCB (result){
console.log("Step 3: " + result);
}
jsfiddle使用setTimeout而不是objectStore来演示异步特性。
说明getStep函数:
getStep函数就像一个"种子"函数,它开始解析你想要做的事情的链(即步骤1,步骤2,步骤3)。它只是创建一个返回传入变量值的函数。这是用来传入控制台的函数。在承诺解析链中记录步骤1,然后返回下一个承诺解析的值(步骤2)…JavaScript有闭包的概念,为了获得步数的正确值(而不是执行回调时的'i'的值),我们需要为变量i创建一个闭包。
为了演示,考虑以下代码:HTML:
<button type="button">0</button>
<button type="button">1</button>
<button type="button">2</button>
<button type="button">3</button>
<button type="button">4</button>
addHandlers();
function addHandlers() {
//Don't do this. Just demonstrating a feature:
var buttons = document.getElementsByTagName("button") || [],
i, len = buttons.length;
for (var i = 0; i < len; i++) {
buttons[i].onclick = function () {
//will always alert 5
alert(i);
}
}
}
由于变量i在for循环结束后为5,因此这是函数中使用的值。这就是为什么你需要为i创建一个闭包(为了清晰起见,再次使用getStep):
addHandlers();
function addHandlers() {
var buttons = document.getElementsByTagName("button") || [],
i, len = buttons.length;
for (var i = 0; i < len; i++) {
//getStep creates a function with a closure for i at its current value in the loop
buttons[i].onclick = getStep(i);
}
}
function getStep(i) {
return function () {
alert(i);
}
}
查看前后
- 使用JSP从服务器检索和显示图像
- 通过Magento的网络服务检索运费
- 如何通过php页面将数据库值检索到jquery自动完成框中
- 无法使用javascript检索SPList项
- 可以't使用Angular解析/检索JSON
- GoogleFeed正在检索图像
- 通过ajax将坐标传递到php服务器端,并在处理后检索到javascript
- 使用Scala Play Framework视图中的键检索映射值
- 从数据库中检索字段,而不模拟它们
- 如何在corona sdk中从CK编辑器中检索数据
- 如何使用Javascript客户端对象模型检索Sharepoint 2010列表项权限
- 在Node.js中上传和检索图像
- XML2JSON并检索数据
- 如何从php返回的JSON中检索值
- Indexeddb检索速度慢的问题
- 在indexedDB中检索失败
- 错误"试图在不允许突变的数据库上进行突变操作."在indexedDB中检索数据时
- 为什么使用linq2indexedDB插入IndexedDB失败,以及如何检索错误
- IndexedDB:检索与对象存储中特定对象关联的行外键
- Javascript中的回调执行序列,从IndexeddB检索