如何将promise resolve()转移到另一个promise

时间:2015-03-05 15:15:10

标签: javascript promise q

假设我有一个“JsonEditor”模块(仅用于示例),它有3个函数:get(),setProperty()和save()。

以下是代码(问题如下):

var fs   = require('fs')
  , q    = require('q');

var jsonEditorModule = (function() {
    return {
        get: function(jsonPath) {
            // ...
        },

        save: function(jsonObject, jsonPath) {
            var qJson = q.defer();

            var jsonContent = JSON.stringify(jsonObject, null, 2);

            fs.writeFile(jsonPath, jsonContent, function(err) {
                if(err) {
                    qJson.reject(err);
                }
                else {
                    qJson.resolve();
                }
            });

            return qJson.promise;
        },

        setProperty: function(prop, value, jsonPath) {
            var self = this;
            var qJson = q.defer();

            this.get(jsonPath)
            .then(
                function(jsonObject) {
                    // Set the property
                    jsonObject[prop] = value;

                    // Save the file
                    self.save(jsonObject, jsonPath)
                    .then(
                        function() {
                            qJson.resolve();
                        },
                        function() {
                            qJson.reject();
                        },
                    );
                }
            );

            return qJson.promise;
        },
    };
})();

module.exports = jsonEditorModule;

在setProperty()函数中的save()之后看到then()?

看起来很蠢,对吧?

我是否需要手动解决()并拒绝()我的承诺? 我不能只将save()行为转移到我的setProperty()promise吗?

希望这个问题足够清楚(而不是太愚蠢)。

由于

2 个答案:

答案 0 :(得分:2)

这里描述了你想要实现的目标:chaining,基本上如果处理程序返回一个promise(让我们称之为innerPromiseFromHandler),那么.then的处理程序当innerPromiseFromHandler获得分辨率值时,将在先前的承诺上定义:



var jsonEditorModule = (function() {
  return {
    get: function(jsonPath) {
      return Q.delay(1000).then(function () {
        document.write('get...<br/>');
        return 'get';
      });
    },

    save: function(result) {
      return Q.delay(1000).then(function () {
        document.write('save...<br/>');        
        return result + ' save';
      });
    },

    setProperty: function(prop, value, jsonPath) {
      return this.get(jsonPath)
        .then(function(result) {
          return jsonEditorModule.save(result);
        });
    }
  };
})();
      
jsonEditorModule
  .setProperty()
  .then(function (result) {    
    document.write(result + ' finish');
  })
&#13;
<script src="http://cdnjs.cloudflare.com/ajax/libs/q.js/0.9.2/q.js"></script>
&#13;
&#13;
&#13;

答案 1 :(得分:2)

  

看起来很蠢,对吗?我是否需要手动resolve()reject()我的承诺?

是的,事实上它有一个自己的名字:手动解决/拒绝额外的承诺被称为愚蠢的deferred antipattern

  

我不能将save()行为转移到我的setProperty()承诺吗?

是的,这很简单 - 并且它内置于then方法:调用.then()会为您的回调的return值返回一个新承诺,即使该值已被隐藏在承诺中。

var jsonEditorModule = {
    get: function(jsonPath) {
        // ...
    },
    save: function(jsonObject, jsonPath) {
        return Q.ninvoke(fs, "writeFile", jsonPath, JSON.stringify(jsonObject, null, 2));
    },
    setProperty: function(prop, value, jsonPath) {
        return this.get(jsonPath).then(function(jsonObject) {
//      ^^^^^^
            // Set the property
            jsonObject[prop] = value;
            // Save the file
            return this.save(jsonObject, jsonPath);
//          ^^^^^^
        }.bind(this));
    }
};