2015-10-12 4 views
2

Я не могу получить несколько файлов для загрузки данных и назначения на глобальные переменные. Я читал similar questions и related examples, но у меня все еще есть проблемы.Использование queue() для загрузки нескольких файлов и назначения глобальных переменных

var origins = [], 
    geoJSON = { 
     "type": "FeatureCollection", 
     "features": [] 
    }; 

queue(1) 
    .defer(d3.csv, "path_to.csv", function(d) { 
     origins.push(d.o_geoid) 
     }) 
    .defer(d3.json, "path_to.json", function(d) { 
     // Limit GeoJSON features to those in CSV 
     for (var i = d.features.length - 1; i >= 0; i--) { 
     if($.inArray(d.features[i].properties['GEOID10'], origins) != -1) { 
      geoJSON.features.push(d.features[i]); 
     } 
     } 
    }) 
    .await(ready); 

function ready() { 
    console.log(geoJSON); 
} 

Я рад фильтровать функции GeoJSON в ready(), если это работает лучше, но мне нужно, чтобы это произошло, прежде чем начать создавать карту с

d3.g.selectAll("path") 
    .data(geoJSON.features) 
    .enter.append("path") 
... 

Я предполагаю, что это имеет отношение к делать с обратными вызовами и пустыми результатами, но я не могу заставить его работать. Я понял, что с помощью .await(console.log(geoJSON)); выводит правильный объект на консоль. Функция ready() не будет выполнена. Спасибо за любую помощь в понимании и устранении этой проблемы.

+0

Вы не можете назначать значения из асинхронных обратных вызовов в глобальные. Вся ваша обработка должна выполняться в функции '.ready()'. –

+0

Во-первых, если вы используете 'queue (1)', вы запускаете '.defers' последовательно. Вы должны сделать это, потому что вы используете переменную 'origins' во втором' .defer'. На этом этапе использование '.queue' становится бессмысленным. Во-вторых, ваша готовая функция должна принимать аргументы 'ready (error, result1, result2)' где resultN является возвратом вашего '.defer'. Забудьте глобальные переменные ... – Mark

+0

@Mark Спасибо. Я думал, что использование «очереди» было необходимо, чтобы убедиться, что все данные загружены, прежде чем пытаться использовать d3 для данных.Как я могу убедиться, что данные geojson были отфильтрованы до того, как я создаю многоугольники? Мне нужно только ~ 40 из них из ~ 770, но эти 40 иногда меняются на основе ввода csv. – josiekre

ответ

4

Ваш вопрос уже ответили Jason Davies' reply to the thread you linked, но в любом случае, здесь он вновь формулируются в терминах вашего точного примера ...

var origins = [], 
    geoJSON = { 
     "type": "FeatureCollection", 
     "features": [] 
    }; 

queue(1) 
    .defer(function(url, callback) { 
     d3.csv(url, function(error, csvData) { 
      if(!error) csvData.forEach(function(d) {origins.push(d.o_geoid)}); 
      callback(error, d); 
     }) 
    }, "path_to.csv") 
    .defer(function(url, callback) { 
     d3.json(url, function(error, jsonData) { 
      // Limit GeoJSON features to those in CSV 
      for(var i = jsonData.features.length - 1; !error && i >= 0; i--) { 
       if($.inArray(jsonData.features[i].properties['GEOID10'], origins) != -1) { 
        geoJSON.features.push(jsonData.features[i]); 
       } 
      } 
      callback(error, jsonData); 
     }) 
    }, "path_to.json") 
    .await(ready); 

function ready(error) { 
    console.log(error ? "error: " + error.responseText : geoJSON); 
} 

Я никогда не использовал очереди, но, если вы об этом думаете, это довольно очевидно из ответа Джейсона, как это работает.
Основная картина

queue() 
    .defer(asynchRequest1, url1) 
    .defer(asynchRequest2, url2) 
    .await(callback) 

function callback(error){ 
    console.log(error ? 
     "error: " + error.responseText : 
     "completed, " + (arguments.length - 1) + " objects retrieved" 
    ); 
} 

Сигнатура вызова для первого аргумента .defer является function(url, callback) и подпись обратного вызова function(error, result). Первый согласован с соглашениями d3 (для которых, очевидно, разработана очередь), а более поздняя - обычная практика асинхронного javascript (т. Е. Узла).
Чтобы сделать эту работу, под капотом очередь должна предоставить аргумент обратного вызова, и это должна быть функция, которая попадает в объект await, с результатом запроса asynch в качестве аргументов, используя стандартную подпись function(error, result).

Если вы используете прямой шаблон, где первый аргумент DEFER является d3.csv, например, затем, после ее завершения, d3.csv будет вызывать функцию обратного вызова, предоставленные очередями, поэтому соединения с await объектом, передавая это ошибка/результат состояние ,

В косвенной схеме, описанной Джейсоном Дэвисом, d3.csv завернут в другую функцию - с той же сигнатурой, которая отменяет вызов вызванного внутренним вызовом очереди до тех пор, пока не завершится d3.csv и ваша пост-обработка будет выполнена.

Теперь, когда мы понимаем, что происходит, мы можем подумать о рефакторинге, чтобы сделать его более чистым. Возможно, это так ...

... который имеет точно такой же эффект.

+0

Несколько лакомых кусочков. Таким образом, 'origins.push (csvData.o_geoid);' не будет работать. Это должно быть 'csvData.forEach (function (d) {originins.push (d.o_geoid)});'. Я также думаю, что 'queue (1)' может быть просто 'queue()', поскольку тот больше не зависит от другого. Помимо этого, это работает и упрощает вещи. Спасибо за подробное объяснение. – josiekre

+0

ОК, хорошо, пожалуйста, примите ответ;) –

+0

@CoolBlue, отличный ответ. – Mark

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

  • Нет связанных вопросов^_^