html текст
All interests
  • All interests
  • Design
  • Food
  • Gadgets
  • Humor
  • News
  • Photo
  • Travel
  • Video
Click to see the next recommended page
Like it
Don't like
Add to Favorites

«Лапша» из callback-ов — будьте проще

По следам недавних топиков, а также постоянных рассказов в стиле «мой стартап не взлетел, потому что его зохавала лапша из callback-ов».

Как раз недавно я закончил небольшой проект (ссылку не даю, чтобы не заподозрили — кому надо см. профиль), полностью и на всех этапах написанном только на JS, и притом полностью асинхронный. Разумеется, я столкнулся с пресловутой проблемой «лапши». И, вы не поверите, совершенно спокойно решил её без всяких там фреймворков и хитрых приемов.

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



exports.processRequest = function (request, response) {
    db.query('SELECT COUNT(id) FROM books', function (res1) {
        // do something
        db.query('SELECT * FROM books LIMIT ' + Number(limit) + ' OFFSET' + Number(offset), function (res2) {
            // do something 2
            db.query('SELECT * FROM bookData WHERE bookId IN (' + ids.join(', ') + ')', function (res3) {
                  // И вот наконец формируем как-то dataset
                  response.write(render(dataset));
            });
        });
    });
}


Если накинуть ещё пару-тройку промежуточных шагов, то всё станет совсем плохо.
Теперь зададим себе простой вопрос: зачем мы написали эту лапшу? Действительно ли нам необходимы здесь три вложенных замыкания?

Нет, конечно. У нас нет ровно никакой нужды из третьей анонимной функции иметь доступ к замыканиям второй и первой. Перепишем немного код:

exports.processRequest = function (request, response) {
    var dataset = {};
    
    getBookCount();

    function getBookCount () {
        db.query('SELECT COUNT(id) FROM books', onBookCountReady);
    }

    function onBookCountReady (res) {
        // ...заполняем dataset
        getBooks();
    }

    function getBooks () {
        db.query('SELECT * FROM books LIMIT ' + dataset.limit + ' OFFSET' + dataset.offset, onBooksReady);
    }

    function onBooksReady (res) {
        // ... заполняем dataset
        getMetaData();
    }

   function getMetaData () {
       db.query('SELECT * FROM bookData WHERE bookId IN (' + dataset.ids.join(', ') + ')', onMetaDataReady);
   }

   function onMetaDataReady (res) {
       // ... заполняем dataset
       finish();
   }

   function finish () {
      response.write(render(dataset));
   }
}


Пожалуйста. Код стал полностью линейным, и, что немаловажно, более структурированным; весь program flow у вас перед глазами, логические блоки кода оформлены отдельными функциями. Никаких фреймворков и хитрых синтаксисов. И никаких подводных камней — dataset замкнут в контексте обработки пары request-response, случайно залезть в какие-то разделяемые между request-ами данные не получится.

Всё немного усложняется, если нужно что-то запараллелить. У меня такой задачи не было, но если бы была (допустим, есть два набора метаданных), то я решал бы её так:

   function getMetaData () {
      var parallelExecutor = new ParallelExecutor({
          meta1: getMetaData1,
          meta2: getMetaData2
      });

      function getMetaData1 () {
          db.query('smthng', onMetaData1Ready);
      }

      function getMetaData2 () {
          db.query('smthng', onMetaData2Ready);
      }

      function onMetaData1Ready (res) {
          // заполняем dataset
          parallelExecutor.ready('meta1');
      }

      function onMetaData2Ready (res) {
          // заполняем dataset
          parallelExecutor.ready('meta2');
      }

     parallelExecutor.start(onMetaDataReady);
  }

  function onMetaDataReady () {
  }


Смысл всё тот же — создать отдельное замыкание для набора функций, который обычно объединяют в «лапшу», и расписать их последовательно.

Кажется, что в таком формате асинхронные callback-и не только не захламляют код, но и, напротив, делают его более структурированным и читабельным.
Читать дальше
Twitter
Одноклассники
Мой Мир

материал с habrahabr.ru

7

      Add

      You can create thematic collections and keep, for instance, all recipes in one place so you will never lose them.

      No images found
      Previous Next 0 / 0
      500
      • Advertisement
      • Animals
      • Architecture
      • Art
      • Auto
      • Aviation
      • Books
      • Cartoons
      • Celebrities
      • Children
      • Culture
      • Design
      • Economics
      • Education
      • Entertainment
      • Fashion
      • Fitness
      • Food
      • Gadgets
      • Games
      • Health
      • History
      • Hobby
      • Humor
      • Interior
      • Moto
      • Movies
      • Music
      • Nature
      • News
      • Photo
      • Pictures
      • Politics
      • Psychology
      • Science
      • Society
      • Sport
      • Technology
      • Travel
      • Video
      • Weapons
      • Web
      • Work
        Submit
        Valid formats are JPG, PNG, GIF.
        Not more than 5 Мb, please.
        30
        surfingbird.ru/site/
        RSS format guidelines
        500
        • Advertisement
        • Animals
        • Architecture
        • Art
        • Auto
        • Aviation
        • Books
        • Cartoons
        • Celebrities
        • Children
        • Culture
        • Design
        • Economics
        • Education
        • Entertainment
        • Fashion
        • Fitness
        • Food
        • Gadgets
        • Games
        • Health
        • History
        • Hobby
        • Humor
        • Interior
        • Moto
        • Movies
        • Music
        • Nature
        • News
        • Photo
        • Pictures
        • Politics
        • Psychology
        • Science
        • Society
        • Sport
        • Technology
        • Travel
        • Video
        • Weapons
        • Web
        • Work

          Submit

          Thank you! Wait for moderation.

          Тебе это не нравится?

          You can block the domain, tag, user or channel, and we'll stop recommend it to you. You can always unblock them in your settings.

          • SLCH
          • домен habrahabr.ru

          Get a link

          Спасибо, твоя жалоба принята.

          Log on to Surfingbird

          Recover
          Sign up

          or

          Welcome to Surfingbird.com!

          You'll find thousands of interesting pages, photos, and videos inside.
          Join!

          • Personal
            recommendations

          • Stash
            interesting and useful stuff

          • Anywhere,
            anytime

          Do we already know you? Login or restore the password.

          Close

          Add to collection

             

            Facebook

            Ваш профиль на рассмотрении, обновите страницу через несколько секунд

            Facebook

            К сожалению, вы не попадаете под условия акции