try / catch блоки с async / wait

Я копаю в функции 7 асинхронного / ждущего узла 7 и продолжаю спотыкаться по коду, как это

async function main() { try { var quote = await getQuote(); console.log(quote); } catch(error) { console.error(error); } } 

Кажется, это единственная возможность разрешить / отклонить или вернуть / выбросить с помощью async / await, однако v8 не оптимизирует код внутри блоков try / catch ?!

Есть ли альтернативы?

    альтернативы

    Альтернатива этому:

     async function main() { try { var quote = await getQuote(); console.log(quote); } catch (error) { console.error(error); } } 

    будет что-то вроде этого, явно используя обещания:

     function main() { getQuote().then((quote) => { console.log(quote); }).catch((error) => { console.error(error); }); } 

    или что-то вроде этого, используя стиль продолжения прохождения:

     function main() { getQuote((error, quote) => { if (error) { console.error(error); } else { console.log(quote); } }); } 

    Исходный пример

    То, что делает ваш исходный код, приостанавливает выполнение и ожидает, что promise, возвращенное getQuote() будет выполнено. Затем он продолжает выполнение и записывает возвращаемое значение в var quote а затем печатает его, если promise было разрешено или выбрасывает исключение, и запускает блок catch, который печатает ошибку, если promise было отклонено.

    Вы можете сделать то же самое, используя API Promise, как и во втором примере.

    Представление

    Теперь для производительности. Давайте проверим это!

    Я просто написал этот код – f1() дает 1 как возвращаемое значение, f2() выбрасывает 1 как исключение:

     function f1() { return 1; } function f2() { throw 1; } 

    Теперь давайте назовем тот же код миллион раз, сначала с f1() :

     var sum = 0; for (var i = 0; i < 1e6; i++) { try { sum += f1(); } catch (e) { sum += e; } } console.log(sum); 

    А затем давайте изменим f1() на f2() :

     var sum = 0; for (var i = 0; i < 1e6; i++) { try { sum += f2(); } catch (e) { sum += e; } } console.log(sum); 

    Это результат, который я получил для f1 :

     $ time node throw-test.js 1000000 real 0m0.073s user 0m0.070s sys 0m0.004s 

    Это то, что я получил для f2 :

     $ time node throw-test.js 1000000 real 0m0.632s user 0m0.629s sys 0m0.004s 

    Кажется, что вы можете сделать что-то вроде 2 миллионов бросков в секунду в одном однопоточном процессе. Если вы делаете больше, чем это, вам может понадобиться беспокоиться об этом.

    Резюме

    Я бы не стал беспокоиться о подобных вещах в Node. Если такие вещи будут использоваться много, тогда он будет оптимизирован в конечном итоге группами V8 или SpiderMonkey или Chakra, и все последуют за ними - это не похоже на то, что он не оптимизирован как принцип, это просто не проблема.

    Даже если он не оптимизирован, я бы все же утверждал, что если вы максимизируете свой процессор в узле, то вы, вероятно, должны написать свой хруст числа в C - вот что такое, например, родные аддоны. Или, может быть, такие вещи, как node.native , лучше подходят для работы, чем Node.js.

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

    Альтернатива похожа на обработку ошибок в Голанге

    Поскольку async / await использует обещания под капотом, вы можете написать небольшую полезную функцию следующим образом:

     export function catchEm(promise) { return promise.then(data => [null, data]) .catch(err => [err]); } 

    Затем импортируйте его, когда вам нужно поймать некоторые ошибки, и заверните свою функцию async, которая возвращает promise с ней.

     import catchEm from 'utility'; async performAsyncWork() { const [err, data] = await catchEm(asyncFunction(arg1, arg2)); if (err) { // handle errors } else { // use data } } 

    Альтернативой блоку try-catch является ожидание-js lib. Я часто использую его. Например:

     import to from 'await-to-js'; async function main(callback) { const [err,quote] = await to(getQuote()); if(err || !quote) return callback(new Error('No Quote found'); callback(null,quote); } 

    Этот синтаксис намного чище по сравнению с try-catch.

     async function main() { var getQuoteError var quote = await getQuote().catch(err => { getQuoteError = err } if (getQuoteError) return console.error(err) console.log(quote) } 

    В качестве альтернативы вместо объявления возможной ошибки var, чтобы удалить ошибку вверху, вы можете сделать

     if (quote instanceOf Error) ... 

    Хотя это не будет работать, если что-то вроде ошибки TypeError или Reference. Вы можете гарантировать, что это обычная ошибка, хотя с

     async function main() { var quote = await getQuote().catch(err => { console.error(err) return new Error('Error getting quote') }) if (quote instanceOf Error) return quote // get out of here or do whatever console.log(quote) } 

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

    Я бы хотел сделать это 🙂

     const sthError = () => Promise.reject('sth error'); const test = opts => { return (async () => { // do sth await sthError(); return 'ok'; })().catch(err => { console.error(err); // error will be catched there }); }; test().then(ret => { console.log(ret); }); 

    Это похоже на ошибку обработки с помощью co

     const test = opts => { return co(function*() { // do sth yield sthError(); return 'ok'; }).catch(err => { console.error(err); }); }; 
    Давайте будем гением компьютера.