脚本只打印数组中的最后一个文件而不是所有文件
Script only prints last file in array instead of all files
我正在阅读 Flannagan 7ed 的 JavaScript 权威指南 中有关 Promises 的内容。书中有一个脚本展示了如何为任意数量的 URL 动态构建 Promise 链。脚本如下:
function fetchSequentially(urls) {
// We'll store the URL bodies here as we fetch them
const bodies = [];
// Here's a Promise-returning function that fetches one body
function fetchOne(url) {
return fetch(url)
.then(response => response.text())
.then(body => {
// We save the body to the array, and we're purposely
// omitting a return value here (returning undefined)
bodies.push(body);
});
}
// Start with a Promise that will fulfill right away (with value undefined)
let p = Promise.resolve(undefined);
// Now loop through the desired URLs, building a Promise chain
// of arbitrary length, fetching one URL at each stage of the chain
for (url of urls) {
p = p.then(() => fetchOne(url));
}
// When the last Promise in that chain is fulfilled, then the
// bodies array is ready. So let's return a Promise for that
// bodies array. Note that we don't include any error handlers:
// we want to allow errors to propagate to the caller.
return p.then(() => bodies);
}
//The script was run as below
//I added the line below to declare the urls array
let urls = ['/data.txt', '/readme.txt', '/textfile.txt'];
//the line below is from the book
fetchSequentially(urls)
.then(bodies => {
console.log(bodies)
})
.catch(e => console.error(e));
我将 let urls
行添加到 运行 脚本以在我的 PC 上获取 3 个文本文件。
当脚本 运行s 似乎只获取最后一个文件 textfile.txt
时,它会在控制台打印第三个文件的内容 3 次。我以为脚本会检索所有 3 个文件的内容,将它们添加到主体数组,然后将所有 3 个文件的内容记录到控制台。
谁能看出这不起作用的原因?
看起来这是导致问题的部分:
for(url of urls) {
p = p.then(() => fetchOne(url));
}
这里您正在创建一个全局变量 url
,并且由于它是 运行 异步的,fetchOne(url)
正在使用它的最后一个实例。
相反,您可以这样做:
for(let url of urls) {
p = p.then(() => fetchOne(url));
}
这会为每次迭代创建 url
的本地实例。
这种异步遍历数组的编程风格会引入像这样的细微错误,所以我推荐一种每次迭代都明确创建一个新实例的风格。类似于:
urls.forEach(function (url) {
p = p.then(() => fetchOne(url));
});
虽然对于这种有多个承诺的事情,你可能只想用 Promise.all
做一个 .map
:
return Promise.all(urls.map(fetchOne)); // instead of promise chaining with p
我正在阅读 Flannagan 7ed 的 JavaScript 权威指南 中有关 Promises 的内容。书中有一个脚本展示了如何为任意数量的 URL 动态构建 Promise 链。脚本如下:
function fetchSequentially(urls) {
// We'll store the URL bodies here as we fetch them
const bodies = [];
// Here's a Promise-returning function that fetches one body
function fetchOne(url) {
return fetch(url)
.then(response => response.text())
.then(body => {
// We save the body to the array, and we're purposely
// omitting a return value here (returning undefined)
bodies.push(body);
});
}
// Start with a Promise that will fulfill right away (with value undefined)
let p = Promise.resolve(undefined);
// Now loop through the desired URLs, building a Promise chain
// of arbitrary length, fetching one URL at each stage of the chain
for (url of urls) {
p = p.then(() => fetchOne(url));
}
// When the last Promise in that chain is fulfilled, then the
// bodies array is ready. So let's return a Promise for that
// bodies array. Note that we don't include any error handlers:
// we want to allow errors to propagate to the caller.
return p.then(() => bodies);
}
//The script was run as below
//I added the line below to declare the urls array
let urls = ['/data.txt', '/readme.txt', '/textfile.txt'];
//the line below is from the book
fetchSequentially(urls)
.then(bodies => {
console.log(bodies)
})
.catch(e => console.error(e));
我将 let urls
行添加到 运行 脚本以在我的 PC 上获取 3 个文本文件。
当脚本 运行s 似乎只获取最后一个文件 textfile.txt
时,它会在控制台打印第三个文件的内容 3 次。我以为脚本会检索所有 3 个文件的内容,将它们添加到主体数组,然后将所有 3 个文件的内容记录到控制台。
谁能看出这不起作用的原因?
看起来这是导致问题的部分:
for(url of urls) {
p = p.then(() => fetchOne(url));
}
这里您正在创建一个全局变量 url
,并且由于它是 运行 异步的,fetchOne(url)
正在使用它的最后一个实例。
相反,您可以这样做:
for(let url of urls) {
p = p.then(() => fetchOne(url));
}
这会为每次迭代创建 url
的本地实例。
这种异步遍历数组的编程风格会引入像这样的细微错误,所以我推荐一种每次迭代都明确创建一个新实例的风格。类似于:
urls.forEach(function (url) {
p = p.then(() => fetchOne(url));
});
虽然对于这种有多个承诺的事情,你可能只想用 Promise.all
做一个 .map
:
return Promise.all(urls.map(fetchOne)); // instead of promise chaining with p