Loading...

промистер: каталарды обработкалоо

промистер: каталарды обработкалоо

 

Убада чынжырлары каталарды кармоо үчүн сонун. Эгер убада ишке ашпаса, башкаруу эң жакынкы ката иштетүүчүгө өтөт. Иш жүзүндө бул абдан ыңгайлуу.

Мисалы, төмөнкү мисалда fetchURL жараксыз (веб-сайт жок) жана .catchал катаны кармайт:

@A@fetch('https://no-such-server.blabla') // ошибка
  .then(response => response.json())
  .catch(err => alert(err)) // TypeError: failed to fetch (текст может отличаться)@A@

Көрүнүп тургандай, .catchкатадан кийин дароо болушу керек эмес, ал бир же бир нечеден кийин дагы болушу мүмкүн.then

Же серверде баары жакшы болушу мүмкүн, бирок биз жоопто туура эмес JSON алабыз. Бардык каталарды кармоонун эң оңой жолу - .catchчынжырдын аягына кошуу:

@A@fetch('/article/promise-chaining/user.json')
  .then(response => response.json())
  .then(user => fetch(`https://api.github.com/users/${user.name}`))
  .then(response => response.json())
  .then(githubUser => new Promise((resolve, reject) => {
    let img = document.createElement('img');
    img.src = githubUser.avatar_url;
    img.className = "promise-avatar-example";
    document.body.append(img);

    setTimeout(() => {
      img.remove();
      resolve(githubUser);
    }, 3000);
  }))
  .catch(error => alert(error.message));@A@

Эгер баары жайында болсо, анда бул .catchтакыр аткарылбайт. Бирок убадалардын бири четке кагылса (тармак көйгөйлөрү же туура эмес json саптары же башкасы), анда ката кармалып калат.

толук эмес... try catch

Убада функциясынын жана иштетүүчүлөрдүн айланасында "көрүнбөгөн" бар try..catch. Эгерде өзгөчөлүк пайда болсо, ал кармалып, бул ката менен убада четке кагылган деп эсептелет.

Мисалы, бул код:

@A@new Promise((resolve, reject) => {
  throw new Error("Ошибка!");
}).catch(alert); // Error: Ошибка!

... ушул сыяктуу иштейт:

 
 
new Promise((resolve, reject) => {
  reject(new Error("Ошибка!"));
}).catch(alert); // Error: Ошибка!@A@

try..catchУбаданын тегерегиндеги "көрүнбөгөн " катаны автоматтык түрдө кармап, аны четке кагылган убадага айлантат.

Бул убада функциясында гана эмес, иштетүүчүлөрдө да иштейт. throwЭгерде биз ( ) иштеткичтен ( ) ката кетирсек .then, анда убада четке кагылды деп эсептелинет жана башкаруу эң жакынкы ката иштетүүчүгө өтөт.

Мисал:

@A@new Promise((resolve, reject) => {
  resolve("ок");
}).then((result) => {
  throw new Error("Ошибка!"); // генерируем ошибку
}).catch(alert); // Error: Ошибка!@A@

Бул бардык каталар үчүн гана эмес, throw. Мисалы, программалык камсыздоо катасы:

@A@new Promise((resolve, reject) => {
  resolve("ок");
}).then((result) => {
  blabla(); // нет такой функции
}).catch(alert); // ReferenceError: blabla is not defined@A@

Акыркысы чакырылган .catchубадаларды да reject, иштеткичтердеги туш келди каталарды да кармайт.

Каталарды ыргытyy

Биз буга чейин байкагандай, .catchал сыяктуу иш-аракет кылат try..catch.thenБиз каалагандай көп иштеткичтерге ээ боло алабыз жана андан соң .catchбардык иштеткичтерден каталарды кармоо үчүн бирөөнү колдонсок болот.

Кадимкидей try..catch, катаны талдап, аны чече албасак, аны кайра ыргыта алабыз. Ошол эле убадалар үчүн да мүмкүн.

throwЭгерде биз блоктун ичине ката кетирсек ( ) .catch, башкаруу кийинки эң жакын ката иштетүүчүгө өтөт. Жана эгер биз катаны иштетип, иштеткичтен кадимкидей чыксак, анда кийинки ийгиликтүү иштеткич иштей берет .then.

Төмөндөгү мисал .catchкатаны ийгиликтүү чечет:

@A@// the execution: catch -> then
new Promise((resolve, reject) => {

  throw new Error("Ошибка!");

}).catch(function(error) {

  alert("Ошибка обработана, продолжить работу");

}).then(() => alert("Управление перейдёт в следующий then"));@A@

Бул жерде блок .catchкадимкидей бүтөт. Ошондуктан, кийинки ийгиликтүү иштеткич деп аталат .then.

