脚本仅在数组中打印最后一个文件,而不是所有文件

发布于 2025-01-21 13:59:45 字数 1849 浏览 1 评论 0原文

我正在阅读有关Flannagan 7ED的 javaScript《权威指南》的有关承诺的信息。在书中有一个脚本,该脚本显示了如何为任意数量的URL动态构建承诺链。脚本如下:

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));

我添加了让URL行以运行脚本以在我的PC上获取3个文本文件。

当脚本运行时,它似乎仅获取最后一个文件textfile.txt,并且在控制台中3次打印出第三文件的内容。我以为脚本将检索所有3个文件的内容,将它们添加到身体数组中,然后将所有3个文件的内容记录到控制器上。

谁能发现为什么这不起作用?

I'm reading about Promises in JavaScript The Definitive Guide by Flannagan 7ed. In the book there is a script which shows how to build a Promise chain dynamically for an arbitrary number of URLs. The script is as follows:

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));

I added the let urls line to run the script to fetch 3 text files on my PC.

When the script runs it seems to only fetch the last file textfile.txt, and it prints out the contents of the third file 3 times in the console. I thought the script would retrieve the contents of all 3 files, add them to the bodies array, and then log the contents of all 3 files to console.

Can anyone spot why this isn't working?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

你的呼吸 2025-01-28 13:59:45

看起来这是引起问题的部分:

   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));
});

尽管有多个承诺的这种事情,您可能只想用.map使用Promise.all

return Promise.all(urls.map(fetchOne)); // instead of promise chaining with p

It looks like this is the section that's causing problems:

   for(url of urls) {
       p = p.then(() => fetchOne(url));
   }

Here you're creating a global variable url, and since it's running asynchronously, fetchOne(url) is using the last instance of it.

Instead you can do something like:

   for(let url of urls) {
       p = p.then(() => fetchOne(url));
   }

This creates a local instance of url for each iteration.

This sort of style of programming of iterating through arrays asynchronously can introduce subtle errors like this one, so I'd recommend a style that unambiguously creates a new instance per iteration. Something like:

urls.forEach(function (url) {
   p = p.then(() => fetchOne(url));
});

Though for this sort of thing with multiple promises, you might just want to do a .map with Promise.all:

return Promise.all(urls.map(fetchOne)); // instead of promise chaining with p
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文