Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[18.224.246.203] |
|
Сообщ.
#1
,
|
|
|
Без масты тут опять все зарасло
- Маста! а как написать асинхронную функцию Хароши вопрос новичек! вот как будет знаменитая функция фиббоначи: 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 |
Сообщ.
#3
,
|
|
|
без понятия - Маста, а как сделать саму функцию fib асинхронной? - ну я имею ввиду чтобы она вычислялась не блокируя I/O Новичок есть несколько приемов первое написать дополнение Node на С/C++ с использованием потоков или переписать саму функцию fib таким образом чтобы она периодически проверяла I/O. - А можно примерчик? Добавлено Вот например 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. - А можно примерчик? Можно Машку за ляжку попробуй сделать это сам - Ok Маста а почему вы вычисляли фибоначи от 25 а не 42 как в предыдущем примере? Заметил таки просто от 42 долго вычисляется Можно ускорить вычисления, убрав из fib1 process.nextTick. - Это как? А вот так ..... 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(); } ..... |
Сообщ.
#4
,
|
|
|
Проверил асинхронность в действии создал Express сервер и что вы думаете через process.nextTick асинхронности нет! Делаю два запроса и оба висят!
Заменил на setImmediate теперь все пучком! 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'); }); |
Сообщ.
#5
,
|
|
|
- Маста, а можно ускорить вычисление числа фибоначи?
Да конечно можно Можно применить так называмую мемоизацию результатов вычисления тем самым у нас в разы уменьшится количество вычислений. - Как это? Например 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. Правда теперь юзать такую оптимизированую функцию для демонстрации асинхронного вычисления не имеет смысла, поскольку она синхронно вычисляется очень быстро для любого значения |
Сообщ.
#6
,
|
|
|
Возникла трабла при тестировании
Запускаю сервер, далее запускаю Хром, печатаю http://localhost:3000/10 и что вы думаете результат выводит все пучком, но в консоле пишет вот это: (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. |
Сообщ.
#7
,
|
|
|
Вставил проверку catch в промис
demo.asyncFib(number).then(result => { console.log(`fibonacci value for ${number} is ${result}`); res.send(`<h1>Fib: ${result}</h1>`); }) .catch(err => console.log(err)); Теперь выхлоп такой 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) Что за нафик! Результат то выводит правильно! Несколько раз проверял код функции asyncFib вроде все правильно |
Сообщ.
#8
,
|
|
|
Нашел баг
Вставил лог мидлварэ app.use(function (req, res, next) { console.log(`${req.method} ${req.url}`); next(); }); получил GET /10 fibonacci value for 10 is 55 GET /favicon.ico RangeError: Maximum call stack size exceeded ..... выходит что кроме основного Хром посылал еще и запрос /favicon.ico! этот запрос обрабатывался одним и тем же get обработчиком. Что делать? Есть несколько решений первое заюзать регулярку для точной проверки url app.get(/^\/(\d+)$/, function (req, res) { var number = req.params[0]; ..... или вставить проверку isNaN в колбэк функцию: app.get('/:number', function (req, res) { var number = parseInt(req.params.number); if (isNaN(number)) { return res.send(); } ..... а можно проще app.get('/:number', function (req, res) { var number = parseInt(req.params.number) || 0; ..... |
Сообщ.
#9
,
|
|
|
- Маста, вот как будет на async
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])); } - Причем он немного быстрее чем на промисах Епт Новичок! Ты не новичек! |