LINUX.ORG.RU

Нестандартное использование try/catch/throw

 


0

1

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

tst=function(arr, wanted){
try{
arr.forEach(function(el){if(el===wanted) throw el})
}catch(e){return e}
}

tst([1,2,3], 2)// 2
tst([1,2,3], 5)// undefined
Тут конечно, картину портит try, который тут, по-сути, не нужен, хорошо бы было, если бы throw/catch могли работать самостоятельно, как в лиспах, но, тем не менее, фича эта работает в js.

Ответ на: комментарий от anonymous

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

linux-101
() автор топика
Ответ на: комментарий от deep-purple

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

Потом, многие думают что эксепшены это вообще зло т.к. они, по сути, отдельный поток управления в программе. Эдакий GOTO, только страшнее т.к. заранее не знаешь куда оно прилетит :). Это может быть хорошо для обработки ошибок. А вот логику программы на этом строить... Адъ.

true_admin ★★★★★
()
Ответ на: комментарий от noomorph

С какого куя она упадет? Наоборот возрастет, а в ряде случаев, возрастет на 100%. Ты прерываешь обход массива здесь в произвольном месте. В любом случае, упасть она никак не может

anonymous
()

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

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

Hater ★★
()
Ответ на: комментарий от linux-101

Вьізов дополнительной функции (foreach vs for) при обходе пол ляма елементов єто охренеть какая дорогая операция. Поверь мне

ZuBB ★★★★★
()
Ответ на: комментарий от Hater

Во-первых, как уже было сказано, из-за этого падает производительность

Можна огласить все строки/места которьіе влияют на производительность? //нужно для самопроверки

ZuBB ★★★★★
()
Ответ на: комментарий от ZuBB

влияют

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

anonymous
()
Ответ на: комментарий от anonymous

Если мьі говорим о производительности и пол ляма айтемов — то да, втаком случае лучше забьіть

ZuBB ★★★★★
()
Ответ на: комментарий от noomorph

Речь ниже о V8.

Ога, особенно для V8 актуально


test=function(fu, name){
console.time(name)
fu()
console.timeEnd(name)
}

function with_try(arr, wanted){
try{
arr.forEach(function(el){if(el===wanted) throw el})
}catch(e){return e}
}

function without_try(arr, wanted){
var result
arr.forEach(function(el){if(el===wanted) result=el})
return result
}

arr=["a", {foo: "bar"}, 3]
i=10000000
while(i--){arr.push(i)}


test(function (){with_try(arr, 3)}, "with_try")
test(function (){without_try(arr, 3)}, "without_try")


//firefox
//with_try: timer started start_page.html:20
//with_try: 0.53ms start_page.html:22
//without_try: timer started start_page.html:20
//without_try: 610.57ms

//chrome:
//with_try: 0.000ms start_page.html:22
//without_try: 1592.000ms 

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

anonymous
()
Ответ на: комментарий от noomorph

V-8 щас вообще превратился в тормозное говно, у них оптимизация головного мозга. Выложат пару синтетических тестов специально подогнанных под специфику компилятора, а миллион хомячков дрочат.

anonymous
()
Ответ на: комментарий от anonymous

ну так добавь обычный for. для полноты картины

ZuBB ★★★★★
()
Ответ на: комментарий от noomorph

это все хорошо но у меня двигло от ишака :(

ZuBB ★★★★★
()
Ответ на: комментарий от true_admin

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

anonymous
()
Ответ на: комментарий от true_admin

низя. циклы используют лохи. а anonimius^Wнормальные пацаны юзают кавайные foreach/filter/map/etc

ZuBB ★★★★★
()
Ответ на: комментарий от ZuBB

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

anonymous
()
Ответ на: комментарий от anonymous

я сказал об оптимизации ибо ТС говорил о примере с 0.5М айтемов. хотя в предыдущем сообщении я вроде как не о оптимизации говорил. я имел ввиду это сообщение

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

Потом, многие думают что эксепшены это вообще зло т.к. они, по сути, отдельный поток управления в программе. Эдакий GOTO, только страшнее т.к. заранее не знаешь куда оно прилетит :). Это может быть хорошо для обработки ошибок. А вот логику программы на этом строить... Адъ.

ZuBB ★★★★★
()
Ответ на: комментарий от anonymous

Проверь с Array.prototype.find, и тест твой вообще некорректный.

noomorph
()

