На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
Модераторы: ElcnU, ANDLL, fatalist
  
> AsyncFuncDemo
    Без масты тут опять все зарасло :D

    - Маста! а как написать асинхронную функцию :huh:

    Хароши вопрос новичек! :D
    вот как будет знаменитая функция фиббоначи:
    ExpandedWrap disabled
      class AsyncFuncDemo {
          // async function
          asyncFib(n, callback) {
              if (typeof(callback) !== 'function') callback = null;
       
              if (typeof(n) !== 'number')
                  return callback(new Error('First arg missing or not a number.'));
              
              process.nextTick(() => {
                  // Block on CPU
                  var value = this.fib(n);
                  callback(null, value);
              });
          }
       
          fib(n) {
              if (n < 2) return n;
              return this.fib(n-1) + this.fib(n-2);
          }
      }
       
      var demo = new AsyncFuncDemo();
      var number = 42;
       
      demo.asyncFib(number, function (err, value) {
          if (err) return console.log(err);
          console.log('fibonaci value for %d is %d', number, value);
      });
       
      console.log('called asyncFib...');
      console.log('called sync fib: ', demo.fib(number));
      // called asyncFib...
      // called sync fib:  267914296
      // fibonaci value for 42 is 267914296
      Цитата Cfon @
      Без масты тут опять все зарасло


      Неотвеченный вопрос есть здесь.
        Цитата ya2500 @
        Неотвеченный вопрос есть здесь.

        без понятия :D

        - Маста, а как сделать саму функцию fib асинхронной?
        - ну я имею ввиду чтобы она вычислялась не блокируя I/O :huh:
        Новичок есть несколько приемов первое написать дополнение Node на С/C++ с использованием потоков или переписать саму функцию fib таким образом чтобы она периодически проверяла I/O.

        - А можно примерчик? :scratch:

        Добавлено
        Вот например
        ExpandedWrap disabled
          class AsyncFuncDemo {
              async asyncFib(n) {
                  if (typeof(n) !== 'number')
                      return new Error('First arg missing or not a number.');
           
                  if (n < 2) return n;
           
                  const fib1 = () => new Promise(resolve =>
                      process.nextTick(() => resolve(this.asyncFib(n-1)))
                  );      
                  const fib2 = () => new Promise(resolve =>
                      process.nextTick(() => resolve(this.asyncFib(n-2)))
                  );
                  return await fib1() + await fib2();  
              }
           
              fib(n) {
                  if (n < 2) return n;
                  return this.fib(n-1) + this.fib(n-2);
              }
          }
           
          var demo = new AsyncFuncDemo();
          var number = 25;
           
          demo.asyncFib(number).then(result => {
              console.log('fibonacci value for %d is %d', number, result);
          });
           
          console.log('called asyncFib...');
          console.log('called sync fib: ', demo.fib(number));
           
          // called asyncFib...
          // called sync fib:  75025
          // fibonacci value for 25 is 75025

        Суть в том, что надо каждую часть вычисления заключить в process.nextTick тогда I/O не будет блокироваться жестко на время вычисления тяжелой функции.

        Вместо async/await и промисов можно заюзать библу async.

        - А можно примерчик? :huh:
        Можно Машку за ляжку :lool: попробуй сделать это сам :D

        - Ok Маста а почему вы вычисляли фибоначи от 25 а не 42 как в предыдущем примере?
        Заметил таки :D просто от 42 долго вычисляется :D
        Можно ускорить вычисления, убрав из fib1 process.nextTick.

        - Это как? :huh:
        А вот так :D
        ExpandedWrap disabled
          .....
              async asyncFib(n) {
                  if (typeof(n) !== 'number')
                      return new Error('First arg missing or not a number.');
           
                  if (n < 2) return n;
           
                  const fib2 = () => new Promise(resolve =>
                      process.nextTick(() => resolve(this.asyncFib(n-2)))
                  );
                  return await this.asyncFib(n-1) + await fib2();  
              }
          .....
        Сообщение отредактировано: Cfon -
          Проверил асинхронность в действии создал Express сервер и что вы думаете через process.nextTick асинхронности нет! Делаю два запроса и оба висят!
          Заменил на setImmediate теперь все пучком! :D
          ExpandedWrap disabled
            const express = require('express');
            const async = require('async');
            const { performance } = require('perf_hooks');
             
            class AsyncFuncDemo {
                async asyncFib(n) {
                    if (n < 2) return n;
             
                    const fib1 = () => Promise.resolve(this.asyncFib(n-1));
                    const fib2 = () => new Promise(resolve =>
                        setImmediate(() => resolve(this.asyncFib(n-2)))
                    );
             
                    return await fib1() + await fib2();  
                }
             
                fib(n) {
                    if (n < 2) return n;
                    return this.fib(n-1) + this.fib(n-2);
                }
            }
             
            const app = express();
             
            app.get('/:number', function (req, res) {
                var time = performance.now();
                var demo = new AsyncFuncDemo;
                var number = req.params.number;
             
                demo.asyncFib(number).then(result => {
                    console.log('fibonacci value for %d is %d', number, result);
                    time = performance.now() - time;
                    console.log('Время выполнения = ', time);
                    res.send('<h1>Fibonacci value: ' + result + '</h1>');
                });
            });
             
            app.listen(3000, function () {
                console.log('Test-server is running on port 3000');
            });
          Сообщение отредактировано: Cfon -
            - Маста, а можно ускорить вычисление числа фибоначи? :huh:
            Да конечно можно :)
            Можно применить так называмую мемоизацию результатов вычисления тем самым у нас в разы уменьшится количество вычислений.
            - Как это? :scratch:
            Например
            ExpandedWrap disabled
              class AsyncFuncDemo {
                  constructor() {
                      this.asyncFib = (function () {
                          var numbers = [0, 1];
                          return async function (n) {
                              const fib1 = () => Promise.resolve(this.asyncFib(n-1));
                              const fib2 = () => new Promise(resolve =>
                                  setImmediate(() => resolve(this.asyncFib(n-2)))
                              );
                              var num = numbers[n];
                              if (typeof(num) === 'undefined') {
                                  num = await fib1() + await fib2();  
                                  numbers[n] = num;
                              }
                              return num;  
                          }
                      })();
                  }
              .....

            Я перенес определение асинхронной функции в конструктор поскольку в классе нельзя производить вычисления. Они нам нужны поскольку я использую iife.
            Правда теперь юзать такую оптимизированую функцию для демонстрации асинхронного вычисления не имеет смысла, поскольку она синхронно вычисляется очень быстро для любого значения :D
            Сообщение отредактировано: Cfon -
              Возникла трабла при тестировании :huh:
              Запускаю сервер, далее запускаю Хром, печатаю http://localhost:3000/10 и что вы думаете результат выводит все пучком, но в консоле пишет вот это:
              ExpandedWrap disabled
                (node:652) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 2): RangeError: Maximum call stack size exceeded
                (node:652) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
              Сообщение отредактировано: Cfon -
                Вставил проверку catch в промис
                ExpandedWrap disabled
                  demo.asyncFib(number).then(result => {
                          console.log(`fibonacci value for ${number} is ${result}`);
                          res.send(`<h1>Fib: ${result}</h1>`);
                      })
                      .catch(err => console.log(err));

                Теперь выхлоп такой
                ExpandedWrap disabled
                  RangeError: Maximum call stack size exceeded
                      at AsyncFuncDemo.asyncFib (/Users/cfon/workspace/javascript/examples/async-demo.js:56:43)
                      at fib1 (/Users/cfon/workspace/javascript/examples/async-demo.js:51:49)
                      at AsyncFuncDemo.asyncFib (/Users/cfon/workspace/javascript/examples/async-demo.js:56:36)
                      at fib1 (/Users/cfon/workspace/javascript/examples/async-demo.js:51:49)
                      at AsyncFuncDemo.asyncFib (/Users/cfon/workspace/javascript/examples/async-demo.js:56:36)
                      at fib1 (/Users/cfon/workspace/javascript/examples/async-demo.js:51:49)
                      at AsyncFuncDemo.asyncFib (/Users/cfon/workspace/javascript/examples/async-demo.js:56:36)
                      at fib1 (/Users/cfon/workspace/javascript/examples/async-demo.js:51:49)
                      at AsyncFuncDemo.asyncFib (/Users/cfon/workspace/javascript/examples/async-demo.js:56:36)
                      at fib1 (/Users/cfon/workspace/javascript/examples/async-demo.js:51:49)
                      at AsyncFuncDemo.asyncFib (/Users/cfon/workspace/javascript/examples/async-demo.js:56:36)
                      at fib1 (/Users/cfon/workspace/javascript/examples/async-demo.js:51:49)
                      at AsyncFuncDemo.asyncFib (/Users/cfon/workspace/javascript/examples/async-demo.js:56:36)
                      at fib1 (/Users/cfon/workspace/javascript/examples/async-demo.js:51:49)
                      at AsyncFuncDemo.asyncFib (/Users/cfon/workspace/javascript/examples/async-demo.js:56:36)
                      at fib1 (/Users/cfon/workspace/javaScript/examples/async-demo.js:51:49)

                Что за нафик! Результат то выводит правильно! :wall:
                Несколько раз проверял код функции asyncFib вроде все правильно :wacko:
                Сообщение отредактировано: Cfon -
                  Нашел баг :D
                  Вставил лог мидлварэ
                  ExpandedWrap disabled
                    app.use(function (req, res, next) {
                        console.log(`${req.method} ${req.url}`);
                        next();
                    });

                  получил
                  ExpandedWrap disabled
                    GET /10
                    fibonacci value for 10 is 55
                    GET /favicon.ico
                    RangeError: Maximum call stack size exceeded
                    .....

                  выходит что кроме основного Хром посылал еще и запрос /favicon.ico! :D
                  этот запрос обрабатывался одним и тем же get обработчиком.

                  Что делать?
                  Есть несколько решений первое заюзать регулярку для точной проверки url
                  ExpandedWrap disabled
                    app.get(/^\/(\d+)$/, function (req, res) {
                        var number = req.params[0];
                    .....

                  или вставить проверку isNaN в колбэк функцию:
                  ExpandedWrap disabled
                    app.get('/:number', function (req, res) {
                        var number = parseInt(req.params.number);
                        
                        if (isNaN(number)) {
                            return res.send();
                        }
                    .....

                  а можно проще
                  ExpandedWrap disabled
                    app.get('/:number', function (req, res) {
                        var number = parseInt(req.params.number) || 0;
                    .....
                  Сообщение отредактировано: Cfon -
                    - Маста, вот как будет на async :D
                    ExpandedWrap disabled
                      asyncFib(n, callback) {
                              if (n < 2) return callback(null, n);
                              async.series([
                                  cb => this.asyncFib(n-1, cb),
                                  cb => setImmediate(() => this.asyncFib(n-2, cb))
                              ], (err, results) => callback(null, results[0] + results[1]));
                          }

                    - Причем он немного быстрее чем на промисах :blink:

                    Епт Новичок! Ты не новичек! :D
                    Сообщение отредактировано: Cfon -
                    0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                    0 пользователей:


                    Рейтинг@Mail.ru
                    [ Script execution time: 0,0363 ]   [ 15 queries used ]   [ Generated: 24.04.24, 22:37 GMT ]