Pull to refresh
163
0
Send message
Да ну, у меня пока твои файлы будут читаться, уже в базу что-то запишется )
Доктор, во мне иногда просыпается обфускатор )
Егор, fs.readFileSync() в отличие от fs.readFile.sync() — блокирует весь процесс, что не есть круто )
Если оборачивать объект полностью — то да. Но в таком случае слишком много избыточных операций. Представьте себе, мы хотим использовать Sync(fs).readFile — а для этого программе нужно обработать и обернуть все функции объекта fs.
Ну, это уже специфика языка такая. Те же самые проблемы с call() и apply().
Ну так об этом и идет речь в последнем примере. Только FutureSync(fs) это уже слишком :)
Была еще мысль вот такого подхода (чтобы не портить Function.prototype):

// Sync(fn [,obj])([arg1, arg2, ...])
var source = Sync(fs.readFile, fs)(__filename, 'ascii');

Но это, как по мне, хуже, чем:
var source = fs.readFile.sync(fs, __filename, 'ascii');
Тогда продемонстрируйте мне удобный, понятный и безкостыльный nodejs код (с корректной обработкой ошибок), который:
a. Последовательно прочтет 3 файла один за другим, склеит и выведет их исходный код
б. Параллельно прочтет 3 файла, склеит и выведет их исходный код (но в жестко заданной последовательности)

a. на node-sync:
var Sync = require('sync'), fs = require('fs');
Sync(function(){
    try {
        var file1 = fs.readFile.sync(null, 'file1');
        var file2 = fs.readFile.sync(null, 'file2');
        var file3 = fs.readFile.sync(null, 'file3');
        console.log([file1, file2, file3].map(String).join(''));
    }
    catch (e) {
        console.error(e);
    }
})


б. на node-sync:
var Sync = require('sync'), fs = require('fs');
Sync(function(){
    try {
        var file1 = fs.readFile.future(null, 'file1');
        var file2 = fs.readFile.future(null, 'file2');
        var file3 = fs.readFile.future(null, 'file3');
        console.log([file1.result, file2.result, file3.result].map(String).join(''));
    }
    catch (e) {
        console.error(e);
    }
})
> Костыль это не новые возможности, а переиначивание уже существующих возможностей для чьего-нибудь удобства. Да и то, удобства субъективного.
Согласен. Но это не относится к данному решению.

> Node.js специально сделан асинхронным, без блокирования потока, а тут наоборот возвращаются блокировщики и т.п.
Ну вы уже прям как MagaSoft. Вы хоть поняли, как это работает?

yield — это новые возможности, или костыль?
> То что делается с целью «асинхронное, но чтобы выглядило типа как синхронное» — костыли. Причем, очень вредные в целом, имхо.
Что такое «асинхронное» и как это должно выглядеть? Если есть устоявшееся мнение, что «асинхронное» в nodejs выглядит в виде анонимного коллбэка с ошибкой первым аргументом — это всего лишь последствие синтаксических свойств языка на текущий момент его развития. Если есть способ упростить эту конструкцию в свете развития возможностей технологии — это не костыль.

Вот костыль:
someAsyncFunction(function(err, result){
    if (err) return callback(err); // <-- костыль
})


Нет костыля:
try {
    // костыль? а call, apply, bind - тоже костыли?
    var result = someAsyncFunction.sync();
}
catch (e) {
    // нет костыля
}


> Люблю Javascript и не хочу чтобы отношение к нему стало такое же как к PHP сейчас.
Я тоже люблю Javascript. Но то, что вы будете называть костылями новые его возможности, явно ему не поможет )

> Сейчас есть шанс, что Node.JS превратится в подобие PHP, появятся толпы говноскриптеров, которые прочитали только как вывести alert и побежали сайты создавать.
ниасилят, имхо
Как минимум,
Код должен отражать выполняемую задачу при минимальном количестве «шума».
Бонус — у node-sync меньше шума.
Не дублирует, а абстрагирует.
Тогда функциональное программирование в целом — это один большой костыль?

Библиотека Seq — костыль?
Ну, а что нелогичного в том, чтобы у функции в прототипе был метод sync (аналогичный call и apply), который будет абстрагировать вас от коллбэков?
var fs = require('fs');
var exec = require('child_process').exec;
var Seq = require('seq');

Seq()
    .seq(function () {
        exec('whoami', this)
    })
    .par(function (who) {
        exec('groups ' + who, this);
    })
    .par(function (who) {
        fs.readFile(__filename, 'ascii', this);
    })
    .seq(function (groups, src) {
        console.log('Groups: ' + groups.trim());
        console.log('This file has ' + src.length + ' bytes');
    })
;

vs
var fs = require('fs');
var exec = require('child_process').exec;
var Sync = require('sync');

