使用来自 Node/Express 中间 API 的多个 API 调用,尝试使用 promise.all()

Working with multiple API calls from a Node/Express intermediate API, trying to use promise.all()

提问人:Jeffrey Bentley 提问时间:4/12/2023 最后编辑:halferJeffrey Bentley 更新时间:4/19/2023 访问量:52

问:

在这个项目中,我发现了我的理解中的各种差距。我正在构建一个中间 API 服务器。一些端点获取一组信息,然后对每条信息进行外部调用,然后对响应进行一些操作,最终需要在完成所有操作后发送响应。

我通常一次处理一个电话,并认为我对 Async Await 有很好的掌握。三年前,我使用 Promise.all() 进行一些并行调用,但这是一个时代,这并不完全是以相同的方式翻译。我还尝试使每个步骤都在事物上并链接 .then()s,但是我的一些函数没有看到异步/不会触发 .我看过的所有文档都让我走到了一半,但我仍然卡住了。.then()

const createUserDir = async (req, res) =>{
    // make User Directory
    fs.mkdir(path.join(__dirname, `../Users/${req.body.userID}`), { recursive: true },(err)=>{
        if (err) {
            return console.error(err);
        }
        getAllAssetImages(req.body.assets, req.body.config, req.body.userID, res)
    })
}

const getAllAssetImages =async (assets, config, userID, response)=> {
    
    try {
        const allAssets = await Promise.all(
            assets.map(asset => (
// utils.getAsset is an axios call to get a file, this works
                utils.getAsset(asset, config)
                .then(res => fs.mkdir(path.join(__dirname, `../Users/${userID}/${asset.assetId}`),
                ()=>fs.writeFile(path.join(__dirname, `../Users/${userID}/${asset.assetId}/${asset.assetId}.pptx`), res.data, {encoding: 'binary'}, async (err) => {
                    if (err){
                        console.log(err.code)
                    } else {
                        console.log("File written successfully")
//convertPPTS.convertPPTS is an async function that uses ppt-png npm package: works    
                    convertPPTS.convertPPTS([path.join(__dirname,`../Users/${userID}/${asset.assetId}/${asset.assetId}.pptx`)],path.join(__dirname,`../Users/${userID}/${asset.assetId}/`))
                       
                    } 
                }
            ))
        )
            )))
            .then(()=>{
                console.log('please log at the end')
                response.send({status:200, body:'assets available!'})
    })
            console.log('all the promises', allAssets)
        } catch (err){
            throw Error(err)
        }
}

router.post('/', (req,res) => {
     createUserDir(req, res)
     .then(()=>{console.log('all assets written')})
})


export default { router }

它通常会完成获取,写入转换三个文件中的 2 个,然后说它已经完成,然后在它尝试转换尚未存在的文件时抛出错误。

JavaScript 节点.js 异步 回调 promise.all

评论

0赞 Bergi 4/12/2023
首先删除 和 回调。使用代替 .fs.mkdirfs.writeFilefs/promisesfs
0赞 Jeffrey Bentley 4/13/2023
fs/promise 有一些关于性能的符号,所以我避免了它们,因为我对它的理解有点少。话虽如此,我确信我正在做出各种性能牺牲
0赞 Bergi 4/13/2023
不确定您所说的“一些关于性能的符号”是什么意思。你绝对应该使用该模块(除非你需要支持不提供它的旧 node.js 版本),首先关注干净和可读的代码,以使其正常工作。您不会注意到性能差异 - 即使您注意到了,也不应该过早优化,而应仅在您拥有工作版本之后进行优化。

答:

0赞 Jeffrey Bentley 4/13/2023 #1

我做的最重要的事情是删除了 .then() 和 await promise 的混合,倾向于 promise 和 async await。我相信,通过允许其中一些并行运行,并改变正在等待的内容,还有优化的空间。

const createUserDir = async (req) => {
  let { assets, userID, SP } = req.body;

  fs.mkdir(path.join(__dirname, `../Users/${req.body.userID}`), { recursive: true }, (err) => {
      if (err) {
        console.error(err.message)
        return (err);
      }
    }
  );
  await getAllAssetImages(assets, SP, userID);
};

const getAllAssetImages = async (assets, config, userID) => {
  try {
    await Promise.all(
      assets.map(async (asset) => {
        let res = await showpadUtils.getAsset(asset, config);
        await new Promise((resolve, reject) =>
          fs.mkdir( path.join(__dirname, `../Users/${userID}/${asset.assetId}`), () => (
            fs.writeFile(path.join(__dirname, `../Users/${userID}/${asset.assetId}/${asset.assetId}.pptx`),
                res.data,
                { encoding: "binary" },
                async (err) => {
                  if (err) {
                    console.log(err.code);
                  } else {
                    console.log("File written successfully");
                    resolve(
                      convertPPTS.convertPPTS(
                        [
                          path.join(__dirname, `../Users/${userID}/${asset.assetId}/${asset.assetId}.pptx`),
                        ],
                        path.join(__dirname, `../Users/${userID}/${asset.assetId}/`)
                      )
                    );
                  }
                }
              )
          )
          )
        );
      })
    );

    console.log("please log at the end");
} catch (err) {
    throw Error(err);
}
};

router.post("/", async (req, res) => {
    await createUserDir(req);
    console.log("all assets written");
    res.send({ status: 200, body: "assets available!" });
});

评论

0赞 Bergi 4/13/2023
不要使用函数作为回调 - 你没有做任何事情,即使你这样做了,你也应该只承诺而不是包装业务逻辑。此外,而不是 do call ,并且 是没有意义的,应该省略。asyncfs.writeFileawaitwriteFileif (err) { console.log(err.code); }reject} catch (err) { throw Error(err); }
0赞 Bergi 4/13/2023
你不是在等../Users/${req.body.userID} 完成。fs.mkdir(path.join(__dirname, ), …)