繁体   English   中英

承诺链和匿名承诺回报

[英]Promise chains and anonymous promise returns

在这里,我有一连串的诺言,效果很好。 所有* .destroy都是返回诺言的诺言:

function callDBDestroy() {
   var db;

   DB_Categories.destroy().then(function () {
      return DB_Equipment.destroy();
   }).catch(function (err) {
      showMsg("Error in callDBDestroy: " + err);
   }).then(function () {
      return DB_Certificates.destroy();
   }).catch(function (err) {
      showMsg("Error in callDBDestroy: " + err);
   }).then(function () {
      return DB_Locations.destroy();
   }).catch(function (err) {
      showMsg("Error in callDBDestroy: " + err);
   });
}

但我想在每个语句中添加一个if语句,以检查PouchDB数据库是否存在(如果DB_ *为null,则不存在)。

如果存在,我想销毁它,然后返回(所有这些返回诺言)。

如果不存在,我想返回一个匿名承诺,该承诺不返回任何内容,因为这些承诺都没有我关心的任何数据。

在该示例中,我添加了一些示例代码来执行if语句,并且我想知道我将在将传递一个promise(解析)值的null实例中放入什么。

function callDBDestroy() {
   var db;


   DB_Categories.destroy().then(function () {
      if( DB_Equipment != null) {
          return DB_Equipment.destroy();
      }
      else {
          Anonymous empty promise - something like:

          new Promise().resolve();

      }
   }).then(function () {
      return DB_Certificates.destroy();
   }).then(function () {
      return DB_Locations.destroy();
   }).catch(function (err) {
      showMsg("Error in callDBDestroy: " + err);
   });
}

谢谢,

汤姆

看来您只是想知道如何手动解决/拒绝Promise。 如果是这种情况,如果您想转到catch处理程序,则可以仅调用Promise.resolve(optionalValue)Promise.reject(optionalValue)

function callDBDestroy() {
   var db;

   DB_Categories.destroy()
   .then(function () {
      if( DB_Equipment != null) {
          return DB_Equipment.destroy();
      } else {
          return Promise.resolve();
      }
   }).then(function () {
      return DB_Certificates.destroy();
   }).then(function () {
      return DB_Locations.destroy();
   }).catch(function (err) {
      showMsg("Error in callDBDestroy: " + err);
   });
}

您可以将其包装:

function withDb(db, handler) {
    return function onFulfilled(value) {
       if(db === null) throw new Error("DB Null");
       return handler(value);
    });
}

哪个可以让您做:

function callDBDestroy() {
   var db;
   var w = withDb(db); // or whatever instance

   DB_Categories.destroy().then(w(function () {
       // do stuff

    }))); // .then(w( to chain calls here.
    ...
}

我想返回一个匿名诺言,该诺言不返回任何内容,因为这些诺言都没有我关心的任何数据。 就像是:

 new Promise().resolve(); 

您正在寻找Promise.resolve(undefined) 尽管您可以省略undefined ,但这是隐式的。

….then(function () {
    if (DB_Equipment != null) {
        return DB_Equipment.destroy();
    } else {
        return Promise.resolve(undefined);
    }
}).…

而且,您甚至不必从then回调中返回promise,只需返回undefined (或不return ing)将具有相同的效果。

….then(function () {
    if (DB_Equipment != null) {
        return DB_Equipment.destroy();
    }
}).…

在您的情况下,我建议使用包装函数:

function destroyDatabase(db, name = "db") {
    if (db != null)
        return db.destroy().catch(err => {
            showMsg(`Error in destroying ${name}: ${err}`);
        });
    else
        return Promise.resolve();
}
function callDBDestroy() {
    return destroyDatabase(DB_Categories, "categories")
    .then(() => destroyDatabase(DB_Certificates, "certificates"))
    .then(() => destroyDatabase(DB_Locations, "locations"))
}
// or even in parallel:
function callDBDestroy() {
    return Promise.all([
        destroyDatabase(DB_Categories, "categories"),
        destroyDatabase(DB_Certificates, "certificates"),
        destroyDatabase(DB_Locations, "locations")
    ]);
}

由于您执行相同的任务,并且只有数据库发生更改,因此如何使用数组:

//serial
function callDBDestroy() {
    var databases = [
        DB_Categories,
        DB_Equipment,
        DB_Certificates,
        DB_Locations
    ];

    function errorMessage(err){ showMsg("Error in callDBDestroy: " + err) };

    databases.reduce(
        (prev, db) => db == null? 
            prev: 
            prev.then(() => db.destroy().catch(errorMessage)), 
        Promise.resolve()
    )
}

//parallel
function callDBDestroy() {
    var databases = [
        DB_Categories,
        DB_Equipment,
        DB_Certificates,
        DB_Locations
    ];

    function errorMessage(err){ showMsg("Error in callDBDestroy: " + err) };

    databases.forEach( db => db && db.destroy().catch(errorMessage) );
}

我添加了一个序列号和一个paralell版本。

似乎您可以使用数据库数组对此进行干燥 ,并替换许多冗余代码,然后循环遍历该数组:

function callDbDestroy();
    var dbs = [DB_Categories, DB_Equipment, DB_Certificates, DB_Locations];

    // chain all the destroys together
    return dbs.reduce((p, db) => {
        return p.then(() => {
            if (db) {
                return db.destroy().catch(err => {
                    showMsg("Error in callDBDestroy: " + err);
                });
            }
        });

    }, Promise.resolve());
}

您不必从.then()处理函数返回承诺。 如果您没有返回值,则就像执行return undefined ,这意味着没有值将传递给下一个.then()处理程序,但是promise链将继续正常运行。 从概念上讲,它的工作原理与return Promise.resolve()相同,但是不需要在那里做额外的承诺。

由于您没有将值从一个.then()传递到链中的下一个,因此您没有任何要传递的值,因此,如果没有db值可以调用destroy,则无法返回任何内容。

仅供参考,使用.reduce()遍历数组与return p.then(...)结构是用于对数组上的异步操作进行排序的常见设计模式。

仅供参考,使用Bluebird Promise库(具有一些有用的帮助程序),可以这样进行:

function callDbDestroy();
    var dbs = [DB_Categories, DB_Equipment, DB_Certificates, DB_Locations];

    return Promise.mapSeries(dbs, db => {
        if (db) {
            return db.destroy().catch(err => {
                showMsg("Error in callDBDestroy: " + err);
            });
        }
    });
}

有关为何即使在ES6上Bluebird(或其他Promise库)仍然有用的更多信息,请参阅既然有了ES6 Promise是否还有理由使用Q或BlueBird这样的Promise库?


由于这些数据库似乎都可能是独立的,所以我想知道为什么要强制它们按顺序执行。 如果不必强制将它们顺序排列,则可以执行以下操作:

function callDbDestroy();
    var dbs = [DB_Categories, DB_Equipment, DB_Certificates, DB_Locations];

    return Promise.all(dbs.map(db => {
        if (db) {
            return db.destroy().catch(err => {
                showMsg("Error in callDBDestroy: " + err);
            });
        }
    }));
}

由于这可以并行运行操作,因此有机会缩短端到端的执行时间,而不是严格的序列化。

暂无
暂无

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

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