首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >深度Promise.all

深度Promise.all
EN

Stack Overflow用户
提问于 2020-06-26 18:13:01
回答 2查看 240关注 0票数 0

我有一个承诺链,以保存文件列表结束。我想等到所有文件保存或失败,然后继续我的链子。问题是,当我在有自己的子链的承诺列表上使用Promise.all时,Promise.all上的thens开始解决,而then则在Promise.all内的承诺上开始解决。请参阅下面的注释示例。

代码语言:javascript
复制
const fs = require('fs');
const util = require('util');
// Make a promise out of the file write function
const promiseWriteFile = (file, data, options) => {
    return util.promisify(fs.writeFile).call(fs, file, data, options);
};

...

console.log('Received files');
console.group();
// Start long promise chain
somePromise(...)
    .then((result) => {
        console.log('validating blah blah');
    })
    .then((result) => {
        ...
    })
    .then((result) => {
        // Now I need to save the files to the disk
        let path = './uploaded_files/';
        // Here I want to resolve all the file save promises, or find one that fails
        return Promise.all(
            request.files.map((file) => {
                let filename = path + Date.now() + '_' + file.originalname;
                // Purposely change `path` so that the next file write will fail
                path = './garbage/';
                console.log('Trying to save file:', filename);
                return promiseWriteFile(filename, file.buffer, 'binary')
                    .then(() => {
                        console.log('Saving file:', filename);
                    })
                    .catch((error) => {
                        console.log('Could not save file:', filename);
                        throw error;
                    });
            }),
        );
    })
    .then(() => { // <======= I don't want this to happen until the promises in the `Promise.all` above have fully, DEEPLY resolved
        // set success message
        message = 'Part successfully created.';
        console.groupEnd();
        console.log('Part created successfully.');
    })
    .catch((exception) => {
        message = exception.message;
        console.groupEnd();
        console.log('Part invalid.');
    });

输出结果如下:

代码语言:javascript
复制
Received files
  validating blah blah
  Trying to save file: ./uploaded_files/A.txt
  Trying to save file: ./garbage/B.txt
Part invalid.
Could not save file: ./garbage/B.txt
Saving file: ./uploaded_files/A.txt

因此,正如您所看到的,打印“无法保存文件”和“保存文件”的行在大承诺链的“那时/捕获”之后执行。您可以判断,因为console.groupEnd()首先被调用,然后才有进一步的输出。

如何确保在所有的子承诺完成之前,大承诺链上的捕获不会发生?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-06-26 18:22:25

您正在map上的catch块中抛出错误

代码语言:javascript
复制
.catch((error) => {
  console.log('Could not save file:', filename);
  throw error;
});

这破坏了您的Promise.all(),并导致它在完成所有承诺之前在其链中捕获。相反,您应该只是转发该错误,而不是崩溃错误链。您需要重新考虑如何确认所有的写入和以下步骤。

稍后处理返回的示例:

代码语言:javascript
复制
    .then((result) => {
        let path = './uploaded_files/';
        return Promise.all(
            request.files.map((file) => {
                let filename = path + Date.now() + '_' + file.originalname;
                path = './garbage/';
                console.log('Trying to save file:', filename);
                return promiseWriteFile(filename, file.buffer, 'binary')
                    .then(() => {
                        return  { filename };
                    })
                    .catch((error) => {
                        return { error, filename };
                    });
            }),
        );
    })
    .then((results) => {
        const successes = results.filter(({ error }) => !error);
        const failures = results.filter(({ error }) => error);
        // process them here
    })

现在您可以以您想要的方式处理它们,并且每个对象在返回中都有一个文件名,允许您识别它们,删除它们,不管您想要什么。

票数 1
EN

Stack Overflow用户

发布于 2020-06-26 18:20:37

当您在.catch上使用promise.all时,它将为您添加的每个子承诺添加捕获。没有"catchFinally“方法。

要阻止其他承诺的发生,请看下面的示例:

代码语言:javascript
复制
Promise.config({ cancellation: true }); // <-- enables this non-standard feature

const promise1 = new Promise((resolve, reject) => {
    setTimeout(resolve, 1000, 'resolve1');
}).then(a => { console.log('then1'); return a; });

const promise2 = new Promise((resolve, reject) => {
    setTimeout(reject, 2000, 'reject2');
}).then(a => { console.log('then2'); return a; });

const promise3 = new Promise((resolve, reject) => {
    setTimeout(resolve, 3000, 'resolve3');
}).then(a => { console.log('then3'); return a; });

const promises = [promise1, promise2, promise3];

Promise.all(promises)
    .then(values => { 
        console.log('then', values); 
    })
    .catch(err => { 
        console.log('catch', err); 
        promises.forEach(p => p.cancel()); // <--- Does not work with standard promises
    });

请注意,即使promise3被取消,它的setTimeout回调仍将被调用。但它不会触发当时的回调或捕捉回调。就好像这个承诺永远不会达成决议.永远不会。

票数 -2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/62600602

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档