承诺callback承诺回报

关于这两个重要来源: 新西兰 – 承诺诺言链条和MDN诺言 ,我想问一下:

每次我们从promise履行处理程序返回一个值时,该值是如何传递给从同一个处理程序返回的新的promise的?

例如,

let p1 = new Promise(function(resolve, reject) { resolve(42); }); let p2 = new Promise(function(resolve, reject) { resolve(43); }); let p3 = p1.then(function(value) { // first fulfillment handler console.log(value); // 42 return p2; }); p3.then(function(value) { // second fulfillment handler console.log(value); // 43 }); 

在这个例子中, p2是一个承诺。 p3也是p1履行处理程序的承诺。 然而p2 !== p3 。 相反, p2以某种方式神奇地解决了43 (如何?),然后这个价值被传递给p3的执行处理程序。 即使这里的句子也是令人困惑的。

你能向我解释一下这里究竟发生了什么? 我完全理解这个概念。

then()就说抛出内部then()callback抛弃了失败的结果,并且从then()callbackthen()callback执行成功的值。

 let p2 = p1.then(() => { throw new Error('lol') }) // p2 was rejected with Error('lol') let p3 = p1.then(() => { return 42 }) // p3 was fulfilled with 42 

但是有时候,即使是在延续的过程中,我们也不知道我们是否成功了。 我们需要更多的时间。

 return checkCache().then(cachedValue => { if (cachedValue) { return cachedValue } // I want to do some async work here }) 

但是,如果我在那里做asynchronous工作, returnthrow就太迟了,不是吗?

 return checkCache().then(cachedValue => { if (cachedValue) { return cachedValue } fetchData().then(fetchedValue => { // Doesn't make sense: it's too late to return from outer function by now. // What do we do? // return fetchedValue }) }) 

这就是为什么承诺如果你不能解决另一个承诺是没有用的。

这并不意味着在你的例子中p2变成 p3 。 他们是单独的Promise对象。 但是,通过返回p2来产生p3 then() ,你会说: “我希望p3解决任何p2parsing,无论是成功还是失败”。

至于这是怎么发生的,它是特定于实现的。 在内部,你可以把then()看作是创造一个新的Promise。 只要它喜欢,实现将能够实现或拒绝它。 通常情况下,退货时会自动履行或拒绝:

 // Warning: this is just an illustration // and not a real implementation code. // For example, it completely ignores // the second then() argument for clarity, // and completely ignores the Promises/A+ // requirement that continuations are // run asynchronously. then(callback) { // Save these so we can manipulate // the returned Promise when we are ready let resolve, reject // Imagine this._onFulfilled is an internal // queue of code to run after current Promise resolves. this._onFulfilled.push(() => { let result, error, succeeded try { // Call your callback! result = callback(this._result) succeeded = true } catch (err) { error = err succeeded = false } if (succeeded) { // If your callback returned a value, // fulfill the returned Promise to it resolve(result) } else { // If your callback threw an error, // reject the returned Promise with it reject(error) } }) // then() returns a Promise return new Promise((_resolve, _reject) => { resolve = _resolve reject = _reject }) } 

同样,这是非常多的伪代码,但是显示了如何在Promise实现中实现then()的思想。

如果我们想增加对Promise的parsing支持,那么如果你传递给then()callback返回一个Promise,我们只需要修改代码来创build一个特殊的分支:

  if (succeeded) { // If your callback returned a value, // resolve the returned Promise to it... if (typeof result.then === 'function') { // ...unless it is a Promise itself, // in which case we just pass our internal // resolve and reject to then() of that Promise result.then(resolve, reject) } else { resolve(result) } } else { // If your callback threw an error, // reject the returned Promise with it reject(error) } }) 

让我再次澄清,这不是一个实际的Promise实现,并且有很大的漏洞和不兼容性。 然而,它应该给你一个直观的Promise图书馆如何实现解决诺言的想法。 当你对这个想法感到满意后,我build议你看一看Promise实现如何处理这个 。

基本上p3return另一个承诺: p2 。 这意味着p2的结果将作为parameter passing给下一个callback函数,在这种情况下,它将parsing为43

无论何时使用关键字return您都将结果作为parameter passing给next的callback函数。

 let p3 = p1.then(function(value) { // first fulfillment handler console.log(value); // 42 return p2; }); 

你的代码:

 p3.then(function(value) { // second fulfillment handler console.log(value); // 43 }); 

等于:

 p1.then(function(resultOfP1) { // resultOfP1 === 42 return p2; // // Returning a promise ( that might resolve to 43 or fail ) }) .then(function(resultOfP2) { console.log(resultOfP2) // '43' }); 

顺便说一句,我注意到你正在使用ES6的语法,你可以使用胖箭头语法有一个更轻的语法:

 p1.then(resultOfP1 => p2) // the `return` is implied since it's a one-liner .then(resultOfP2 => console.log(resultOfP2)); 

在这个例子中,p2是一个承诺。 p3也是来自p1的执行处理程序的承诺。 然而p2!== p3。 相反,p2以某种方式神奇地解决了43(如何?),然后这个价值被传递给p3的执行处理程序。 即使这里的句子也是令人困惑的。

一个简化的版本如何工作(只有伪代码)

 function resolve(value){ if(isPromise(value)){ value.then(resolve, reject); }else{ //dispatch the value to the listener } } 

整个事情是比较复杂的,因为你必须小心,这个承诺已经解决了,还有更多的事情。

我会试着回答“为什么callback可以回复Promise s自己”更加规范的问题。 换一个angular度来看,我比较了Promise和一个不那么复杂和容易混淆的容器types – Array

Promise是未来价值的容器。 Array是一个任意数量值的容器。

我们不能将正常的函数应用于容器types:

 const sqr = x => x * x; const xs = [1,2,3]; const p = Promise.resolve(3); sqr(xs); // fails sqr(p); // fails 

我们需要一种机制将它们提升到特定容器的环境中:

 xs.map(sqr); // [1,4,9] p.then(sqr); // Promise {[[PromiseValue]]: 9} 

但是当提供的函数本身返回一个相同types的容器时会发生什么?

 const sqra = x => [x * x]; const sqrp = x => Promise.resolve(x * x); const xs = [1,2,3]; const p = Promise.resolve(3); xs.map(sqra); // [[1],[4],[9]] p.then(sqrp); // Promise {[[PromiseValue]]: 9} 

sqra行为像预期的一样。 它只是返回一个正确值的嵌套容器。 这显然不是很有用。

但是怎样才能解释sqrp的结果呢? 如果我们遵循自己的逻辑,它必须是Promise {[[PromiseValue]]: Promise {[[PromiseValue]]: 9}} – 但事实并非如此。 那么这里有什么魔法呢?

为了重build机制,我们只需要稍微调整我们的map方法:

 const flatten = f => x => f(x)[0]; const sqra = x => [x * x]; const sqrp = x => Promise.resolve(x * x); const xs = [1,2,3]; xs.map(flatten(sqra)) 

flatten只是一个函数和一个值,应用函数对值进行解开结果,从而将一个嵌套的数组结构降低一级。

简而言之, thenPromise的上下文中,就等价于在Array的上下文中将mapflatten合并在一起。 这种行为是非常重要的。 我们不仅可以将正常的function应用于Promise而且可以将自身的function应用于Promise

事实上,这是函数式编程的范畴。 Promisemonad的具体实现, thenbind / chain ,返回Promise的函数是monadic函数。 当你了解Promise API时,你基本上可以理解所有单子。