давайте я вам дам более реальный пример

вар №1

Task.prototype.setGraphicPoints = function(specObj, graphic, params) {
    var _1axis = this.defaultKeys[0];
    var _2axis = this.defaultKeys[1];
    var length = specObj[_2axis].length;
    var prevYValue = null;

    for (var jj = 0, x, y; jj < length && Host.CanContinue(); jj++) {
        if (params.graphicType === 'sidestep' && prevYValue !== null) {
            graphic.AddPoint(specObj[_1axis][jj], prevYValue);
        }

        x = specObj[_1axis][jj];
        y = specObj[_2axis][jj];

        try {
            if (params.graphicType === 'multicolor') {
                graphic.AddColorPoint(x, y, specObj.color[jj]);
            } else {
                graphic.AddPoint(x, y);
            }
        } catch (e) {
            //DEBUG_START
            _e(jj, 'got a NaN insead of number at');
            _i(x, '`' + _1axis + '` equals to');
            _i(y, '`' + _2axis + '` equals to');
            continue;
            //DEBUG_STOP

            this.addBug({'message': 'core.messages.error1', 'onetime': true});
            continue;
        }

        prevYValue = specObj[_2axis][jj];

        if (this.drawMarkers) {
            this.drawMarker(specObj[_1axis][jj] * Host.Frequency, '');
        }
    }

    return true;
};

вар №2

Task.prototype.setGraphicPoints = function(specObj, graphic, params) {
    var _1axis = this.defaultKeys[0];
    var _2axis = this.defaultKeys[1];
    var length = specObj[_2axis].length;
    var isXValueInvalid = null;
    var isYValueInvalid = null;
    var prevYValue = null;

    for (var jj = 0, x, y; jj < length && Host.CanContinue(); jj++) {
        if (params.graphicType === 'sidestep' && prevYValue !== null) {
            graphic.AddPoint(specObj[_1axis][jj], prevYValue);
        }

        x = specObj[_1axis][jj];
        y = specObj[_2axis][jj];

        isXValueInvalid = isNaN(parseFloat(x)) || !isFinite(x);
        isYValueInvalid = isNaN(parseFloat(y)) || !isFinite(y);

        if (isXValueInvalid || isYValueInvalid) {
            //DEBUG_START
            _e(jj, 'got a NaN insead of number at');
            _i(x, '`' + _1axis + '` equals to');
            _i(y, '`' + _2axis + '` equals to');
            continue;
            //DEBUG_STOP

            this.addBug({'message': 'core.messages.error1', 'onetime': true});
            continue;
        }

        if (params.graphicType === 'multicolor') {
            graphic.AddColorPoint(x, y, specObj.color[jj]);
        } else {
            graphic.AddPoint(x, y);
        }

        prevYValue = specObj[_2axis][jj];

        if (this.drawMarkers) {
            this.drawMarker(specObj[_1axis][jj] * Host.Frequency, '');
        }
    }

    return true;
};

какой вариант будет работать быстрее? что еще можна подкрутить?

условия: кол-во елементов 100 - 10000, свойство «color» отсутсвует, drawMarkers установл в 0. рантайм JS VM из IE. поддержка начиная с восьмой версии и далее. если вам будет легче примите что «graphicType» не равно 'sidestep'

интересует скорость

ZuBB ★★★★★
()
Последнее исправление: ZuBB (всего исправлений: 3)
Ответ на: комментарий от anonymous

выход из рекурсивного поиска элементов по дереву

Если я правильно понял о чем ты то это отлично делается без эксепшенов.

def find(root, node):
  if root == node: return node
  return find(root.left, node) or find(root.right, node)

Не, ну если глубина дерева адовая то эксепшеном, конечно, быстрее..

true_admin ★★★★★
()
Ответ на: комментарий от linux-101

я имею в виду, покажи, где без этого никак, а не «сатрите, пасаны, я написал линейный поиск через жопу!».

anonymous
()
Ответ на: комментарий от anonymous

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

linux-101
() автор топика
Ответ на: комментарий от linux-101

Знаешь, мне больше всего нравится то, что предлагалка похожих тредов предлагает твои же. Не за горами тот день, когда мы сможем-таки тебя отсеять)

anonymous
()

Во многих языках можно использовать try catch таким образом, но только это нерационально ни разу, каждый вход в try - новый дамп с стеке. А переписать это без try catch, как правило, несложно.

Aswed ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.