2014-08-22 3 views
0

Прежде чем я задам этот вопрос, я никоим образом не являюсь свободным разработчиком javascript. Я исхожу из фона ООП, так что все асинхронные вызовы/методы передачи странны.Получение значения обратно из метода dropbox.js findByName()?

В любом случае, я использую dropbox.js SDK и, в частности, следующий способ (как указано в документации):

(XMLHttpRequest) findByName(path, namePattern, options, callback)

У меня есть список расширений файлов я зацикливание чтобы найти, вызвав findByName для каждого.

var file_extensions = [".py", ".cpp", ".erl"]; 

function look_for_files(directory_path, file_extensions){ 
    // To hold counts for each file extension 
    var count_dict = []; 

    for (var i = 0; i < file_extensions.length; i++){ 

     var current_file = file_extensions[i]; 

     client.findByName(PATH, current_file, function(error, count){ 
      if(error){ 
       return showError(error); 
      } 
      else { 
       count_dict.push(count.length); 
      } 
     }); 
    } 
    console.log(count_dict); 
}; 

Как вы можете видеть, я просто пытаюсь вызвать метод каждый раз, и возвратить ее в список под названием count_dict. Однако я не могу показать это значение в списке в findByName method.. Я уверен, что это связано с тем, что я неправильно понимаю обратные вызовы и как все это работает, но может ли кто-то, возможно, помочь?

Спасибо

+0

Вы проверяете, что count_dict по-прежнему пуст каким-либо другим способом, чем инструкция console.log в конце? Потому что, если нет, это может быть проблемой, вызванной асинхронным характером запроса, то есть код может попасть в оператор console.log до того, как произошел какой-либо из обратных вызовов. –

ответ

0

Выполнение этого кода поможет вам увидеть проблему:

function do_one_thing(thing, callback) { 
    // Invoke the callback one second later (simulating an async network call) 
    window.setTimeout(function() { 
     callback('Done with ' + thing) 
    }, 1000); 
} 

function do_things(things) { 
    for (var i = 0; i < things.length; i++) { 
     do_one_thing(things[i], function (result) { 
      console.log('Got result: ' + result); 
     }); 
    } 
    console.log('Outside of loop.'); 
} 

do_things(["one", "two", "three"]); 

Выход должен быть чем-то вроде этого:

Outside of loop. 
Got result: Done with one 
Got result: Done with two 
Got result: Done with three 

Возвращаясь к коду, вам «Вызов трех сетевых вызовов, затем печать пустого списка, а затем завершаются сетевые вызовы.

Есть несколько вариантов исправить это. Мой любимый использовать библиотеку обещаний как Q:

function do_one_thing(thing) { 
    var deferred = Q.defer(); 
    // Resolve the promise one second later (simulating an async network call) 
    window.setTimeout(function() { 
     deferred.resolve('Done with ' + thing); 
    }, 1000); 

    return deferred.promise; 
} 

function do_things(things) { 
    return Q.all(things.map(do_one_thing)); 
} 

do_things(["one", "two", "three"]).then(function (results) { 
    console.log('All done!'); 
    console.log(results); 
}); 

Таким образом, все вызовы могут работать одновременно, но вы получите только результаты, когда они все завершены.

Другой вариант свернуть свой собственный механизм для ожидания, что нужно сделать:

function do_one_thing(thing, callback) { 
    // Invoke the callback one second later (simulating an async network call) 
    window.setTimeout(function() { 
     callback('Done with ' + thing); 
    }, 1000); 
} 

function do_things(things, callback) { 
    var results = []; 
    var pending = things.length; 

    for (var i = 0; i < things.length; i++) { 
     // "index" just captures the current value of "i" 
     (function (index) { 
      do_one_thing(things[index], function (result) { 
       // Store the results in the right place. 
       results[index] = result; 
       // Decrement the pending count. 
       pending -= 1; 

       // If we're all done, invoke the callback with the full results. 
       if (pending === 0) { 
        callback(results); 
       } 
      }); 
     })(i); 
    } 
} 

do_things(["one", "two", "three"], function (results) { 
    console.log('All done!'); 
    console.log(results); 
}); 

Суть заключается в том, что, поскольку каждый вызов является асинхронным, и они могут вернуться в любом порядке, вам нужно каким-то образом дождаться их завершения, а затем предоставить ответ на вызывающий код в виде обратного вызова.

0

client.findByName является асинхронным, и ваш код не учитывает это. Приведенный ниже код устраняет эту проблему, проверяя количество записей в count_dict и ожидая, пока не вернутся все сетевые вызовы.

var file_extensions = [".py", ".cpp", ".erl"]; 

function look_for_files(directory_path, file_extensions){ 

    // To hold counts for each file extension 
    var count_dict = []; 

    countExtensions(file_extensions, function(){ 
    console.log(count_dict) 
    }); 

    function countExtensions (file_extensions, callback) { 

    for (var i = 0; i < file_extensions.length; i++) { 

     var current_file = file_extensions[i]; 

     client.findByName(PATH, current_file, function(error, count){ 
     if(error) return showError(error); 
     count_dict.push(count.length); 
     if (count_dict.length === file_extensions.length) return callback(); 
     }); 
    }  
    } 
}; 
+0

Если я правильно понял этот код, это будет делать только один сетевой вызов за раз, верно? Это проще, чем мой код ниже, но я думаю, что лучше всего запускать все асинхронные вызовы сразу. – smarx

+0

@smarx Вы совершенно правы, обновили код, чтобы сделать это. – davidmerfield

+0

Эта версия кода запускает все параллельно, но я основываюсь на времени, когда каждый вызов возвращается, результаты могут быть не в порядке (не совпадают с вводом). – smarx

Смежные вопросы