承诺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工作, return
或throw
就太迟了,不是吗?
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
解决任何p2
parsing,无论是成功还是失败”。
至于这是怎么发生的,它是特定于实现的。 在内部,你可以把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实现如何处理这个 。
基本上p3
是return
另一个承诺: 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
只是一个函数和一个值,应用函数对值进行解开结果,从而将一个嵌套的数组结构降低一级。
简而言之, then
在Promise
的上下文中,就等价于在Array
的上下文中将map
与flatten
合并在一起。 这种行为是非常重要的。 我们不仅可以将正常的function应用于Promise
而且可以将自身的function应用于Promise
。
事实上,这是函数式编程的范畴。 Promise
是monad的具体实现, then
是bind
/ chain
,返回Promise
的函数是monadic函数。 当你了解Promise
API时,你基本上可以理解所有单子。
- 节点JS Promise.all和forEach
- 多个`.then()`在单个的angularjs承诺 – 所有使用_original_数据
- 为什么onRejected没有调用Promise.all()数组中包含的Promise.reject()传递给Promise.all()?
- 事件循环上下文中的微任务和macros任务之间的区别
- JavaScript Promisecallback是asynchronous执行的
- 了解node.js中的承诺
- 承诺:然后vs +然后捕获
- 通过forEach循环使用async / await
- 如何find哪些promise在nodejs中未处理UnhandledPromiseRejectionWarning?