承诺链和匿名承诺返回

时间:2017-03-20 22:44:59

标签: 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(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语句,我想知道我会在null实例中放置什么来传递promise(resolve)值。

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

谢谢,

汤姆

5 个答案:

答案 0 :(得分:1)

看起来你只是想知道如何手动解决/拒绝承诺。如果是这种情况,如果您想转到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);
   });
}

答案 1 :(得分:0)

你可以包装它:

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.
    ...
}

答案 2 :(得分:0)

  

我想返回一个匿名的承诺,它不会返回任何内容,因为没有任何承诺有任何我关心的数据。类似的东西:

new Promise().resolve();

您正在寻找Promise.resolve(undefined)。虽然您可以省略undefined,但这是隐含的。

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

您甚至不必从then回调中返回承诺,只需返回undefined(或不return)就会产生相同的效果。

….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")
    ]);
}

答案 3 :(得分:0)

如何使用数组,因为您执行相同的任务,只有数据库更改:

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

我添加了序列和并列版本。

答案 4 :(得分:0)

您似乎可以DRY使用数据库数组替换大量冗余代码,然后循环遍历数组:

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()的值传递给链中的下一个,所以你没有任何东西可以通过那里,所以如果没有{{1调用destroy on的值。

仅供参考,使用db循环数组是.reduce()结构是一种常见的设计模式,用于对数组上的异步操作进行排序。

仅供参考,使用Bluebird promise库(有一些有用的帮助器),可以这样做:

return p.then(...)

有关Bluebird(或其他承诺库)即使使用ES6仍然有用的原因的详细信息,请参阅Are there still reasons to use promise libraries like Q or BlueBird now that we have ES6 promises?

由于看起来这些数据库可能都是独立的,我想知道为什么要强制它们按顺序执行。如果他们不必被迫按顺序进行,那么你可以这样做:

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

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