Javascript 承诺链与匿名承诺回报

Javascript 承诺链与匿名承诺回报,javascript,promise,pouchdb,Javascript,Promise,Pouchdb,在这里,我有一系列的承诺,效果很好。所有*.destroy都是回报承诺的承诺: function callDBDestroy() { var db; DB_Categories.destroy().then(function () { return DB_Equipment.destroy(); }).catch(function (err) { showMsg("Error in callDBDestroy: " + err); }).then

在这里,我有一系列的承诺,效果很好。所有*.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语句来检查数据库是否存在(如果DB_*为null,则不存在)

如果它存在,我想摧毁它,然后返回(这些都是返回的承诺)

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

在这个示例中,我添加了一些示例代码来执行if语句,我想知道在传递承诺(resolve)值的null实例中应该放些什么

谢谢


Tom

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

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();
你在找我。尽管可以省略未定义的
,但这是隐式的

….then(function () {
    if (DB_Equipment != null) {
        return DB_Equipment.destroy();
    } else {
        return Promise.resolve(undefined);
    }
}).…
您甚至不必从
回调中返回承诺,只需返回
未定义的
(或不返回
返回
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")
    ]);
}

使用数组如何,因为您执行的是相同的任务,并且只有DB发生了更改:

//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) );
}
我添加了一个串行版本和一个并行版本。

似乎您可以通过使用一个数据库数组来解决这个问题并替换大量冗余代码,然后只需在数组中循环:

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()
处理程序返回承诺。如果您没有返回值,那么这就像执行
returnundefined
,这意味着没有值将传递给下一个
。then()
处理程序,但承诺链将继续正常运行。从概念上讲,它的工作原理与
return Promise.resolve()
相同,但不需要在那里做出额外的承诺

由于您没有将值从一个
.then()
传递到链中的下一个,因此您没有要传递的内容,因此如果没有要调用的
db
值,您就不能返回任何内容

仅供参考,使用
.reduce()
在数组中循环是使用
返回p。然后(…)
结构是对数组上的异步操作进行排序的常见设计模式

仅供参考,使用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);
            });
        }
    });
}
有关为什么Bluebird(或其他promise库)在ES6中仍然有用的更多信息,请参阅


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

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

由于这将并行运行操作,因此与严格的序列化相比,它有机会获得更快的端到端执行时间。

假设如果数据库为null,您不想继续执行其余的链式承诺,则不会。此外,您可以只调用
Promise.resolve()
,您不需要
新的
东西,您的意思是“回报承诺的方法“?它们必须连续运行吗?因为看起来你是新来的,如果下面的任一答案回答了你的问题,那么你可以通过单击最佳答案旁边的绿色复选标记向社区表明这一点。”。这也会在堆栈溢出上为您赢得一些声誉点数,因为您需要遵循正确的过程。从
返回承诺中没有任何意义。resolve()
开始,然后作为
承诺。resolve
将在返回值上自动调用。你只需要
返回@BenjaminGruenbaum谢谢你的留言,同意了。我试图向OP解释如何手动解决/拒绝承诺,因为这似乎是一个混乱的问题。因此,如果我做了“返回”或“返回‘某物’”,则a解析被称为事件。实际上,我曾想过使用Promise.all,但不确定如何设置它。我不确定map的作用。@tshad-
.map()
是一个数组方法。你可以读到它。它将一个数组作为输入并生成一个新数组-在本例中,我生成一个承诺数组,然后将其传递给
Promise.all()
。我原以为您必须返回,否则承诺会导致问题(副作用)。我发现在某些情况下,我对代码有问题,添加一个返回解决了这个问题。是的,如果你正在做一些使用承诺的事情,你(几乎)总是需要
返回它们。然而,当没有数据库并且您不做任何事情时,您也不需要返回任何结果。
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);
            });
        }
    }));
}