2015-07-19 2 views
0

Я пытаюсь реализовать алгоритм в js. Я хочу прочитать данные из текстового файла (строка за строкой) без ввода выбора, просто установив путь к файлу в исходном коде. Я пробовал каждый метод в stackoverflow, все они не работают для меня.Синхронный XMLHttpRequest при чтении файла в JavaScript

Файл, который нужно прочитать, находится именно на моем локальном хосте.

Может ли кто-нибудь помочь?

--------- Обновление ----------

вот мой код и там ошибка происходит, как:

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

Файл, который я пытаюсь прочитать, находится именно в моей папке localhost.

<html> 
    <head> 
    </head> 
    <body> 
     <script type="text/javascript"> 
      var rules = {}; 
      var left, right1, right2, probability; 
      // read rule file and process it into rules format 
      function readTextFile(file) { 
       var rawFile = new XMLHttpRequest(); 
       rawFile.open("GET", file, false); 
       rawFile.onreadystatechange = function() { 
        if(rawFile.readyState === 4) { 
         if(rawFile.status === 200 || rawFile.status == 0) { 
          var allText = rawFile.responseText; 
          allText = allText.split("\n"); 
          allText = allText.splice(0, allText.length-1); 
          allText.forEach(function (rule) { 
           rule; 
           left = rule[0]; 
           probability = parseFloat(rule.slice(rule.indexOf(":")+2)); 
           rules[left] ? rules[left] : rules[left] = {}; // init left 
           if (rule[6] == " ") { 
            right1 = rule[5]; 
            right2 = rule[7]; 
            rules[left][right1] ? rules[left][right1] : rules[left][right1] = {}; // init right1 
            rules[left][right1][right2] = probability; 
           } else { 
            right1 = rule.slice(5, rule.indexOf(":") - 1); 
            rules[left][right1] = probability; 
           } 
          }); 
         } 
        } 
       } 
       rawFile.send(null); 
      } 
      readTextFile("rules.txt"); 
      console.log(rules); 
     </script> 
    </body> 
</html> 

--------------------- Update2 ---------------------- -----

Правила, как это:

A -> D C : 0.00688348825155337 
A -> D M : 0.03345377673232689 
A -> G F : 0.43257400994797 
A -> L C : 0.4225829540437112 
A -> L H : 0.014080236090023698 
A -> L M : 0.06637630954705294 
A -> N M : 0.001218212356843953 
A -> O M : 0.022583482305501317 
+1

Можете ли вы поделиться код, который вы пробовали? Это поможет нам в предоставлении решения/предложения. –

+0

И какие ошибки вы получали? –

+0

