2017-01-12 5 views
0

Я в сценарии, где у меня есть promise внутри promise. Однако при вызове .then на содержащем promise я получаю результат моего внутреннего обещания. Это здорово, но я не понимаю, почему это работает. Почему я могу это сделать:Наблюдаемый как обещание вложенное в обещание

this.dataService.init().then(d => console.log(d)); 

вместо этого:

this.dataService.init().then(p => p.then(d => console.log(d)); 

DataService

init(){ 
    return this.geo.init().then(p => this.get(p.lat, p.lon)); 
    } 

    get(lat, lon){ 
    let uri = `${this.baseuri}lat=${lat}&lon=${lon}&appid=${this.appid}` 
    //this returns a promise 
    return this.http.get(uri).toPromise() 
     .then(d => d.json() || {}); 
    } 

геолокации служба

init(){ 
    return new Promise(this.getGeolocation); 
    } 

ответ

3

Когда вы возвращаете обещание изнутри обработчика .then(), внешнее обещание и внутреннее обещание соединяются вместе. Внешнее обещание затем получит свою ценность от внутреннего обещания, и внешнее обещание не будет называть его обработчиками .then(), пока не будет разрешено внутреннее обещание.

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

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

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

Таким образом, в этой строке:

return this.geo.init().then(p => this.get(p.lat, p.lon)); 

Вот последовательность операций:

  1. Вызов this.geo.init(). Это возвращает обещание, мы назовем p1.
  2. Позвоните .then() по этому обещанию и передайте ему обратный вызов. Это регистрирует обработчик обратного вызова .then(), который будет вызван позже, когда будет разрешено предыдущее обещание. Он также возвращает новое обещание, которое возвращается из вашей функции. Мы назовем это обещание p2. Это один из ключей, который позволяет этому работать.
  3. Теперь p1 в конечном итоге решает. Это вызывает зарегистрированный на нем обратный вызов обработчика .then(). Это вызывает this.get(...), который возвращает другое обещание p3, которое возвращается изнутри этого обработчика .then() в качестве возвращаемого значения.
  4. Обещание инфраструктура видит, что вы вернулись обещание от .then() обработчика так он связывает p2 с p3 и p2 не разрешится, пока p3 не делает, и когда p3 делает наконец-то решена, p2 использует разрешенное значение.Ключ, который делает эту работу, заключается в том, что p1 давно разрешен, но p1.then() вернул новое обещание p2, которое вернуло вашу функцию верхнего уровня. И p2 получает прикованное к p3, так p2 не разрешается до тех пор, пока p2 делает и p2 не получает разрешенное значение от p3.

FYI, вы можете цепью на любую произвольную глубину.

1

Функция dataService.init возвращает обещание. Когда вы вызываете функцию, которая возвращает обещание, параметр, который передается в .then(), является тем, что вы получаете ПОСЛЕ того, как обещание было разрешено. Обещание не может разрешить и вернуть ДРУГОЕ обещание к его обратному вызову .then. Он должен ждать, пока первое обещание разрешится первым.

this.dataService.init().then(d => console.log(d));

Когда обратный вызов получает d, оба обещания уже решены, и d это значение, а не обещание. Поэтому не имеет смысла снова называть .then().

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

Например:

const getXhrResult =() => axios.get('/some-url') // returns a promise 

const func1 =() => getXhrResult().then((res) => { 
    console.log('Got the result') 
    return result * 2 // also returns a promise 
} 

const func2 =() => func1().then(console.log) 

func2() // logs the result * 2. 
Смежные вопросы