2016-01-25 2 views
1

Вот подмножество лотов больше кода; JavaScript в Node.js. По сути, эквивалент функции a требует некоторого модульного тестирования (в функции b). При возврате с b, a призывает к тестированию исключений (в функции c). c призывает к синхронному тестированию исключений (в функции d). Позже c вызовет другую функцию (e, скажем) для асинхронного тестирования исключений (использование Promise reject()). Лучше всего использовать Promises везде в Node.js, но даже использование их не всегда приводит к поведению, которое я предсказываю.Почему этот JavaScript Promise reject() обрабатывается при обратном вызове результата?

'use strict'; 

function d() { 
    return new Promise(function(resolve, reject) { 
    console.log('start d throw test'); 
    try { 
     throw new Error('Error type'); 
    } catch (e) { 
     console.log('d catch block e.message=' + e.message + 
     ' rejecting to c'); 
     return reject(new Error('d ' + e.message)); 
    } // catch 
    }) // Promise 
} 

function c() { 
    return new Promise(function(resolve, reject) { 
    console.log('start c'); 
    d() 
    .then(// d then 
     function(result) { console.log('c d result callback'); }, 
     function(error) { 
     console.log('c d error callback error.message=' + error.message + 
      ' rejecting to a'); 
     return reject(new Error('second try')); 
     } 
    ) // d then 
    }) // Promise 
} 

function b() { 
    console.log('start b resolving to a'); 
    return Promise.resolve(); 
} 

function a() { 
    return new Promise(function(resolve, reject) { 
    console.log('start a'); 
    b() 
    .then(// b then 
     function(result) { 
     console.log('a b result callback to c'); 
     c(); 
     }, 
     function(error) { 
     console.log('a b error callback error.message=' + error.message); 
     } 
    ) // b then 
    .then(// c then 
     function(result) { 
     console.log('a c result callback '); 
     }, 
     function(error) { 
     console.log('a c error callback error.message=' + error.message); 
     } 
    ) // c then 
    .catch(
     function(error) { 
     console.log('a final catch error.message=' + error.message); 
     } 
    ) // catch 
    }) // Promise 
} 

a(); 

я предсказал, например, что каждый раз, когда я выдать обещание отказаться(), обработка будет происходить в ошибке обратного вызова вызывающего абонента. (Обратите внимание, что каждый reject() также использует new Error.) Следовательно, я ожидал этот вывод в console.log.

start a 
start b resolving to a 
a b result callback to c 
start c 
start d throw test 
d catch block e.message=Error type rejecting to c 
c d error callback error.message=d Error type rejecting to a 
a c error callback error.message=second try 

Обратите внимание, что когда d называется отклонять(), я предсказывал обработка будет идти на обратный вызов c ошибки. Аналогично, c reject() перейдет в обратный вызов ошибки a. Вместо этого, я получаю этот выход:

start a 
start b resolving to a 
a b result callback to c 
start c 
start d throw test 
d catch block e.message=Error type rejecting to c 
c d error callback error.message=d Error type rejecting to a 
a c result callback 

c отклонять(), похоже, идет к aрезультат обратного вызова.

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

Вопросы:

  1. Почему обработка происходит в результате обратного вызова, а не обратного вызова ошибки?
  2. Как функция b вызывает эффект так долго после ее завершения?
  3. Как я могу это исправить?
  4. Какие плюсы и минусы привязаны к использованию return reject по сравнению с reject? Большую часть времени (по крайней мере), похоже, работает. Я не поймал более короткую форму, вызывающую проблемы.
+1

он должен быть 'Возвращение с();' – mido

+0

Очень интересно читать: http://pouchdb.com/2015/05/18 /we-have-a-problem-with-promises.html Вы сделали ошибку * Rookie # 5 *, вы не вернули c().Кроме того, не смешивайте вещи так много, либо используйте обратный вызов ошибки или (повторный) бросок ошибок (бросок очень рекомендуется), не оба, это запутывает. – Shanoor

+0

@ShanShan: Спасибо, что мотивировал меня перечитать эту статью. Это одна из лучших статей о обещаниях, которые я видел. Я не полностью понял ошибку Rookie №5 раньше (очевидно). – BaldEagle

ответ

5

основной вопрос, вы сделали c(); вместо return c();, другие проблемы включают в себя:

  • метод d, c может быть упрощена, остановка упаковка обещает с new Promise(...)
  • использование ИЗБЕЖАТЬ из .then(success, error), в большинстве случаев, целесообразно использовать then(success).catch(error).
  • вы код может быть уменьшена ниже:

    'use strict'; 
    
    function d() { 
        return Promise.reject(new Error('Error type')); 
    } 
    
    function c() { 
        console.log('start c'); 
        return d() 
        .then(result => console.log('c d result callback')) 
        .catch(error => { 
         console.log('c d error callback error.message=' + error.message + 
         ' rejecting to a'); 
         throw new Error('second try'); 
        }); 
    } 
    
    function b() { 
        console.log('start b resolving to a'); 
        return Promise.resolve(); 
    } 
    
    function a() { 
        console.log('start a'); 
        return b() 
        .then(result => { 
         console.log('a b result callback to c'); 
         return c();  
        }).catch(error => console.log('a b error callback error.message=' + error.message)) 
        .then(result => console.log('a c result callback ')) 
        .catch(error => console.log('a final catch error.message=' + error.message)); 
    } 
    
    a(); 
    
+0

Спасибо, много. Вы сделали мне две большие милости. (1) Вы определили проблему с возвратом c(). (2) Вы продемонстрировали много альтернативного синтаксиса, которого я не видел. (И это не потеряло меня, что ваш код намного короче, чем у меня, и много ясности!) – BaldEagle

Смежные вопросы