我正在尝试了解承诺链的内部运作方式。我知道对 Promise 调用 then() 总是返回一个新的 Promise。
当从 then() 回调中返回 Promise 时,它是否会替换 then() 本身返回的 Promise?换句话说,内部承诺取代了链中的外部承诺。
如果能知道这个承诺链实际上会是什么样子的话那就太好了:
function fetchData() {
console.log("Fetching data...");
return fetch('https://api.example.com/data1')
.then(data1 => {
console.log("Data 1 fetched");
return fetch('https://api.example.com/data2');
})
.then(data2 => {
console.log("Data 2 fetched");
return { data1, data2 };
});
}
还有一个旁注,如果我要在这段代码中添加对 then() 的最终调用,该调用除了记录某些内容而不返回之外什么也不做,那么 then() 创建的承诺将用 data2 值来解析?
当从
回调中返回 Promise 时,它是否会替换then()
本身返回的 Promise?then()
不。
then
本身返回的promise已经被返回,因此它代表一个不同的对象,它甚至可以被分配给一个变量。如果是这样,该变量将不会获得第二次赋值来替换它第一次引用的对象。
这两个 Promise 是不同的对象,但第一个 Promise 被“锁定”到第二个 Promise。正如ECMA脚本规范所说:
如果一个 Promise 已解决或者已被“锁定”以匹配另一个 Promise 的状态,则该 Promise 是“已解决”。
在您的代码示例中有这些承诺对象
由第一个返回
fetch
then
then
fetchData
返回的值)由第二个fetch
then
返回的值被锁定以匹配其状态。
then()
的最终调用,该调用除了记录某些内容而不返回之外什么也不做,那么
创建的承诺将通过then()
值来解决? 不,不会。您希望data2
then()
承诺解决的值应该由
then
回调返回。如果您只记录某些内容而不返回显式值,则返回值是 undefined
,这就是 Promise 将解析的值。其他备注
data1
回调中引用了
then
,但未定义。 data1
变量的范围是第一个 then
回调的局部范围。如果您希望它沿着 Promise 链传递,您应该确保它是(向下)链中每个 Promise 的分辨率值的一部分。
其次,
fetch
还没有返回数据,而是返回一个响应对象。您需要使用像
json()
这样的方法来消费数据流,并等待该方法返回的promise。在 async
/
await
语法可用之前,您可以这样做:// Helper function
function getJson(url) {
return fetch(url).then(response => response.json());
}
function fetchData() {
console.log("Fetching data...");
return getJson('https://api.example.com/data1').then(data1 => {
console.log("Data 1 fetched");
// Pass data1 down the promise chain
return Promise.all([data1, getJson('https://api.example.com/data2')]);
}).then(([data1, data2]) => {
console.log("Data 2 fetched");
return { data1, data2 };
});
}
使用
async
/
await
这个范围问题就消失了:async function fetchData() {
console.log("Fetching data...");
const data1 = await getJson('https://api.example.com/data1');
console.log("Data 1 fetched");
const data2 = await getJson('https://api.example.com/data2');
console.log("Data 2 fetched");
return { data1, data2 };
}
最后,如果第二个请求不依赖于第一个请求的响应,您可以发出第二个请求而无需等待第一个响应:
async function fetchData() {
console.log("Fetching data... (both requests)");
const [data1, data2] = await Promise.all([
getJson('https://api.example.com/data1'),
getJson('https://api.example.com/data2')
]);
return { data1, data2 };
}