175 lines
		
	
	
		
			9.0 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
			
		
		
	
	
			175 lines
		
	
	
		
			9.0 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
| ---
 | ||
| title: Promises
 | ||
| localeTitle: обещания
 | ||
| ---
 | ||
| ## обещания
 | ||
| 
 | ||
| JavaScript однопоточный, что означает, что два бита скрипта не могут работать одновременно; они должны бежать один за другим. Promise - это объект, который представляет собой возможное завершение (или отказ) асинхронной операции и ее итоговое значение.
 | ||
| 
 | ||
| ```javascript
 | ||
| var promise = new Promise(function(resolve, reject) { 
 | ||
|   // do thing, then… 
 | ||
|  
 | ||
|   if (/* everything worked */) { 
 | ||
|     resolve("See, it worked!"); 
 | ||
|   } 
 | ||
|   else { 
 | ||
|     reject(Error("It broke")); 
 | ||
|   } 
 | ||
|  }); 
 | ||
| ```
 | ||
| 
 | ||
| ## В одном из этих состояний существует обещание
 | ||
| 
 | ||
| *   Ожидание: начальное состояние, ни выполнено, ни отклонено.
 | ||
| *   Выполнено: операция успешно завершена.
 | ||
| *   Отклонено: операция завершилась неудачно.
 | ||
| 
 | ||
| Объект Promise работает как прокси-сервер для значения, которое не обязательно известно при создании обещания. Это позволяет связать обработчики с вероятным результатом успешной асинхронной операции или причиной сбоя. Это позволяет асинхронным методам возвращать такие значения, как синхронные методы: вместо немедленного возврата окончательного значения асинхронный метод возвращает обещание предоставить значение в какой-то момент в будущем.
 | ||
| 
 | ||
| ## Использование 'Then' (Promise Chaining)
 | ||
| 
 | ||
| Чтобы выполнить несколько асинхронных вызовов и синхронизировать их один за другим, вы можете использовать цепочку слияния. Это позволяет использовать значение из первого обещания в последующих последующих обратных вызовах.
 | ||
| 
 | ||
| ```javascript
 | ||
| Promise.resolve('some') 
 | ||
|   .then(function(string) { // <-- This will happen after the above Promise resolves (returning the value 'some') 
 | ||
|     return new Promise(function(resolve, reject) { 
 | ||
|       setTimeout(function() { 
 | ||
|         string += 'thing'; 
 | ||
|         resolve(string); 
 | ||
|       }, 1); 
 | ||
|     }); 
 | ||
|   }) 
 | ||
|   .then(function(string) { // <-- This will happen after the above .then's new Promise resolves 
 | ||
|     console.log(string); // <-- Logs 'something' to the console 
 | ||
|   }); 
 | ||
| ```
 | ||
| 
 | ||
| ## API обещаний
 | ||
| 
 | ||
| В классе Promise существует 4 статических метода:
 | ||
| 
 | ||
| *   Promise.resolve
 | ||
| *   Promise.reject
 | ||
| *   Promise.all
 | ||
| *   Promise.race
 | ||
| 
 | ||
| ## Обещания могут быть соединены вместе
 | ||
| 
 | ||
| При написании обещаний для решения конкретной проблемы вы можете связать их вместе, чтобы сформировать логику.
 | ||
| 
 | ||
| ```javascript
 | ||
| var add = function(x, y) { 
 | ||
|   return new Promise((resolve,reject) => { 
 | ||
|     var sum = x + y; 
 | ||
|     if (sum) { 
 | ||
|       resolve(sum); 
 | ||
|     } 
 | ||
|     else { 
 | ||
|       reject(Error("Could not add the two values!")); 
 | ||
|     } 
 | ||
|   }); 
 | ||
|  }; 
 | ||
|  
 | ||
|  var subtract = function(x, y) { 
 | ||
|   return new Promise((resolve, reject) => { 
 | ||
|     var sum = x - y; 
 | ||
|     if (sum) { 
 | ||
|       resolve(sum); 
 | ||
|     } 
 | ||
|     else { 
 | ||
|       reject(Error("Could not subtract the two values!")); 
 | ||
|     } 
 | ||
|   }); 
 | ||
|  }; 
 | ||
|  
 | ||
|  // Starting promise chain 
 | ||
|  add(2,2) 
 | ||
|   .then((added) => { 
 | ||
|     // added = 4 
 | ||
|     return subtract(added, 3); 
 | ||
|   }) 
 | ||
|   .then((subtracted) => { 
 | ||
|     // subtracted = 1 
 | ||
|     return add(subtracted, 5); 
 | ||
|   }) 
 | ||
|   .then((added) => { 
 | ||
|     // added = 6 
 | ||
|     return added * 2; 
 | ||
|   }) 
 | ||
|   .then((result) => { 
 | ||
|     // result = 12 
 | ||
|     console.log("My result is ", result); 
 | ||
|   }) 
 | ||
|   .catch((err) => { 
 | ||
|     // If any part of the chain is rejected, print the error message. 
 | ||
|     console.log(err); 
 | ||
|   }); 
 | ||
| ```
 | ||
