简体   繁体   English

如何将自定义属性或方法添加到Promise?

[英]How to add a custom property or method to a promise?

Regular promises have the beloved .then() and .catch() functions. 经常有承诺心爱的.then().catch()函数。

When promising to retrieve an object that itself has properties that return promises we find chains of promises such as the following: promising检索本身具有返回承诺属性的对象时,我们会找到承诺链,如下所示:

require("clientside-view-loader")
    .then((view)=>
        return view.load("clientside-view-modal-login_signup");
    })
    .then((compiler)=>{
        return compiler.generate()
    })
    .then((modal)=>{
        document.body.appendChild(modal);
        modal.show("login");
    })

This is UGLY! 这太丑了!

How can we modify a promise to attach a custom property so that we can convert the above into the following? 我们如何修改承诺以附加自定义属性,以便将以上内容转换为以下内容?

require("clientside-view-loader")
    .load("clientside-view-modal-login_signup")
    .generate()
    .then((modal)=>{
        document.body.appendChild(modal);
        modal.show("login");
    })

note, these examples use the clientside-require require and not the nodejs require 注意,这些示例使用clientside-require require而不是nodejs require

How can we modify a promise to attach a custom property so that we can convert the above into the following? 我们如何修改承诺以附加自定义属性,以便将以上内容转换为以下内容?

You don't modify promises at all. 您根本不修改承诺。 You just implement the builder pattern for the above promise chain. 您只需为上述承诺链实现构建器模式。

class ClientSideViewLoader {
  constructor(p = Promise.resolve()) {
    this.promise = p;
  }
  static init() {
    return new this(require("clientside-view-loader"));
  }
  load(x) {
    return new this.constructor(this.promise.then(view =>
      view.load(x)
    ));
  }
  generate() {
    return new this.constructor(this.promise.then(compiler => 
      compiler.generate()
    ));
  }
  then(...args) {
    return this.promise.then(...args);
  }
}

ClientSideViewLoader.init()
.load("clientside-view-modal-login_signup")
.generate()
.then(modal => {
  document.body.appendChild(modal);
  modal.show("login");
})

No need to do anything complicated like subclassing Promise . 不需要做任何复杂的事情,例如将Promise子类。 If you want, you can also dynamically generate all these methods. 如果需要,还可以动态生成所有这些方法。

This is UGLY! 这太丑了!

Well, if you were looking for beautiful promise code, you would simply use modern async / await syntax instead of then callbacks: 好吧,如果你正在寻找美丽的承诺的代码,你会简单地使用现代async / await语法,而不是then回调:

const view = await require("clientside-view-loader");
const compiler = await view.load("clientside-view-modal-login_signup");
const modal = await compiler.generate();
document.body.appendChild(modal);
modal.show("login");

Your initial code can be made shorter and more readable simply by using different syntax for your arrow functions . 只需通过为箭头函数使用不同的语法,就可以使初始代码更短,更易读。 These two rules of arrow function syntax are relevant: 箭头函数语法的以下两个规则是相关的:

  • parentheses are optional around the only argument of single-argument functions 在单参数函数的唯一参数周围,括号是可选的
  • single-statement functions that return a value can have the {} and the return removed 返回值的单语句函数可以将{}return删除

Thus, you could write your code like this, with the short form view => … instead of (view) => { return …; } 因此,您可以这样编写代码,即使用简短的格式view => …而不是(view) => { return …; } (view) => { return …; } : (view) => { return …; }

require("clientside-view-loader")
    .then(view => view.load("clientside-view-modal-login_signup"))
    .then(compiler => compiler.generate())
    .then(modal => {
        document.body.appendChild(modal);
        modal.show("login");
    });

If you know the properties you wish to add in advance you can simply append a property to the promise like you would any other object: 如果您知道要预先添加的属性,则可以像向其他对象一样简单地将属性附加到promise:

view_loader.load = function(path){
    return this.then((view_loader)=>{
        return view_loader.load(path)
    })
}
view_loader.load(...) // now works!

Here's a function that does this for a dynamic set of properties: 这是一个针对一组动态属性执行此操作的函数:

function modify_orig_promise(original_promise, properties_to_append){
    var blacklist = ["then", "catch", "spread"];
    var function_keys = Object.keys(properties_to_append);
    for(var i = 0; i < function_keys.length; i++){
        var function_key = function_keys[i];
        if(blacklist.indexOf(function_key) > -1) {
            console.warn("properties_to_append in require(__, {functions : {} }) included a blacklisted function name : `"+key+"`. skipping this property.")
        } else {
            var requested_function = properties_to_append[function_key];
            original_promise[function_key] = requested_function; // append the function to the promise
        }
    }
    return original_promise;
}

Then 然后

var properties_to_append = {
    load : function(path){
        return this.then((view_loader)=>{ return view_loader.load(path)}) 
    }
}
modified_require = modify_orig_promise(require("clientside-view-loader"), properties_to_append);
modified_require.load("clientside-view-modal-login_signup") // Works

If you dont know the properties in advance (eg, the properties are determined from a promise) you'll need to use a proxy that waits until that promise resolves to respond. 如果您不事先知道属性(例如,属性是从Promise确定的),则需要使用一个代理,该代理要等到Promise做出响应后再进行响应。 This is answered here: How to add properties to a promise asynchronously? 在这里得到答复: 如何异步地向诺言添加属性?

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

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