承诺回调返回承诺
Promise callbacks returning promises
关于这两个伟大的来源:NZakas - Returning Promises in Promise Chains and MDN Promises,我想问以下问题:
每次我们 return 来自 promise fulfillment 处理程序的值,该值如何传递给新的 promise return 来自同一处理程序的?
例如,
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
的执行处理程序。就连这里的句子也让人费解。
你能给我解释一下这里到底发生了什么吗?我对这个概念一头雾水。
基本上 p3
是 return
-ing 另一个承诺:p2
。这意味着 p2
的结果将作为参数传递给下一个 then
回调,在本例中它解析为 43
。
每当您使用关键字 return
时,您都会将结果作为参数传递给下一个 then
的回调。
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));
假设在 then()
回调中抛出以失败拒绝结果承诺,而从 then()
回调中 return 执行具有成功值的结果承诺。
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
})
但是,如果我在那里进行异步工作,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
})
})
这就是为什么如果您不能解决另一个 Promise.
,Promise 就没有用的原因
这并不意味着在您的示例中 p2
会 变成 p3
。它们是独立的 Promise 对象。然而,通过 returning p2
从 then()
产生 p3
你是在说 “我想要 p3
解决任何 p2
解析,无论成功还是失败。
至于如何发生这种情况,它是特定于实现的。在内部,您可以将 then()
视为创建一个新的 Promise。实施将能够随时满足或拒绝它。通常,当您 return:
时,它会自动完成或拒绝它
// 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 解析的支持,我们只需要修改代码以在 callback
传递给 then()
returned 时有一个特殊的分支承诺:
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 库如何实现对 Promise 的解析。在您对这个想法感到满意之后,我建议您看一下 Promise 的实际实现方式 handle this.
In this example, p2 is a promise. p3 is also a promise originating from p1's fulfillment handler. However p2 !== p3. Instead p2 somehow magically resolves to 43 (how?) and that value is then passed to p3's fulfillment handler. Even the sentence here is confusing.
这是如何工作的简化版本(只有伪代码)
function resolve(value){
if(isPromise(value)){
value.then(resolve, reject);
}else{
//dispatch the value to the listener
}
}
如果 promise 已经解决,还有一些其他事情,那么整个事情就比较复杂了,因为你必须要小心。
我会尝试更规范地回答"why then
callbacks can return Promise
s themselves"这个问题。换个角度,我将 Promise
s 与一种不那么复杂和混乱的容器类型进行比较 - Array
s.
A Promise
是未来值的容器。
Array
是任意数量值的容器。
我们不能将普通函数应用于容器类型:
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}
但是当提供的函数本身 return 是相同类型的容器时会发生什么?
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
表现符合预期。它只是 return 具有正确值的嵌套容器。这显然不是很有用。
但是如何解释sqrp
的结果呢?如果我们按照自己的逻辑,它必须类似于 Promise {[[PromiseValue]]: Promise {[[PromiseValue]]: 9}}
- 但事实并非如此。那么这里发生了什么魔法?
为了重建机制,我们只需要稍微调整一下我们的 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
的上下文中相当于 map
与 flatten
在 Array
的上下文中组合。这种行为非常重要。 我们不仅可以将普通函数应用于 Promise
,还可以将函数本身 return 应用于 Promise
。
其实这是函数式编程的领域。 Promise
是 monad 的具体实现,then
是 bind
/chain
和 return 的函数s a Promise
是一个单子函数。当你理解了 Promise
API 你基本上理解了所有的单子。
关于这两个伟大的来源:NZakas - Returning Promises in Promise Chains and MDN Promises,我想问以下问题:
每次我们 return 来自 promise fulfillment 处理程序的值,该值如何传递给新的 promise return 来自同一处理程序的?
例如,
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
的执行处理程序。就连这里的句子也让人费解。
你能给我解释一下这里到底发生了什么吗?我对这个概念一头雾水。
基本上 p3
是 return
-ing 另一个承诺:p2
。这意味着 p2
的结果将作为参数传递给下一个 then
回调,在本例中它解析为 43
。
每当您使用关键字 return
时,您都会将结果作为参数传递给下一个 then
的回调。
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));
假设在 then()
回调中抛出以失败拒绝结果承诺,而从 then()
回调中 return 执行具有成功值的结果承诺。
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
})
但是,如果我在那里进行异步工作,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
})
})
这就是为什么如果您不能解决另一个 Promise.
,Promise 就没有用的原因这并不意味着在您的示例中 p2
会 变成 p3
。它们是独立的 Promise 对象。然而,通过 returning p2
从 then()
产生 p3
你是在说 “我想要 p3
解决任何 p2
解析,无论成功还是失败。
至于如何发生这种情况,它是特定于实现的。在内部,您可以将 then()
视为创建一个新的 Promise。实施将能够随时满足或拒绝它。通常,当您 return:
// 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 解析的支持,我们只需要修改代码以在 callback
传递给 then()
returned 时有一个特殊的分支承诺:
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 库如何实现对 Promise 的解析。在您对这个想法感到满意之后,我建议您看一下 Promise 的实际实现方式 handle this.
In this example, p2 is a promise. p3 is also a promise originating from p1's fulfillment handler. However p2 !== p3. Instead p2 somehow magically resolves to 43 (how?) and that value is then passed to p3's fulfillment handler. Even the sentence here is confusing.
这是如何工作的简化版本(只有伪代码)
function resolve(value){
if(isPromise(value)){
value.then(resolve, reject);
}else{
//dispatch the value to the listener
}
}
如果 promise 已经解决,还有一些其他事情,那么整个事情就比较复杂了,因为你必须要小心。
我会尝试更规范地回答"why then
callbacks can return Promise
s themselves"这个问题。换个角度,我将 Promise
s 与一种不那么复杂和混乱的容器类型进行比较 - Array
s.
A Promise
是未来值的容器。
Array
是任意数量值的容器。
我们不能将普通函数应用于容器类型:
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}
但是当提供的函数本身 return 是相同类型的容器时会发生什么?
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
表现符合预期。它只是 return 具有正确值的嵌套容器。这显然不是很有用。
但是如何解释sqrp
的结果呢?如果我们按照自己的逻辑,它必须类似于 Promise {[[PromiseValue]]: Promise {[[PromiseValue]]: 9}}
- 但事实并非如此。那么这里发生了什么魔法?
为了重建机制,我们只需要稍微调整一下我们的 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
的上下文中相当于 map
与 flatten
在 Array
的上下文中组合。这种行为非常重要。 我们不仅可以将普通函数应用于 Promise
,还可以将函数本身 return 应用于 Promise
。
其实这是函数式编程的领域。 Promise
是 monad 的具体实现,then
是 bind
/chain
和 return 的函数s a Promise
是一个单子函数。当你理解了 Promise
API 你基本上理解了所有的单子。