简体   繁体   English

Js:链接以清晰易读的方式承诺链接

[英]Js : Chaining promises chains in a clear and readable way

Hello there overflowers, 您好,有溢水者,

I'm currently working on a project of mine, using a node server with a mongo data store. 我目前正在使用带有mongo数据存储的节点服务器来开发我的项目。 I'm currently writing some functions to populate the database for me. 我目前正在编写一些函数来为我填充数据库。
Examples of objects in the database are Users,Classes,School Years,Students ratings, etc. 数据库中对象的示例包括“用户”,“班级”,“学年”,“学生评分”等。
All the functions to create such objects are implemented like this : 创建此类对象的所有功能都是这样实现的:

    function popUser(users){
        chain = [];
        users.forEach((v,i,a)=>{
            let p = new Promise(function(res,rej){
                let newU = new User(v);
                newU.save(()=>{
                    err && rej(err);
                    res();
                });
            });
            chain.push(p);
        });
        return chain
    }

In the remainder of my population module i invoke such functions depending on my needs. 在我的总体模块的其余部分中,我将根据我的需求调用此类功能。 The order in which the above functions are called is important, thus I don't want fully parallel execution of constructors. 调用上述函数的顺序很重要,因此我不希望完全并行执行构造函数。

With Promises I could do something like this : 有了Promises,我可以做这样的事情:

popUser(users).then(popClasses).then(...). ... .catch((err)=>{})

With Promises Chains I know that I can do the following 有了Promises Chains,我知道我可以做到以下几点

Promise.all(usersChain).then(()=>{
    //make a new chain for Classes
    Promise.all(classesChain).then (()=>{},(err)=>{})
},(err)=>{})

I think we can agree that it becomes quite hard to read and understand, thus the question : 我认为我们可以同意,阅读和理解变得非常困难,因此提出了一个问题:

Is there a way of achieving the same results with a different, more readable syntax? 是否有一种方法可以使用其他更易读的语法来达到相同的结果?

Edit : to be clearer, usersChain and cleassesChains are arrays of Promises to create and insert some object (or objects) into the database. 编辑:更清楚地说,usersChain和cleassesChains是Promises的数组,用于创建一些对象(一个或多个)并将其插入数据库。 I can not make a single chain because some objects might have to be inserted after some other objects have already been inserted. 我无法创建单个链,因为某些对象可能已经插入,而某些对象可能必须插入。

Edit : Wait, can I just call 编辑:等等,我可以打电话吗

Promsie.all(populateCountersPromise).then(promise1).then(promise2).catch((err)=>{})

There are different parts in the code that won't work, or should not be written that way. 代码中有不同的部分无法正常工作,或者不应以这种方式编写。

If you use shortcuts like this: 如果您使用这样的快捷方式:

err && rej(err);
res();

You should know what they mean, because this is equal to: 您应该了解它们的含义,因为这等于:

if( err ) { 
  rej(err);
}
res();

So if an error occurs both rej and res are called. 因此,如果发生错误,则会同时rejres

From your popUser you return an array of Promises, so popUser(users).then(popClasses) would fail, because you cannot call .then on an array. 从您的popUser返回承诺的数组,所以popUser(users).then(popClasses)将失败,因为你不能叫.then阵列上。

The first thing you should do, is to clean up your popUser function: 您应该做的第一件事是清理您的popUser函数:

function popUser(users) {

  let promises = users.map((v, i, a) => {
    return new Promise(function(res, rej) {
      let newU = new User(v);
      newU.save(err => {
        if (err) {
          rej(err)
        } else {
          res()
        }
      });
    });
  });

  return Promies.all(promises)
}

Use .map instead a forEach with a push , because it makes it clear right from the beginning what you do. 使用.map代替使用forEach进行push ,因为它从一开始就使您清楚地知道要做什么。 And use Promies.all to return a Promise from your function that waits for all users to be saved, if you do the same for popClasses you can write it like: 并使用Promies.all从函数中返回一个Promise,等待所有用户被保存,如果对popClasses进行相同操作, popClasses可以这样编写:

popUser(users)
   .then(popClasses)
   .then(...)
   .catch((err)=>{})

If you really want to write it like in your last code snippet, then change it to this: 如果您真的想像上一个代码片段中那样编写它,则将其更改为:

Promise.all(usersChain)
  .then(() => Promise.all(classesChain))
  .then(() => {})
  .catch(err => {})

Many APIs now adays support both the classical callbacks and Promises, so you could improve your popUser further: 如今,当今许多API都支持经典的回调和Promises,因此您可以进一步改善popUser

function popUser(users) {
  let promises = users.map(v => new User(v).save())
  return Promies.all(promises)
}

Mongoose callbacks are legacy API. 猫鼬回调是旧版API。 Mongoose supports promises for a long time and doesn't need to be promisified. 猫鼬支持诺言很长一段时间,不需要被承诺。

For concurrent promises, forEach can be replaced with map , this is exact use case for the latter: 对于并发的Promise, forEach可以用map代替,这是后者的确切用例:

function popUser(users){
  return Promise.all(
    users.map(userData => new User(userData).save())
  );
}

async..await can be used in the rest of the cases where promises should be sequential: async..await可以在promise应该是顺序的其余情况下使用:

try {
  await popUser(users);
  await popClasses();
  ...
} catch (err) {
  ...
}

Why not return Promise.all(chain) in function popUser . 为什么不返回Promise.all(chain)函数中的popUser Promise.all(chain)

Returning a Promise is better to match semantic of popUser which is a function of doing something asynchronously.Returning array of promise is confusing. 返回Promise更好地匹配popUser语义,后者是异步执行的功能。返回promise数组会造成混淆。

Then you can use popUsers.then(popClasses).then(...). ... .catch((err)=>{}) 然后,您可以使用popUsers.then(popClasses).then(...). ... .catch((err)=>{}) popUsers.then(popClasses).then(...). ... .catch((err)=>{}) to queue up promises popUsers.then(popClasses).then(...). ... .catch((err)=>{})来排队诺言

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM