Пользователь
0,0
рейтинг
26 февраля 2011 в 02:23

Разработка → Используем console на полную перевод

Метод console.log() — отличный способ вывести отладочную информацию, не мешая пользователю. Но знаете ли Вы, что объект console имеет еще уйму других не менее полезных методов? Очень редко разработчики используют этот функционал, ограничиваясь неблокирующим alert'ом. Что-ж, давайте исправим это положение.


Небольшое примечание: использование отладочного кода может негативно сказаться на производительности. Удаляйте его из продакшн версии.

Больше, чем просто сообщения


Перед тем, как погрузиться в малоизвестные методы console, рассмотрим функционал console.log подробнее. Например, возможность передачи любого числа аргументов:
var foo = {baz: "tubular", goo: "rad"}, bar = "baz";
console.log("string",1,foo.goo,bar,foo.baz); // string 1 rad baz tubular


В результате все переданные аргументы будут выведены и разделены пробелом. Это, конечно, хорошо, но было бы еще лучше, если бы мы могли как-нибудь вывести все эти аргументы в виде красиво отформатированного сообщения. Хотя, постойте… мы можем!

Если Вы знакомы с функцией printf() в других языках, то спешим обрадовать: console.log() умеет вести себя похожим образом. Возьмем последний пример и передадим первый аргумент в немного измененном виде.
var foo = {baz: "tubular", goo: "rad"}, bar = "baz";
console.log(
     "%s theory is %d %s concept. I can only describe it as %s and %s",
      "string", 1, foo.goo, bar, foo.baz 
);
// string theory is 1 rad concept. I can only describe it as baz and tubular


Что за %s?

Отличный вопрос! Это управляющие последовательности, которые заменяются на соответствующие им значения (в порядке очередности). %s означает «трактовать значение как строку», %d — как число (Также можно использовать %i или %f).

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

Порядок использования аргументов можно изменить вручную, использовав символ $ и приписав перед ним номер аргумента, который мы хотим вывести:
var foo = {baz: "tubular", goo: "rad"}, bar = "baz";
console.log(
     "%2$d theory is %d %s concept. I can only describe it as %s and %s",
     "string",1,foo.goo,bar,foo.baz
);
// 1 theory is 0 baz concept. I can only describe it as tubular and %s string


Эта команда как бы говорит «Я начну со второго аргумента и продолжу, начиная со следующего». Как Вы видите, последовательности, которым не хватило аргументов, остались нетронутыми.

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

Чтобы это исправить, можно изменить формат строки таким образом, чтобы «указатель» не следующий элемент синхронизировался со списком аргументов в определенный момент. Тогда все будет работать как положено.
var foo = {baz: "tubular", goo: "rad"}, bar = "baz";
console.log(
     "%2$d theory is %1$s %3$s concept. I can only describe it as %s and %s",
     "string",1,foo.goo,bar,foo.baz
);
// 1 theory is string rad concept. I can only describe it as baz and tubular


Для того, чтобы аргументы были выведены правильно, нам нужно изменить порядок вывода второго и третьего элементов. Другие элементы и так в правильном положении, так что нет необходимости указывать их позиции. Аргументы будут использованы в следующем порядке: 2, 1, 3, 4, 5.

Форматирование строк — мощный инструмент, и я охватил только вершину айсберга. Попробуйте поиграться самостоятельно и почитать, что пишет Joe Hewitts о консоли.

Различные типы сообщения


Есть еще пара методов, подобных log, но отличающихся внешне. А именно: console.info(), console.warn() и console.error().
console.info("%s numbers %d, %d and %d","hello",1,2,3); // hello numbers 1, 2 and 3
console.warn("%s numbers %d, %d and %d","hello",1,2,3);
console.error("%s numbers %d, %d and %d","hello",1,2,3);

console.info(), console.warn() и console.error() в Firebug'е.

Все три метода умеют выводить строки в соответствие с форматом и принимать любое количество аргументов.

Логи DOM'а


Когда Вам нужно как-то указать в логах на DOM узел лучшего всего использовать методы console.dir() или console.dirxml(), которые могут перечислить свойства элемента или вывести HTML кода элемента.
console.dir(document.documentElement);
console.dirxml(document.documentElement);

Знакомьтесь: console.dir() и console.dirxml() в Chrome.

Группировка


Иногда бывает полезно сгруппировать логи для упрощения работы с ними. Для этого существуют методы console.group(), console.groupCollapsed() и console.groupEnd().
console.group("Overlord");
console.log("Overlord stuff");
 
console.group("Lord");
console.log("Overlord stuff");
 
console.group("Minion");
console.log("Minion stuff");
console.groupEnd();
 
console.groupCollapsed("Servant");
console.log("Servant stuff");

Группировка в консоли Safari.

Как Вы можете видеть, подряд идущие вызовы group создают вложенные папки. Чтобы закрывать папку, используйте метод console.groupEnd(). Метод console.groupCollapsed() аналогичен console.group() за тем лишь исключением, что группа со всем содержимым будет изначально свернута.

Профилирование и замеры


Также консоль позволяет точно замерять время, используя метод console.time() и console.timeEnd(). Расположите вызов первого из них перед кодом, время исполнения которого хотите замерить, а второго — после.
console.time("Execution time took");
// Some code to execute
console.timeEnd("Execution time took");

Пример работы console.time() и console.timeEnd() в Firefox

Таймеры связаны между собой метками (передаются первым аргументом и могут быть любой строкой), так что Вы можете запустить несколько таймеров одновременно. Когда сработает console.timeEnd(), будет выведено сообщение с меткой и прошедшим временем в миллисекундах.

Помимо замера времени можно профилировать Ваш код и вывести стек профилирования, который подробно показывает, где и сколько времени потратил браузер.
console.profile();
// Some code to execute
console.profileEnd();

Профилирование в Chrome.

Assert'ы


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

Assert'ы позволяют обеспечивать соблюдение правил в коде и быть уверенным, что результаты выполнения этого кода соответствуют ожиданиям. Метод console.assert() позволяет проводить элементарное тестирование кода: если что-то пойдет не так, будет выброшено исключение. Первым аргументом может быть все, что угодно: функция, проверка на равенство или проверка существования объекта.
var a = 1, b = "1";
console.assert(a === b, "A doesn't equal B");

Assert в Chrome

Метод assert принимает условие, которое является обязательным к выполнению (в данном случае простая строгая проверка на равенство) и, вторым аргументом, сообщение, которое будет выведено в консоль вместе с выброшенным исключением, если первое условие не будет выполнено.

Поддержка браузерами


Большинство перечисленных методов поддерживаются достаточно хорошо. IE8+, Firefox с расширением firebug, Opera или webkit-браузер вроде Safari или Chrome. Есть, правда, некоторые различия: Firefox, Safari и Chrome отличаются более широкой поддержкой. Проще всего проверить совместимость можно выполнив console.dir(console), результатом которого будет вывод объекта console со всеми его методами.

Opera с Dragonfly поддерживает большинство методов, за исключением форматирования строк и профилирования (хотя методы profile, profileEnd и реализованы, это всего лишь заглушки).

IE8 также поддерживает много вкусностей, включая форматирование строк и assert'ы, но не замеры времени, профилирование, методы dir или dirxml.

Стоит отметить, что firebug lite может добавить некоторые методы к console в браузерах, их не поддерживающих.

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

Extra


Итак, это был очень вольный перевод статьи, но теперь я бы хотел добавить немного от себя:
Node.JS (ветка 0.2) поддерживает методы log, info, warn, error, dir, time / timeEnd, assert и trace.
log не умеет изменять порядок аргументов для подстановок, но сами подстановки реализованы. При вызове метода trace в консоль будет выведен стек вызовов (все методы ничего не возвращают, а просто пишут в консоль). Работает это также как минимум в Chrome и Opera.

В Opera и Chrome, помимо уже перечисленных, реализованы следующие методы:
count — выводит, сколько раз уже выполнялась строка, на которой расположен вызов метода. Аргументом передается строка, которая будет выведена перед количеством вызовов.
debug — ничем не отличается от log.

В Опере также есть метод table, который должен строить красивую табличку из аргументов, но ничего не делает.
Вообще, Опера немного странновата. Результаты работы обсуждаемых функций нужно искать не в стандартной консоли, а на просторах Dragonfly (впрочем, это логично). Причем часть из них можно найти сразу в двух местах: на вкладке «Консоль ошибок» и «Скрипты» -> REPL.

Также в Chrome у объекта console есть свойство memory, являющееся объектом со свойствами totalJSHeapSize и usedJSHeapSize. Однако, в Chromium'е мне так и не удалось застать эти свойства со значениями, отличными от нуля.
Перевод: Ryan Seddon
B@rmaley.e⪥e @barmaley_exe
карма
89,0
рейтинг 0,0
Пользователь
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое Разработка

Комментарии (29)

  • +11
    Спасибо, неплохой обзор.
    Я пару недель назад сделал для дебага js универсальную функцию на базе console, которая представляет объекты используя метод dir, а простые типы с помощью log. Т.е. в самом общем случае не нужно писать 'console.log', а допустим 'clog' или просто 'c'. Думаю некоторые разработчики из лени пишут 'alert' потому что там меньше символов.

    Но все не так просто, я сделал поддержку браузеров которые не поддерживают например метод dir (IE7-8, да и в 9 он более похож на метод Object.toSource), а также вывод в виде html.

    Парa скриншотов:
    Передан объект
    Передан объект

    Передан html объект
    Передан html объект

    Вывод в html
    Вывод в html

    А вот так выглядит функция в ИЕ
    Консоль в ИЕ

    Есть параметры для настройки функции. С её помощью например я очень быстро освоил raphael.js почти без документации.

    Будет ли хабраобществу интересно если я напишу её обзор с приведением кода, а также в сравнении с другими похожими консолями?
    • 0
      Из за разности во времени на вопросы (если будут) смогу ответить только вечером.
      • 0
        Пробовали использовать ключевое слово «debugger»?
        • 0
          Спасибо. Попробовал и оценил возможности. Обязательно посмотрю внимательнее на сей инструмент. Но мне кажется или это все же больше для дебага текущего контекста, а не для инспектирования чего-либо в js (конечно там можно смотреть структуры, но все же)?
          • 0
            Ну, по-моему его можно использовать почти для всего)
    • +1
      Да, будет весьма интересен и рабочий код, и сравнение с альтернативами. Все мы так или иначе делали свои варианты консолей (у меня была просто на чистом JS в плавающем диве, таскаемом за заголовок).
      • 0
        Спасибо, начинаю готовить статью :)
  • +24
    Как раз недавно в твиттере наткнулся на прикольный код:
  • +3
    Кто чего поддерживает лучше сделать таблицей.
  • 0
    > Порядок использования аргументов можно изменить вручную, использовав символ $ и приписав

    Символ %.
    • 0
      Черд. Невнимательно читал:)
  • +1
    Хороший перевод…
    Только если уж использовать для отладки FireBug то надо пользоваться не только алертами)
    getfirebug.com/wiki/index.php/Command_Line_API
  • НЛО прилетело и опубликовало эту надпись здесь
  • 0
    Простите, немного не в тему, а киньте ктонить нормальной реализацией sprintf в Javascript.
  • 0
    Еще думаю стоит заметить что console.log в некоторых броузерах (Chrome, FireFox точно) без ошибки отрабатывают при закрытой консоли, а тот же IE выдает ошибку.

    Просто в связи с этим возникали ошибки: забывали убрать console.log, в Chrome/FF работало все нормально, а в IE ошибка.
    • 0
      Видимо это связанно с устройством встроенной консоли. В стабильной ветке Firefox'а все еще есть ошибка, а в бетках 4-ой ее уже нет, но есть встроенная консоль. Видимо в ie дела обстоят как-то иначе, но как ведет себя ie9 я не знаю… Может кто просветит?
      • 0
        +500 насчет «не работает в стабильной версии». Причем я помню, что относительно недавно в 3-их ФФ с закрытой консолью ещё все срабатывало безошибочно, но не сейчас. Не далее как в начале года насткнулся на именно такой «глюк» — именно из-за неубранного console.log в приложении, открытом на клиентском компьютере не срабатывал полностью скрипт.
        • +1
          Именно потому я пользуюсь такой ф-цией:
          function log () {
              return 'console' in window ? console.log.apply(console, arguments) : null;
          }
          
          • +4
            А я ставлю затычку из методов:
            if (!window.console)
            {
                window.console = {
                    log : function(){},
                    dir : function(){}
                    ....
                }
            }
            
            • 0
              Еще вариант, автоматически активировать консоль если текущий домен выглядит как локальный (чегото-там.local), и глушить затычками если он нелокальный. Ведь отладку делаем обычно на локальных серверах.
          • 0
            Оу, вот этот вариант лучше.
        • 0
          Кстати, о затычках.

          Из готовых решений есть ещё такой кроссбраузерный вариант: Complete cross-browser console.log() с подробным описанием всех решаемых проблем и тестовая страница, где можно сразу увидеть/проверить результат работы во всех браузерах.

          При подключении consolelog.js обратите внимание на то, что этот скрипт не переопределяет уже имеющуюся функцию log() (это может были либо ваша, либо из другой подобной затычки).
  • +3
    Вопрос.
    Напихали мы в свой большой JavaScript проект десятки или даже сотни отладочных и дебагерских вызовов к консоли. А какой самый удобный способ убрать их из релиза?

    Сходу в голову приходит вариант сделать Replace по все JS файлам.
    Или сделать собственный объект console, в котором все методы ничего не делают, и тогда console вызовы можно оставить в коде.

    Может быть есть какие то более приятные варианты?
    • +6
      Переопределение консоли — вполне неплохой вариант. Тем более, можно определить её так:
      new function () {
        var debug    = true;
        var original = window.console;
        window.console = {};
        ['log', 'dir', ...].forEach(function (method) {
          console[method] = function () {
            return (debug && original) ? original[method].apply(original, arguments), 
          }
        });
      };
      


      И проблему с неопределенной консолью решите и легко отключается дебаг.
  • +1
    Стоит добавить что в Chrome есть:
    • переменная $0 всегда равна выбраному елементу на вкладке Elements (или document.body, если ничего не выбрано)
    • функция copy() копирует текст в буфер обмена (например copy(document.body.innerText))
    • функция inspect() переключает на вкладку Elements где автоматически выбирается нужный елемент (например inspect(document.body))
  • 0
    Есть еще такой вариант:

    (function(__global){
        if (!__global.console || (__global.console && !__global.console.log)) {
             __global.console = {
    	     log: (__global.opera && __global.opera.postError)
                 ? __global.opera.postError
    	     : function(){ }
            }
        }
    })(this);
    


  • 0
    Удобно включать режим отладки из адресной строки, например дописывая в неё #console

    if(typeof allow_console == 'undefined'){
       var allow_console= false;

       var hash = location.hash;
       if(hash.indexOf('#console')!=-1){
         allow_console = true;
       }
    }
    if(allow_console==true){
      console.log('Режим отладки включен');
    }

  • 0
    Вот детальнее о профилировании в Google Chrome — http://habrahabr.ru/post/149053/

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