Javascript中的回调执行序列,从IndexeddB检索 [英] Callback execution sequence in Javascript, Retrieving from IndexeddB

查看:184
本文介绍了Javascript中的回调执行序列,从IndexeddB检索的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果我有这样的代码:

  testJSCallbacks 

function testJSCallbacks(){
var i = 0;

for(i = 0; i <5; i ++){
console.log(Step 1+ i);
foo(i,myCB);
}

}

函数foo(key,fnCB){
//从keyed'key'的indexedDB中检索png图像blob。假设数据库是
//创建并正确启动
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); //对于相同的'key'值,这发生在上述结果有效之前。即找到的键
}
fnCB(result);
}
}

myCB = function(result){
console.log(Step 3+ result);
}

实际输出(仅作为示例):

 步骤1 0 
步骤1 1
步骤1 2
步骤1 3
步骤1 4

步骤2 0找到



步骤3< result>



所需输出:

 步骤1 0 
步骤2 0找到
步骤3<键0的结果值到这里>

在我的代码中,我试图从IndexedDB中读取png blob,它们已经存在。但是,在读取/搜索特定的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 ++){
//如果不存在则初始化promise
if(!promise){
promise = Q.fcall(getStep(i));
}
//附加到现有的promise链
else {
promise = promise.then(getStep(i));
}
// then函数返回另一个可以用于链接的promise。
//我们基本上在循环中将每个函数链接在一起。
promise = promise.then(function(key){
//记录步骤的输出
console.log(Step 1+ key);
return key;
})
// then函数使用一个参数(数据)的回调函数。
// foo签名满足此条件,并将使用最后一个promise(key)的分辨率。
.then(foo)
// myCB将在foo解析它的promise之后执行,它在onsuccess回调中执行
.then(myCB);
}
}

函数getStep(step){
return function(){
return step;
}
}

函数foo(key){
//从keyed'key'的indexedDB中检索png图像blob。假设数据库是
//创建并正确启动
var getRequest = transaction.objectStore(store)。get(key),
//需要返回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); //对于相同的'key'值,这发生在上述结果有效之前。即找到的键
}
deferred.resolve(result);
}

return deferred.promise;
}

function myCB(result){
console.log(Step 3:+ result);
}

jsfiddle使用setTimeout而不是objectStore来演示异步性质。 p>

解释getStep函数



getStep函数就像一个seed它会启动解决你想要做的链(即步骤1,步骤2,步骤3)。它简单地创建一个函数,返回传入的变量的值。这用于传递到promise解析链中的console.logs步骤1的函数,然后返回下一个promise解析的值(步骤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(){
//不要这样做。只是演示一个功能:
var buttons = document.getElementsByTagName(button)|| [],
i,len = buttons.length;
for(var i = 0; i< len; i ++){
buttons [i] .onclick = function(){
//总是警告5
alert一世);
}
}
}

在for循环结束后,这是在函数中使用的值。这是为什么你需要为i创建一个闭包(为了清楚起见,再次使用getStep):

  addHandlers 

function addHandlers(){
var buttons = document.getElementsByTagName(button)|| [],
i,len = buttons.length;


for(var i = 0; i< len; i ++){
// getStep创建一个函数, b $ b buttons [i] .onclick = getStep(i);
}
}

function getStep(i){
return function(){
alert(i);
}
}

之前, 之后。


If I've a code like this:

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);
}

Actual Output (just for example):

Step 1 0
Step 1 1
Step 1 2
Step 1 3
Step 1 4

Step 2 0 Found
.
.

Step 3 <result>
.
.
.

Desired output:

 Step 1 0
 Step 2 0 Found
 Step 3 <result value of key 0 goes here>

In my code I'm trying to read png blobs from IndexedDB, which are already stored earlier. But while reading/searching for a specific blob it takes too long to get the result back, meanwhile a search for second blob occurs even though the earlier search is not finished yet.

Can anyone advise what/how would you do if you need to call an asynchronous function in a loop multiple times and the callback takes too long to come? Is my code correct and makes logical sense or this isn't how javascript is done? I'm very new to this and come from an embedded C background.

解决方案

The problem is the getRequest.onsuccess function is asynchronous, while the for loop executes synchronously. This is why it finishes first... In fact, while you are executing the testJsCallbacks, nothing else will execute until the current execution context ends and control is returned back to the javascript event queue because javascript execution context within the browser is single threaded.

To do what you desire, I would suggest using a promise library. Then you can write code like this (see jsfiddle which uses Q.js library):

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);
}

The jsfiddle uses a setTimeout instead of objectStore to demonstrate the async nature.

Explaining getStep function:

getStep function is like a "seed" function in that it kicks off resolving the chain of what you want to do (i.e. Step 1, Step 2, Step 3). It simply creates a function that returns the value of the variable passed in. This is used to pass into the function that console.logs Step 1 in the promise resolution chain and then returns the value for the next promise resolution (Step 2)... JavaScript has the concept of closures and in order to get the correct value for step number (instead of the value of 'i' at the time when the callbacks are executed) we needed to create a closure for the variable i.

To demonstrate, consider this code:

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);
        }
    }
}

Since the variable i is 5 after the for loop ends, this is the value that is used in the function. This is why you would need to create a closure for i (using getStep again for clarity):

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);
        }
}

Fiddle for before and after.

这篇关于Javascript中的回调执行序列,从IndexeddB检索的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