Sync(function(){
    var who = exec.sync(null, 'whoami'); // seq
    var groups = exec.future(null, 'groups ' + who); // par
    var src = fs.readFile.future(null, __filename, 'ascii'); // par
    console.log('Groups: ' + groups.result.trim());
    console.log('This file has ' + src.result.length + ' bytes');
})

(результат идентичен, groups и src работают параллельно)

А в следующей версии планирую добавить автоматическое преобразование объектов:
var Sync = require('sync');
var fs = Sync(require('fs'));
var cp = Sync(require('child_process'));

Sync(function(){
    var who = cp.exec('whoami'); // seq
    var groups = cp.execFuture('groups ' + who); // par
    var src = fs.readFileFuture(__filename, 'ascii'); // par
    console.log('Groups: ' + groups.result.trim());
    console.log('This file has ' + src.result.length + ' bytes');
})
> Для node.js это получается костыльно-ориентированное программирование
А как вы назовете тогда соглашение о том, что «callback всегда должен быть последним и ошибку принимать первым агрументом»?
В реализации node-fibers для v8, может работать только один поток в один момент времени.
> О преимуществах fiber c нейтивной yeild и их use case'ах я не услышал.
так о чем мы вообще говорим?

> ничего некорректного в обычной обработке нет
а я говорил, что есть?

> Далее, к третьей проблеме, расширение базовых прототипов это реально плохая идея.
Согласен. Но это чертовски удобно.

Да, и вправду, это syntactic sugar, заисключанием парочки нюансов, о которых вы не знаете (всего-то).
Честно говоря, я рассчитывал на бóльшую компетентность читателей.
Вы перед тем, как писать такой комментарий, лучше бы изучили вопрос по подробнее. «Претендуешь — соответствуй».
Это yield — поддержка программных прерываний потока без глобальной блокировки процесса. Найдите мне 10 библиотек, использующих нативный yield.

Если collection.find.sync(collection, {'_id':new ObjectID(«aaaaaaaaaaaa»)) вернет err первым аргументом в callback, который передает ему sync(), то этот err вылетит в поток. Если он не будет словлен потоком, то err попадет в callback, который мы передаем в Sync(fn, callback).

Простой пример:
// Обычная асинхронная функция, вызывает callback через 1 сек с ошибкой
function someAsyncFunction(callback) {
    setTimeout(function(){
        callback('something went wrong');
    }, 1000)
}

// Вариант 1
// Новый поток
Sync(function(){
    try {
        // вызываем функцию синхронно, птичка вылетит отсюда
        someAsyncFunction.sync(); 
    }
    // ловим ошибку. в catch. правда.
    catch (e) {
        console.log(e); // something went wrong
    }
})

// Вариант 2
Sync(function(){
    
    // вызываем функцию синхронно
    someAsyncFunction.sync();

    // или вот так
    throw new Error('something went wrong');

}, function(err){
    // Ловим здесь любой exception из текущего потока
    console.log(e); // something went wrong
})


В примере со статьи, любая ошибка, вылетевшая из любой вызванной там функции, попадет в результирующий callback:
function syncFunction() {
    // 
    // внутри очень красивый синхронный код
    // отсюда можно throw
    // любая ошибка из sync() = throw = попадет в результирующий callback
    // 
}.async()

syncFunction(function(err){
    console.log(err); // вот сюда
})

> Пример не удачен, хотя в ноде и не мало мест где можно далеко уйти с колбеками.
Дайте пример лучше — обновлю статью.
Пример аналогичного неблокирующего веб-серева с использованием fibers (библиотека node-sync):

var Sync = require('sync');

http.createServer(function (req, res) {
    
    // Very simple and dangerous check
    var filename = req.url.replace(/\?.*/, '').replace(/(\.\.|\/)/, '');
    
    // Start new fiber
    Sync(function(){
        
        // Read file from disk
        var filecontent = fs.readFile.sync(fs, filename, 'utf8');
        var str = func1_cb.sync(null, filecontent);
        var hash = func2_cb.sync(null, str);
        
        res.writeHead(200, {'Content-Type': 'text/plain'});
        res.end(hash);
        
    }, function(err){

        // Error handling
        if (err) {
            res.writeHead(404, {'Content-Type': 'text/plain'});
            res.end(err);
        }
    })
    
}).listen(8124, "127.0.0.1");


Было бы интересно сравнить производительность данного подхода.
> У любого решения есть недостатки. Какие вы видите недостатки вашего решения?
все же
var result = someObject.someFunction.sync(someObject, arg1, arg2)

не на столько удобно, как:
var result = someObject.someFunction(arg1, arg2)

но в любом случае, удобнее чем:
someObject.someFunction(arg1, arg2, function(err, result){
    if (err) return callback(err);
})

> Ваш «реальный» код требует рефакторинга, имхо. Тогда он будет более читабельный.
слегка упростил пример

Information

Rating
Does not participate
Location
Киев, Киевская обл., Украина
Registered
Activity