Возможный дубликат [HTTP GET запрос в JavaScript?] (Http://stackoverflow.com/questions/247483/http-get-request-in-javascript) – Jonathan

ответ

0

предупреждение вы получаете, потому что синхронные XMLHttpRequest, как правило, не рекомендуется: он может повесить браузер, если сервер не отвечает сразу.

Если вы только собираетесь запустить это на localhost, вы можете игнорировать предупреждение, если хотите, или, лучше, изменить синхронный запрос на асинхронный.

Что делает его синхронным является третьим параметром для .open() вызова:

rawFile.open("GET", file, false); 

Чтобы сделать это асинхронно, изменить что верно:

rawFile.open("GET", file, true); 

Или просто опустить параметр, потому что true является по умолчанию:

rawFile.open("GET", file); 

Остальные y наш код должен работать так, как есть. (Он работал для меня в кратчайшие сроки.) Вы уже написали код таким образом, который будет работать с асинхронным запросом: вы используете данные в обратном вызове , когда readyState === 4, вместо того, чтобы предполагать, что он будет доступен сразу после того, как вы произнесете вызов .open(), как это может сделать синхронный код.

Для получения дополнительной информации см. MDN documentation.

Update 1

Проблема с rules быть определено вне onreadystatechange обратного вызова является нормальным, ожидаемое поведение. Помните, что мы теперь изменили запрос на асинхронный.То есть, вызов .open() инициирует запрос, а затем возвращает сразу, прежде чем данные будут возвращены сервером (даже сервер на localhost).

Решение этого просто: не пытайтесь получить доступ к встроенным данным после запроса. Вместо этого вы можете получить доступ только от в пределах функции обратного вызова успеха или от другой функции, которую вы вызываете из этого обратного вызова.

Например, в обновленном коде просто переместите вызов console.log() в конец обратного вызова, как показано ниже, или позвоните по другой функции, если хотите. Что бы вы ни делали с данными, следуйте этой схеме.

Кроме того, не объявляйте rules в верхней части кода; это приведет только к путанице, потому что значение rules недоступно до тех пор, пока не будет вызвана функция обратного вызова успеха (как вы обнаружили). Вместо этого объявите его внутри обратного вызова.

Аналогично, left, right1, right2 и probability используются только внутри forEach() обратного вызова, так что это, где они должны быть объявлены.

Update 2

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

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

rules.txt файл я тестировал с выглядит следующим образом:

A -> D C : 0.00688 
A -> G F : 0.43257 
B -> with : 0.1875 
C -> with : 0.2 

Код JavaScript является:

function readRules(file) { 
    var request = new XMLHttpRequest(); 
    request.open('GET', file); 
    request.onreadystatechange = function() { 
     if(request.readyState === 4) { 
      if(request.status === 200 || request.status == 0) { 
       processRules1(request.responseText); 
       processRules2(request.responseText); 
      } 
     } 
    } 
    request.send(null); 
} 

function processRules1(allText) { 
    var rules = {}; 
    allText = allText.split("\n"); 
    allText = allText.splice(0, allText.length-1); 
    allText.forEach(function (rule) { 
     left = rule[0]; 
     probability = parseFloat(rule.slice(rule.indexOf(":")+2)); 
     rules[left] ? rules[left] : rules[left] = {}; // init left 
     if (rule[6] == " ") { 
      right1 = rule[5]; 
      right2 = rule[7]; 
      rules[left][right1] ? rules[left][right1] : rules[left][right1] = {}; // init right1 
      rules[left][right1][right2] = probability; 
     } else { 
      right1 = rule.slice(5, rule.indexOf(":") - 1); 
      rules[left][right1] = probability; 
     } 
    }); 
    console.log(JSON.stringify(rules, null, 4)); 
} 

function processRules2(rulesText) { 
    var reRule = /^(\w) -> (\w+)((\w))? : ([\d.]+)$/gm; 
    var rules = {}; 
    rulesText.replace(reRule, function(
     line, left, right1, dummy1, right2, probability 
    ) { 
     if(! rules[left]) rules[left] = {}; 
     if(right2) { 
      if(! rules[left][right1]) rules[left][right1] = {}; 
      rules[left][right1][right2] = probability; 
     } else { 
      rules[left][right1] = probability; 
     } 
    }); 
    console.log(JSON.stringify(rules, null, 4)); 
} 

readRules('rules.txt'); 

processRules1() использует оригинальную технику, и processRules2() использует регулярное выражение.

Обе версии журнал один и тот же результат для испытания rules.txt файла:

{ 
    "A": { 
     "D": { 
      "C": 0.00688 
     }, 
     "G": { 
      "F": 0.43257 
     } 
    }, 
    "B": { 
     "with": 0.1875 
    }, 
    "C": { 
     "with": 0.2 
    } 
} 

Одна часть функции processRules2(), что может показаться немного пугающим является само регулярное выражение:

var reRule = /^(\w) -> (\w+)((\w))? : ([\d.]+)$/gm; 

Скорее чем объяснить это здесь подробно, позвольте мне указать на a page on regex101.com, который проверяет регулярное выражение и объясняет, как он работает. Дайте мне крик, если что-нибудь в их объяснении не ясно.

Кроме того, что это немного короче, регулярное выражение делает код более гибким. Например, предположим, что файл правил иногда использовал более одного пробела между значениями вместо одного пробела в вашем существующем файле. При первоначальном подходе вам придется пересчитать все смещения символов и включить код для обработки как одного пробела, так и нескольких пробелов. С регулярным выражением было бы так же просто, как изменить (который соответствует одному пространству) до + (который соответствует одному или более пробелам).

Также обратите внимание, что регулярное выражение позаботится о разделении файла правил на строки и игнорирует пустую строку в конце файла (вместо того, чтобы использовать .splice() для удаления последней строки). Пустая строка просто не соответствует регулярному выражению, поэтому она игнорируется таким образом.

Нечетная вещь в коде - использование метода .replace(). Обычно этот метод используется, когда вы действительно хотите заменить символы в строке чем-то другим. Но здесь мы просто используем его как способ для вызывать функцию для каждого совпадения в строке, а затем игнорируем значение, возвращаемое .replace().

И последнее предложение: В нескольких местах исходный код что-то вроде этого:

rules[left] ? rules[left] : rules[left] = {}; 

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

if(! rules[left]) rules[left] = {}; 
+0

измените значение false на true, исправьте мое предупреждение. Но есть еще одна проблема, например, в моем последнем коде выше, правила переменных не изменяются вне функции. Но точки останова в функции обратного вызова показывают, что для правил задано значение. Не могли бы вы посмотреть? пожалуйста, игнорируйте мою структуру данных, просто переменная, которая изменяется внутри функции обратного вызова, остается неизменной при выводе. –

+0

Благодарим за предложение, я улучшил свой код с вашего совета, и теперь он работает хорошо. Кстати, мои данные правил обновлены, вы сказали, что может быть какой-то другой способ его обработки, вы имеете в виду регулярные выражения? Очень благодарен за ваше время. –

+0

Отлично, я рад, что у вас это работает! Да, регулярные выражения и 'split' могут помочь немного здесь, например, вы можете заменить' parseFloat (rule.slice (rule.indexOf (":") + 2)) 'с' + rule.split (/: * /) [1] '(Я предполагаю, что за двоеточием следует ноль или более пробелов). Я повторю это во втором комментарии ниже, чтобы избежать обертывания слов ... –

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