2014-12-17 3 views
0

У меня есть текстовый файл, который просто перечисляет некоторые URL-адреса. Я пытаюсь взять каждую строку из текстового файла и добавить его в массив URL-адресов для дальнейшей работы.NodeJS синхронные функции

var fs = require('fs'), 
    Urls = []; 

var returnURLS = function(file) { 

    var read = function(callback) { 
     fs.readFile(file, function(err, logData){ 
      if (err) throw err; 
      var text = logData.toString(); 
      var lines = text.split('\n'); 
      lines.forEach(function(line, callback){ 
       var url = "http://www." + line; 
       Urls.push(url); 
      }); 
      callback(); 
     }); 
    }; 

    var giveBackAnswer = function() { 
     console.log("1: ", Urls); 
     return Urls;  
    }; 

    read(giveBackAnswer); 

}; 

console.log("2: ", returnURLS('textFileWithListOfURLs.txt')); 

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

2: the urls are undefined 
1: [ 'http://www.cshellsmassage.com', 
    'http://www.darsanamartialarts.com', 
    'http://www.davidgoldbergdc.com', 
    'http://www.dayspaofbroward.com',.... (etc) 

Каков наилучший способ заставить эти функции работать синхронно? 1) Компиляция массива Urls через операции с файловой системой 2) Вывести массив на консоль, когда он был заполнен

+0

Мне лично нравится использовать библиотеку 'async', в частности функцию [' series'] (https://github.com/caolan/async#seriestasks-callback), которую она предоставляет. Не уверен, что лучше всего. – aug

+0

Если это всего лишь однократная операция, вам просто нужно использовать 'readFileSync'. –

+0

Вы пытаетесь вернуть значение синхронно из операции, которая является асинхронной. Вы просто не можете этого сделать. Данные еще не закончили считываться, когда 'read()' завершает выполнение. Передайте обратный вызов в 'read()' и обработайте данные из обратного вызова. – jfriend00

ответ

1

Ну, ваша функция принимает возвращается undefined. Это связано с тем, что все функции JavaScript возвращаются undefined.

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

var returnURLS = function(file, whenDone) { 

    var read = function(callback) { 
     fs.readFile(file, function(err, logData){ 
      if (err) whenDone(err); 
      var text = logData.toString(); 
      var lines = text.split('\n'); 
      lines.forEach(function(line, callback){ 
       var url = "http://www." + line; 
       Urls.push(url); 
      }); 
      callback(); 
     }); 
    }; 

    var giveBackAnswer = function() { 
     console.log("1: ", Urls); 
     whenDone(null, Urls); 
    }; 

    read(giveBackAnswer); 

}; 

Который позволит вам сделать:

returnURLS("textFileWithList.txt", function(err, list){ 
    console.log("2: ", list); 
}); 

альтернативное решение с использованием обещания, (Bluebird) будет выглядеть примерно так:

var fs = Promise.promisify(require("fs")); 
var returnURLS = function(file) { 
    return fs.readFileAsync(file).then(function(logData){ 
     var text = logData.toString(); 
     var lines = text.split('\n'); 
     return lines.map(function(line){ 
      return "http://www." + line; 
     }); 
    }); 
}; 

Который позволит вам сделать:

returnURLS("url.txt").then(function(data){ 
     console.log("Got data!", data); 
}); 
0

Обертка функция обратного вызова

var fs = require('fs'), 
    Urls = []; 

function doit(cb){ 

var returnURLS = function(file) { 

    var read = function(callback) { 
     fs.readFile(file, function(err, logData){ 
      if (err) throw err; 
      var text = logData.toString(); 
      var lines = text.split('\n'); 
      lines.forEach(function(line, callback){ 
       var url = "http://www." + line; 
       Urls.push(url); 
      }); 
      callback(); 
     }); 
    }; 

    var giveBackAnswer = function() { 
     console.log("1: ", Urls); 
     return Urls;  
    }; 

    read(giveBackAnswer); 

}; 

cb(returnURLS); 

} 


doit(function(result){ 
console.log("2: ", result('textFileWithListOfURLs.txt')); 
}); 
1

Вы можете использовать fs.readFileSync в этом простом случае:

var returnURLS = function(file) { 
    var text = fs.readFileSync(file).toString(); 
    var lines = text.split('\n'); 
    lines.forEach(function(line, callback){ 
     var url = "http://www." + line; 
     Urls.push(url); 
    }); 
    return Urls;  
}; 

Это совершенно нормально, когда вы надеваете» t нужно параллелизм, как в этой небольшой утилите.

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

var fetchURLS = function(callback) { 

     fs.readFile(file, function(err, logData){ 
      if (err) throw err; 
      var text = logData.toString(); 
      var lines = text.split('\n'); 
      lines.forEach(function(line, callback){ 
       var url = "http://www." + line; 
       Urls.push(url); 
      }); 
      callback(Urls); 
     }); 
    }; 
}; 

fetchURLS('textFileWithListOfURLs.txt', function(urls){ 
    console.log("2: ", urls); 
}); 

Когда ваш код растет по сложности, становится удобнее use promises, чтобы уменьшить «обратный ад».

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