Төмөндөгү мисалда биз блок менен башкача кырдаалды көрөбүз .catch. Иштегич (*)катаны кармайт жана аны иштете албайт (мисалы, ал кантип иштетүүнү гана билет URIError), ошондуктан ката андан ары жөнөтүлөт:

 
 
@A@// the execution: catch -> catch -> then
new Promise((resolve, reject) => {

  throw new Error("Ошибка!");

}).catch(function(error) { // (*)

  if (error instanceof URIError) {
    // обрабатываем ошибку
  } else {
    alert("Не могу обработать ошибку");

    throw error; // пробрасывает эту или другую ошибку в следующий catch
  }

}).then(function() {
  /* не выполнится */
}).catch(error => { // (**)

  alert(`Неизвестная ошибка: ${error}`);
  // ничего не возвращаем => выполнение продолжается в нормальном режиме

});@A@

Башкаруу биринчи блоктон .catch (*)экинчисине (**), чынжыр боюнча өтөт.

Обработкаланбаган каталар

Ката чечилбесе эмне болот? Мисалы, биз .catchчынжырдын аягына мындайча кошууну унутуп калдык:

@A@new Promise(function() {
  noSuchFunction(); // Ошибка (нет такой функции)
})
  .then(() => {
    // обработчики .then, один или более
  }); // без .catch в самом конце!@A@

Ката болгондо, аткаруу эң жакын ката иштетүүчүгө өтүшү керек. Бирок жогорудагы мисалда эч кандай иштетүүчү жок. Ошондуктан, ката "жабылат" дегендей, аны иштете турган эч ким жок.

Иш жүзүндө, коддогу кадимки иштетилбеген каталардай эле, бул бир нерсе туура эмес болгонун билдирет.

Кадимки ката кармалбаса эмне болот try..catch? Скрипт консолдогу билдирүү менен өлөт. Ушундай эле нерсе чечилбеген убада катасында болот.

JavaScript кыймылдаткычы мындай жагдайларды көзөмөлдөйт жана бул учурда глобалдык катаны жаратат. Жогорудагы мисалды иштетсеңиз, аны консолдон көрө аласыз.

Браузерде окуяны колдонуп, мындай каталарды таба алабыз unhandledrejection:

 
 
@A@window.addEventListener('unhandledrejection', function(event) {
  // объект события имеет два специальных свойства:
  alert(event.promise); // [object Promise] - промис, который сгенерировал ошибку
  alert(event.reason); // Error: Ошибка! - объект ошибки, которая не была обработана
});

new Promise(function() {
  throw new Error("Ошибка!");
}); // нет обработчика ошибок@A@

Бул окуя HTML стандартынын бир бөлүгү болуп саналат .

Эгерде ката пайда болуп, иштеткич жок болсо, анда окуя түзүлөт unhandledrejectionжана тиешелүү объект eventката жөнүндө маалыматты камтыйт.

Адатта, мындай каталар өлүмгө алып келет, андыктан колдонуучуга көйгөй тууралуу маалымат берүү жана ката тууралуу маалыматты серверге жөнөтүү эң жакшы.

Node.js сыяктуу браузерден тышкары чөйрөлөрдө иштетилбеген каталарды көзөмөлдөөнүн башка жолдору бар.

Бардыгы

  • .catchубадалардагы ар кандай каталарды кармайт: чалуулар болобу reject()же иштеткичте ташталган ката болобу throw.
  • .thenэкинчи аргумент (ката иштеткич болуп саналат) берилсе, ошондой эле каталарды кармайт.
  • .catchБиз аны каталарды чечүүнү каалаган жерге жайгаштырышыбыз керек жана аны кантип жасоону билишибиз керек. Иштетүүчү катаны талдай алат (өзгөчө ката класстары пайдалуу болушу мүмкүн) жана ал жөнүндө эч нерсе билбесе, аны кайра ыргыта алат (балким, бул программалоо катасыдыр).
  • .catchКатадан калыбына келтирүүнүн кадимки жолу жок болсо, аны такыр колдоно албайсыз .
  • Кандай болгон күндө да, иштетилбеген каталарга көз салуу жана колдонуучуга (мүмкүн биздин серверге) маалымат берүү үчүн окуяны иштеткичти (браузерлер үчүн жана башка чөйрөлөр үчүн) колдонушубуз керек unhandledrejection, ошондо биздин тиркеме эч качан "жөн эле өлбөйт".

Tasks

 

Сиз кандай ойлойсуз? Ал аткарылабы .catch? Жообуңду түшүндүр.

@A@new Promise(function(resolve, reject) {
  setTimeout(() => {
    throw new Error("Whoops!");
  }, 1000);
}).catch(alert);@A@
чечим