| 
 | ||
| Это полезно для использования парадигмы _функционального программирования_ . Создавая функции для манипулирования данными, вы можете объединить их вместе, чтобы собрать окончательный результат. Если в любой точке цепочки функций значение _отклоняется,_ цепь перейдет к ближайшему обработчику `catch()` .
 | ||
| 
 | ||
| Для получения дополнительной информации о функциональном программировании: [функциональное программирование](https://en.wikipedia.org/wiki/Functional_programming)
 | ||
| 
 | ||
| ## Генераторы функций
 | ||
| 
 | ||
| В последних выпусках JavaScript ввел больше способов изначально обрабатывать обещания. Одним из таких способов является генератор функций. Генераторы функций являются «правдоподобными» функциями. При использовании с Promise генераторы могут сделать использование намного проще для чтения и появиться «синхронно».
 | ||
| 
 | ||
| ```javascript
 | ||
| const myFirstGenerator = function* () { 
 | ||
|   const one = yield 1; 
 | ||
|   const two = yield 2; 
 | ||
|   const three = yield 3; 
 | ||
|  
 | ||
|   return 'Finished!'; 
 | ||
|  } 
 | ||
|  
 | ||
|  const gen = myFirstGenerator(); 
 | ||
| ```
 | ||
| 
 | ||
| Вот наш первый генератор, который вы можете видеть по синтаксису `function*` . Объявленная переменная `gen` не будет запускать `myFirstGenerator` , но вместо этого «этот генератор будет готов к использованию».
 | ||
| 
 | ||
| ```javascript
 | ||
| console.log(gen.next()); 
 | ||
|  // Returns { value: 1, done: false } 
 | ||
| ```
 | ||
| 
 | ||
| Когда мы запустим `gen.next()` он отключит генератор и продолжит работу. Поскольку это первый раз, когда мы вызвали `gen.next()` он будет работать с `yield 1` и приостанавливаться до тех пор, пока мы снова не назовем `gen.next()` . Когда вызывается `yield 1` , он возвращает нам `value` которое было получено, и независимо от того, `done` ли генератор.
 | ||
| 
 | ||
| ```javascript
 | ||
| console.log(gen.next()); 
 | ||
|  // Returns { value: 2, done: false } 
 | ||
|  
 | ||
|  console.log(gen.next()); 
 | ||
|  // Returns { value: 3, done: false } 
 | ||
|  
 | ||
|  console.log(gen.next()); 
 | ||
|  // Returns { value: 'Finished!', done: true } 
 | ||
|  
 | ||
|  console.log(gen.next()); 
 | ||
|  // Will throw an error 
 | ||
| ```
 | ||
| 
 | ||
| Поскольку мы продолжаем называть `gen.next()` он будет продолжать идти на следующий `yield` и приостанавливать каждый раз. После того, как у вас больше нет `yield` , он продолжит работу с остальной частью генератора, которая в этом случае просто вернется `'Finished!'` , Если вы снова вызове `gen.next()` , он будет генерировать ошибку по завершении работы генератора.
 | ||
| 
 | ||
| Теперь представьте, что если каждый `yield` в этом примере был `Promise` , сам код выглядел бы крайне синхронно.
 | ||
| 
 | ||
| ### Promise.all (iterable) очень полезен для множественного запроса к другому источнику
 | ||
| 
 | ||
| Метод Promise.all (iterable) возвращает единственное обещание, которое разрешает, когда все обещания в итерабельном аргументе разрешены или когда аргумент итерации не содержит никаких обещаний. Он отвергает причину первого обещания, которое отвергает.
 | ||
| 
 | ||
| ```javascript
 | ||
| var promise1 = Promise.resolve(catSource); 
 | ||
|  var promise2 = Promise.resolve(dogSource); 
 | ||
|  var promise3 = Promise.resolve(cowSource); 
 | ||
|  
 | ||
|  Promise.all([promise1, promise2, promise3]).then(function(values) { 
 | ||
|   console.log(values); 
 | ||
|  }); 
 | ||
|  // expected output: Array ["catData", "dogData", "cowData"] 
 | ||
| ```
 | ||
| 
 | ||
| ### Больше информации
 | ||
| 
 | ||
| Для получения дополнительной информации о обещаниях: [обещания](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) |