2017-01-13 5 views
0

В компании, в которой я работаю, все в настоящее время выполняется с обратными вызовами. Мы начинаем писать небольшие компоненты с обещаниями, от которых зависит большой код. У нас начались проблемы с ними.Как обернуть обещание обратным вызовом?

function getSomething() { 
    return Promise.resolve('hello') 
} 

function test(cb) { 
    getSomething() 
    .then(string => { 
    a.s 
    cb(null, string) 
    }, error => cb(error)) 
} 

test((error, result) => { 
    console.log(error) 
    console.log(result) 
    a.s 
}) 

Это простой пример проблемы. В этом коде, так как a не существует, он бросает предупреждение UnhandledPromiseRejectionWarning и убивает процесс. консольные журналы никогда не достигаются.

Логика заключалась в том, что если ошибка когда-либо произойдет, это вызовет обратный вызов catch.

function test(cb) { 
    getSomething() 
    .then(string => { 
    // a.s 
    cb(null, string) 
    }, error => cb(error)) 
    .catch(error => cb(error)) 
} 

Мне было рекомендовано использовать явный улов в конце цепочки обещаний. Проблема в том, что если в обратном вызове возникает ошибка, обратный вызов запускается дважды.

Спасибо за любую помощь.

+0

Как обернуть весь затем в попытке, и ошибок на улов? –

+1

Ну, может быть, вы не должны использовать обратный вызов 'onRejected' на этапе' then' и просто цепляйте '.catch()', как вы делали во втором фрагменте. – Redu

+0

@Redu, переместите этот комментарий к ответу, потому что это правильный ответ. @ Второй фрагмент AlvaroOrtiz дважды прикрепляет обработчик ошибок 'cb'. – DaveS

ответ

1

Существует тонкое различие между

.then(onFulfilled, onRejected) 

и

.then(onFullfilled) 
.catch(onRejected) 

Первый не смог бы поймать ошибки, возникающие в onFullFilled обратного вызова, а второй один будет. Может быть, вы не должны использовать обратный вызов onRejected на этапе тогда и просто соедините .catch(), как вы делали во втором фрагменте.

+0

Даже если я удаляю второй обработчик в 'then' и возникает ошибка, он все равно вызывает обработчик в инструкции catch. –

+0

@ Альваро Ортис Это нормально. Функтор '.catch()' находится ниже по течению, и он поймает первую ошибку, полученную на предыдущем этапе. – Redu

0

Вы можете отделить код в then части так, что ошибки перед вызовом сЬ обрабатываются иначе, чем те, которые происходят в Сь. Вместо того, чтобы звонить cb там, вы должны вернуть строковое значение, чтобы его можно было использовать в цепочке then. И там вы можете использовать переключатель между успехом и неудачей. Таким образом, cb будет называться только там.

Теперь, если по телефону сЬ происходит ошибка, вы могли бы поймать, что с окончательным .catch, но тогда вы не могли бы назвать сЬ больше, но, возможно, просто вывести что-то, или каскад ошибки, или делать все, что вам хочу сделать в этом случае.

Вот демо с тремя вариантами использования:

  1. Нет ошибки
  2. ошибка в (первый) then
  3. Ошибка в Сь

function getSomething() { 
 
    return Promise.resolve('hello'); 
 
} 
 

 
function test(testNo, cb) { 
 
    getSomething() 
 
    .then(string => { 
 
    if (testNo == 2) a.s; 
 
    return string; // don't call cb yet 
 
    }) 
 
    .then(cb.bind(null, null), cb) // now call it -- mutually exclusive with error case 
 
    .catch(error => { // catch any errors not yet captured -- i.e. in cb 
 
     console.log('test ' + testNo + ': error occurred in success callback'); 
 
    }); 
 
} 
 

 
for (let testNo = 1; testNo <= 3; testNo++) { 
 
    test(testNo, (error, result) => { 
 
    if (error) 
 
     console.log('callback for test ' + testNo + ' error:', error.message); 
 
    else 
 
     console.log('callback for test ' + testNo + ' success:', result); 
 
    if (testNo == 3) a.s; 
 
    }); 
 
}

0

Что происходит в вашем фрагменте кода, так это то, что вы возвращаете отклоненное обещание при возникновении ошибки в вашем then(). И поскольку после этого у вас нет обработчика, это отклоненное обещание не обрабатывается и (к счастью) всплывает.

Вы в основном есть две возможности, чтобы исправить это: Вы можете либо добавить еще catch() после then() метода, как этот

function test(cb) { 
    getSomething() 
    .then(string => { 
    a.s 
    cb(null, string) 
    }) 
    .catch(e => cb) //this catch() handles whatever rejected promise 
        //comes out of then() or from the earlier promise 
} 

В этом решении это может случиться, что вы получите ваш обратный вызов вызывается дважды в случае с ошибка возникает при выполнении cb (null, string). В этом случае вам нужен защитник в вашем обратном вызове, чтобы различать разные коды ошибок, чтобы узнать, поступает ли он от getSomething() или из cb (null, string).

Или вы могли бы добавить традиционный Try/кетчуп блок внутри вашего then() обработчика как этот

function test(cb) { 
    getSomething() 
    .then(string => { 
    try{ 
     a.s 
     cb(null, string) 
    } catch(e) { 
     if(e.message == "callback error" { 
      //do what you want to do to with a callback error 
     } else { 
      //do whatever you want to do with other errors from your catch block 
     } 
    } 
    }, error => cb(error)) 
} 

В этом решении можно поставить охрану, чтобы различать разные причины ошибок внутри блока поймать и обратный вызов называется только один раз. Однако для обработки ваших ошибок необходим другой механизм обработки. Одной из простых возможностей было бы просто проглотить новые ошибки, однако это может быть плохим решением.

В этом проблема с асинхронным программированием, что нет возможности для ошибок превращаться в центральный обработчик, поскольку контекст стека теряется до тех пор, пока обратный вызов не будет окончательно выполнен.

Приветствия, Felix

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