Какую проблему решает Promise?

Node.js внешний интерфейс JavaScript Promise

мой блог на гитхабеGitHub.com/dedicated мойка…

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

Что такое ад обратного вызова? что с этим не так? Это потому, что вложение некрасиво или неудобно читать?

Сначала мы должны подумать,Где проблема с вложением?

Например:

function a() {
  function b() {
    function c() {
      function d() {}
      d();
    }
    c();
  }
  b();
}
a();

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

Проблема вложенности в этом примере — это только проблема отступов, а отступы — это не проблема, кроме того, что код становится шире и, возможно, немного неудобным для чтения кода. Если это все, то почему это не называется «ад отступов» или «вложенный ад»?

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

Таким образом, вложенность «ада обратных вызовов» на самом деле относится кАсинхронное вложение. Это приносит две проблемы: проблемы с удобочитаемостью и проблемы с доверием.

проблемы с читабельностью

Это вопрос из интервью о последовательности казни, который я наугад искал в Интернете:

for (var i = 0; i < 5; i++) {
  setTimeout(function() {
    console.log(new Date, i);
  }, 1000);
}

console.log(new Date, i);

Ответ - это то, что вы думаете для себя, это не главное. Дело в том, думаете ли вы об этом какое-то время?

Аккуратный обратный вызов:

listen( "click", function handler( evt){ 
  setTimeout( function request(){ 
    ajax( "http:// some. url. 1", function response( text){ 
      if (text == "hello") { 
        handler(); 
      } else if (text == "world") { 
        request(); 
      } 
    }); 
  }, 500); 
});

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

Но когда мы на самом деле пишем бизнес-логику, реальная ситуация должна быть такой:

listen( "click", function handler(evt){ 
  doSomething1();
  doSomething2();
  doSomething3();
  doSomething4();
  setTimeout( function request(){ 
    doSomething8();
    doSomething9();
    doSomething10();
    ajax( "http:// some. url. 1", function response( text){ 
      if (text == "hello") { 
        handler(); 
      } else if (text == "world") { 
        request(); 
      } 
    }); 
    doSomething11();
    doSomething12();
    doSomething13();
  }, 500); 
  doSomething5();
  doSomething6();
  doSomething7();
});

Некоторые из этих «делать что-то» асинхронны, а некоторые синхронны. Такой код может быть очень трудно читать, потому что вы должны постоянно думать о порядке их выполнения и держать его в голове. Это проблема читаемости, вызванная асинхронным вложением, вызванным механизмом асинхронной работы.

вопросы доверия

В основном это обсуждается с асинхронными запросами. Когда мы делаем AJAX-запросы, мы, как правило, используем какие-то сторонние инструментальные библиотеки (даже если они упакованы нами самими, в какой-то мере их можно понимать как сторонние), в связи с чем возникает вопрос: действительно ли эти инструментальные библиотеки 100 % надежный?

От"ЮДКЖС"Пример: Программист разработал платежную систему, которая долгое время исправно работала. Внезапно в один прекрасный день кредитная карта клиента была просканирована пять раз подряд во время платежа. После расследования программист обнаружил, что сторонняя библиотека инструментов по какой-то причине выполнила обратный вызов платежа пять раз. Проблема была решена после общения со сторонней командой.

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

Если вы продолжите думать об этом, то обнаружите, что подобных проблем гораздо больше. Подытожим проблемы, которые могут возникнуть:

  • Обратный вызов слишком ранний (обычно асинхронно вызывается синхронно);
  • Обратный вызов слишком запоздал или его нет;
  • Слишком много обратных вызовов;
  • так далее

С этими проверками защищенный код может выглядеть так:

listen( "click", function handler( evt){ 
  check1();
  doSomething1();
  setTimeout( function request(){ 
    check2();
    doSomething3();
    ajax( "http:// some. url. 1", function response( text){ 
      if (text == "hello") { 
        handler(); 
      } else if (text == "world") { 
        request(); 
      } 
    }); 
    doSomething4();
  }, 500); 
  doSomething2();
});

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

Хотя вероятность появления этих ошибок мала, с ними все же приходится иметь дело.

Это проблема доверия, вызванная асинхронным вложением, и корень ее проблемы лежит вИнверсия контроля. Применение инверсии управления в объектно-ориентированном подходе — это внедрение зависимостей, которое реализует развязку между модулями. А в обратных вызовах все не так любезно, и управление передается третьей стороне, которая решает, когда и как вызывать обратный вызов.

Некоторые попытки решить проблему доверия

Добавьте обратный вызов для обработки ошибок

function success(data) { 
  console. log(data); 
} 
function failure(err) { 
  console. error( err ); 
} 
ajax( "http:// some. url. 1", success, failure );

первая ошибка в nodejs

function response(err, data) { 
  if (err) { 
    console. error( err ); 
  } 
  else { 
    console. log( data ); 
  } 
} 
ajax( "http:// some. url. 1", response );

Эти два метода решают некоторые проблемы и снижают нагрузку, но все же не решают проблему полностью. Во-первых, их повторное использование пока не сильно, а во-вторых, проблема многократного вызова обратного вызова до сих пор не решена.

Насколько обещания решают эти две проблемы

Обещание уже является оригинальным поддерживаемым API, который был добавлен в спецификацию JS, а рабочий механизм в основных браузерах одинаково. Это гарантирует, что он надежен.

Как решить проблемы с читабельностью

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

Как исправить проблемы с доверием

Промис не отменяет инверсию управления, а снова инвертирует инвертированное управление, то есть обращает инверсию управления.

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

Обещание имеет следующие характеристики: оно может быть разрешено только один раз, значение разрешения может быть только одно, и его нельзя изменить после разрешения. Любые обратные вызовы then будут вызываться только один раз. Характеристики промисов гарантируют, что промисы могут решать проблемы доверия.

Для преждевременных обратных вызовов, так как промисы могут быть только асинхронными, асинхронных синхронных вызовов не будет. Даже ошибки до разрешения являются асинхронными и не вызывают синхронных (преждевременных вызовов) проблем.

var a = new Promise((resolve, reject) => {
  var b = 1 + c;  // ReferenceError: c is not defined,错误会在下面的a打印出来之后报出。
  resolve(true);
})
console.log(1, a);
a.then(res => {
  console.log(2, res);
})
.catch(err => {
  console.log(err);
})

Для обратных вызовов, которые слишком поздно или не вызваны, Promise сам по себе не будет перезванивать слишком поздно, пока он разрешен, он будет работать, как указано. Что касается проблем с сервером или сетью, то это не то, что Promise может решить, обычно в этом случае будет использоваться конкурентный API Promise.Promise.raceДобавьте тайм-аут:

function timeoutPromise(delay) {
  return new Promise(function(resolve, reject) {
    setTimeout(function() {
      reject("Timeout!");
    }, delay);
  });
}

Promise.race([doSomething(), timeoutPromise(3000)])
.then(...)
.catch(...);

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

Использованная литература: