【问题标题】:Resolve Javascript Promise outside the Promise constructor scope在 Promise 构造函数范围之外解析 Javascript Promise
【发布时间】:2023-01-18 00:03:14
【问题描述】:

我一直在使用 ES6 Promise。

通常,一个 Promise 是这样构造和使用的

new Promise(function(resolve, reject){
    if (someCondition){
        resolve();
    } else {
        reject();
    } 
});

但是为了灵活起见,我一直在做类似下面的事情来解决问题。

var outsideResolve;
var outsideReject;
new Promise(function(resolve, reject) { 
    outsideResolve = resolve; 
    outsideReject = reject; 
});

然后

onClick = function(){
    outsideResolve();
}

这工作正常,但有没有更简单的方法来做到这一点?如果不是,这是一个好习惯吗?

【问题讨论】:

  • 我认为没有其他方法。我相信指定传递给Promise 的回调必须同步执行以允许“导出”这两个函数。
  • 这对我来说就像你写的一样。所以就我而言,这是“规范”的方式。
  • 我认为将来应该有一种正式的方式来实现这一点。我认为此功能非常强大,因为您可以等待来自其他上下文的值。
  • 每当他们想出一个合适的解决方案来解决这个问题时,我希望他们也能使它适用于嵌套的承诺,其中一些可能会重复出现。
  • 我认为 Promise API“建议”始终将它们用作返回值,而不是作为您可以访问或调用的对象。换句话说,迫使我们将它们视为返回值,而不是我们可以访问的对象或我们可以调用的函数,或者我们可以用变量引用或作为参数传递的东西,等等。如果你开始使用承诺作为任何其他对象,你可能会最终需要像你的问题一样从外部解决它......话虽如此,我也认为应该有一种正式的方式来做到这一点......而 Deferred 似乎只是我的一种解决方法。

标签: javascript promise es6-promise


【解决方案1】:

简单的:

var promiseResolve, promiseReject;

var promise = new Promise(function(resolve, reject){
  promiseResolve = resolve;
  promiseReject = reject;
});

promiseResolve();

【讨论】:

  • @ruX,正如公认的答案所提到的那样——它是故意这样设计的。关键是如果抛出异常,它将被 promise 构造函数捕获。这个答案(以及我的)有一个陷阱,即可能会为调用 promiseResolve() 的任何代码抛出异常。承诺的语义是它总是返回一个值。这在功能上也与 OP 的帖子相同,我不明白这是以可重用的方式解决了什么问题。
  • @JonJaques 我不确定你说的是否属实。调用promiseResolve()的代码不会抛出异常。您可以在构造函数上定义一个.catch,无论什么代码调用它,都会调用构造函数的.catch。这是演示其工作原理的 jsbin:jsbin.com/yicerewivo/edit?js,console
  • 是的,它被捕获是因为你在它周围包装了另一个 promise 构造函数——这正是我要表达的观点。但是,假设您有一些其他代码试图在构造函数(又名 Deferred 对象)之外调用 resolve() ...它可能会抛出异常并且不会被捕获 jsbin.com/cokiqiwapo/1/edit?js,console
  • 我什至不确定这是一个糟糕的设计。在 promise 之外抛出的错误不应该在 promise 中被捕获。如果设计者实际上期望要捕获的错误。
  • 问题中已经提到了这个确切的构造。你读过吗?
【解决方案2】:

在这里聚会有点晚,但另一种方法是使用 Deferred 对象。您基本上拥有相同数量的样板文件,但如果您想传递它们并可能在它们的定义之外解析,它会很方便。

天真的实现:

class Deferred {
  constructor() {
    this.promise = new Promise((resolve, reject)=> {
      this.reject = reject
      this.resolve = resolve
    })
  }
}

function asyncAction() {
  var dfd = new Deferred()

  setTimeout(()=> {
    dfd.resolve(42)
  }, 500)

  return dfd.promise
}

asyncAction().then(result => {
  console.log(result) // 42
})

ES5 版本:

function Deferred() {
  var self = this;
  this.promise = new Promise(function(resolve, reject) {
    self.reject = reject
    self.resolve = resolve
  })
}

function asyncAction() {
  var dfd = new Deferred()

  setTimeout(function() {
    dfd.resolve(42)
  }, 500)

  return dfd.promise
}

asyncAction().then(function(result) {
  console.log(result) // 42
})

【讨论】:

  • 请注意这里的词法范围。
  • resolve|reject 是按词法分配还是通过 bind 分配没有实际区别。这只是自 1.0(ish) 以来就存在的 jQuery Deferred 对象的简单实现。它的工作方式与 promise 完全一样,只是没有抛出安全性。这个问题的重点是如何在创建承诺时节省几行代码。
  • 使用延迟是执行此操作的常用方法,我不知道为什么这不更高
  • 优秀的答案!正在寻找 jQuery 提供的延迟功能。
  • Deferred 是否已弃用?
【解决方案3】:

不,没有其他方法可以做到这一点——我唯一能说的是这个用例不是很常见。就像 Felix 在评论中所说的那样 - 你所做的将始终如一。

值得一提的是,promise 构造函数以这种方式运行的原因是抛出安全性——如果当代码在 promise 构造函数内运行时发生了你没有预料到的异常,它将变成拒绝,这种形式的抛出安全性——将抛出的错误转换为拒绝很重要,有助于维护可预测的代码。

出于这个抛出安全的原因,选择了 promise 构造函数而不是 deferreds(这是一种允许你正在做的事情的替代 promise 构造方式) - 至于最佳实践 - 我将传递元素并改用 promise 构造函数:

var p = new Promise(function(resolve, reject){
    this.onclick = resolve;
}.bind(this));

出于这个原因——每当你能够在导出函数时使用 promise 构造函数 - 我建议您使用它。只要你可以避免两者 - 避免两者和连锁。

注意,你永远不应该对if(condition)这样的东西使用promise构造函数,第一个例子可以写成:

var p = Promise[(someCondition)?"resolve":"reject"]();

【讨论】:

  • 嗨,本杰明!如果我们不知道什么时候会兑现承诺,目前是否没有更好的方法来获得美味的承诺糖?像某种异步wait/notify pattern?例如,“存储”,然后调用 Promise 链?例如。在我的特殊情况下,我在服务器上,等待特定的客户端回复(SYN-ACK-kinda 握手以确保客户端成功更新状态)。
  • 我怎么能使用 fetch API 做同样的事情?
  • 不常见?我最终几乎每个项目都需要它。
  • 至于用例,请考虑您需要在触发事件并发生其他事情后做某事。您希望将事件转换为承诺并将其与另一个承诺联合起来。对我来说似乎是一个普遍的问题。
  • 如果你能var p = new Promise(); p.resolve()就太方便了
【解决方案4】:

我喜欢@JonJaques 的回答,但我想更进一步。

如果你绑定 thencatch 然后是 Deferred 对象,那么它完全实现了 Promise API,你可以把它当作 promise 和 await 它等等。

⚠️编者按:我不再推荐这种模式,因为在撰写本文时,Promise.prototype.finally 还不是一个东西,然后它变成了一个东西……这可能发生在其他方法上,所以我建议您使用 @987654328 增加 promise 实例@ 和 reject 函数改为:

function createDeferredPromise() {
  let resolve
  let reject

  const promise = new Promise((thisResolve, thisReject) => {
    resolve = thisResolve
    reject = thisReject
  })

  return Object.assign(promise, {resolve, reject})
}

去赞别人的答案。

class DeferredPromise {
  constructor() {
    this._promise = new Promise((resolve, reject) => {
      // assign the resolve and reject functions to `this`
      // making them usable on the class instance
      this.resolve = resolve;
      this.reject = reject;
    });
    // bind `then` and `catch` to implement the same interface as Promise
    this.then = this._promise.then.bind(this._promise);
    this.catch = this._promise.catch.bind(this._promise);
    this.finally = this._promise.finally.bind(this._promise);
    this[Symbol.toStringTag] = 'Promise';
  }
}

const deferred = new DeferredPromise();
console.log('waiting 2 seconds...');
setTimeout(() => {
  deferred.resolve('whoa!');
}, 2000);

async function someAsyncFunction() {
  const value = await deferred;
  console.log(value);
}

someAsyncFunction();

【讨论】:

  • 我真的很喜欢这个。谢谢你。我将它用作我的 Express 应用程序中的自定义组件,但如果您愿意创建一个 NPM 模块,或者如果需要,我也可以创建一个 NPM 模块,那么它会很棒。这种方法是新的 async / await 和旧的 Parse 平台如何处理 promises 的完美结合en.wikipedia.org/wiki/Parse_(platform)
  • 不要忘记Promise.prototype.finally
  • 好消息@КонстантинВан,我一分钟都没有看到这个答案,我不再推荐这个了。我已经更新了答案以反映
  • 好吧,如果您担心 Promise 的方法将来可能发生变化,您也可以通过循环遍历 Promise 的属性来概括映射工作,不是吗?
【解决方案5】:

我在 2015 年为我的框架提出了一个解决方案。我称这种类型的承诺任务

function createPromise(handler){
  var resolve, reject;

  var promise = new Promise(function(_resolve, _reject){
    resolve = _resolve; 
    reject = _reject;
    if(handler) handler(resolve, reject);
  })
  
  promise.resolve = resolve;
  promise.reject = reject;
  return promise;
}


// create
var promise = createPromise()
promise.then(function(data){ alert(data) })

// resolve from outside
promise.resolve(200)

【讨论】:

  • 谢谢,这有效。但什么是处理程序?我必须将其删除才能使其正常工作。
  • @Sahid 当你运行 createPromise() 时,你需要将一个函数作为参数传递给它。否则代码不起作用。您可以有一个 if 语句并在调用它之前检查处理程序参数的有效性。
  • 感谢您的代码!但是在回调设置它之前,其他一些代码不可能调用你的.resolve吗?我习惯于常规线程,而不是异步事件,所以我可能有点困惑。
【解决方案6】:

接受的答案是错误的。使用范围和引用非常容易,尽管它可能会产生 Promise纯粹主义者生气的:

const createPromise = () => {
    let resolver;
    return [
        new Promise((resolve, reject) => {
            resolver = resolve;
        }),
        resolver,
    ];
};

const [ promise, resolver ] = createPromise();
promise.then(value => console.log(value));
setTimeout(() => resolver('foo'), 1000);

我们实际上是在创建 promise 时获取对 resolve 函数的引用,然后我们返回它以便可以在外部设置它。

一秒钟后,控制台将输出:

> foo

【讨论】:

  • 我认为这是最好的方法。唯一的问题是代码可以不那么冗长。
  • 好的!聪明的主意。如果可以的话+50。
  • 这正是 OP 所做的。事实上,您正在重新发明 Promises 的延迟模式,当然这是可能的并且您的方法有效(作为初始 OP 代码),但是由于接受的答案中描述的“抛出安全原因”,这不是最佳实践。
【解决方案7】:

辅助方法可以减轻这种额外的开销,并给您同样的 jQuery 感觉。

function Deferred() {
    let resolve;
    let reject;
    const promise = new Promise((res, rej) => {
        resolve = res;
        reject = rej;
    });
    return { promise, resolve, reject };
}

用法是

const { promise, resolve, reject } = Deferred();
displayConfirmationDialog({
    confirm: resolve,
    cancel: reject
});
return promise;

类似于 jQuery

const dfd = $.Deferred();
displayConfirmationDialog({
    confirm: dfd.resolve,
    cancel: dfd.reject
});
return dfd.promise();

虽然,在用例中,这种简单的本机语法很好

return new Promise((resolve, reject) => {
    displayConfirmationDialog({
        confirm: resolve,
        cancel: reject
    });
});

【讨论】:

    【解决方案8】:

    我正在使用一个辅助函数来创建我所说的“平面承诺”——

    function flatPromise() {
    
        let resolve, reject;
    
        const promise = new Promise((res, rej) => {
          resolve = res;
          reject = rej;
        });
    
        return { promise, resolve, reject };
    }
    

    我正在这样使用它 -

    function doSomethingAsync() {
    
        // Get your promise and callbacks
        const { resolve, reject, promise } = flatPromise();
    
        // Do something amazing...
        setTimeout(() => {
            resolve('done!');
        }, 500);
    
        // Pass your promise to the world
        return promise;
    
    }
    

    查看完整的工作示例 -

    function flatPromise() {
    
        let resolve, reject;
    
        const promise = new Promise((res, rej) => {
            resolve = res;
            reject = rej;
        });
    
        return { promise, resolve, reject };
    }
    
    function doSomethingAsync() {
        
        // Get your promise and callbacks
        const { resolve, reject, promise } = flatPromise();
    
        // Do something amazing...
        setTimeout(() => {
            resolve('done!');
        }, 500);
    
        // Pass your promise to the world
        return promise;
    }
    
    (async function run() {
    
        const result = await doSomethingAsync()
            .catch(err => console.error('rejected with', err));
        console.log(result);
    
    })();

    编辑: 我已经创建了一个名为flat-promise 的 NPM 包,代码也可用on GitHub

    【讨论】:

      【解决方案9】:

      以防万一有人来寻找 util 的打字稿版本来简化此任务:

      export const deferred = <T>() => {
        let resolve!: (value: T | PromiseLike<T>) => void;
        let reject!: (reason?: any) => void;
        const promise = new Promise<T>((res, rej) => {
          resolve = res;
          reject = rej;
        });
      
        return {
          resolve,
          reject,
          promise,
        };
      };
      

      这可以用于例如。喜欢:

      const {promise, resolve} = deferred<string>();
      
      promise.then((value) => console.log(value)); // nothing
      
      resolve('foo'); // console.log: foo
      
      

      【讨论】:

        【解决方案10】:

        您可以将 Promise 包装在一个类中。

        class Deferred {
            constructor(handler) {
                this.promise = new Promise((resolve, reject) => {
                    this.reject = reject;
                    this.resolve = resolve;
                    handler(resolve, reject);
                });
        
                this.promise.resolve = this.resolve;
                this.promise.reject = this.reject;
        
                return this.promise;
            }
            promise;
            resolve;
            reject;
        }
        
        // How to use.
        const promise = new Deferred((resolve, reject) => {
          // Use like normal Promise.
        });
        
        promise.resolve(); // Resolve from any context.
        

        【讨论】:

          【解决方案11】:

          在某些情况下,我发现自己也缺少 Deferred 模式。你总是可以在 ES6 Promise 之上创建一个:

          export default class Deferred<T> {
              private _resolve: (value: T) => void = () => {};
              private _reject: (value: T) => void = () => {};
          
              private _promise: Promise<T> = new Promise<T>((resolve, reject) => {
                  this._reject = reject;
                  this._resolve = resolve;
              })
          
              public get promise(): Promise<T> {
                  return this._promise;
              }
          
              public resolve(value: T) {
                  this._resolve(value);
              }
          
              public reject(value: T) {
                  this._reject(value);
              }
          }
          

          【讨论】:

          • 我喜欢这个。我只想将签名从 reject 更改为 reject(reason: any)
          【解决方案12】:

          这里的许多答案与this article中的最后一个例子相似。 我正在缓存多个 Promise,并且可以将 resolve()reject() 函数分配给任何变量或属性。因此,我能够使这段代码稍微紧凑一些:

          function defer(obj) {
              obj.promise = new Promise((resolve, reject) => {
                  obj.resolve = resolve;
                  obj.reject  = reject;
              });
          }
          

          以下是使用此版本的 defer()FontFace 加载 Promise 与另一个异步进程组合的简化示例:

          function onDOMContentLoaded(evt) {
              let all = []; // array of Promises
              glob = {};    // global object used elsewhere
              defer(glob);
              all.push(glob.promise);
              // launch async process with callback = resolveGlob()
          
              const myFont = new FontFace("myFont", "url(myFont.woff2)");
              document.fonts.add(myFont);
              myFont.load();
              all.push[myFont];
              Promise.all(all).then(() => { runIt(); }, (v) => { alert(v); });
          }
          //...
          function resolveGlob() {
              glob.resolve();
          }
          function runIt() {} // runs after all promises resolved 
          

          更新:如果您想封装对象,有 2 个备选方案:

          function defer(obj = {}) {
              obj.promise = new Promise((resolve, reject) => {
                  obj.resolve = resolve;
                  obj.reject  = reject;
              });
              return obj;
          }
          let deferred = defer();
          

          class Deferred {
              constructor() {
                  this.promise = new Promise((resolve, reject) => {
                      this.resolve = resolve;
                      this.reject  = reject;
                  });
              }
          }
          let deferred = new Deferred();
          

          【讨论】:

          • 如果你在异步函数中使用这些例子,当你想使用已解析的承诺的值时,你需要引用承诺属性:const result = await deferred.promise;
          【解决方案13】:

          我们的解决方案是使用闭包来存储解析/拒绝函数,并附加一个函数来扩展承诺本身。

          这是模式:

          function getPromise() {
          
              var _resolve, _reject;
          
              var promise = new Promise((resolve, reject) => {
                  _reject = reject;
                  _resolve = resolve;
              });
          
              promise.resolve_ex = (value) => {
                 _resolve(value);
              };
          
              promise.reject_ex = (value) => {
                 _reject(value);
              };
          
              return promise;
          }
          

          并使用它:

          var promise = getPromise();
          
          promise.then(value => {
              console.info('The promise has been fulfilled: ' + value);
          });
          
          promise.resolve_ex('hello');  
          // or the reject version 
          //promise.reject_ex('goodbye');
          

          【讨论】:

          • 太好了……我只是在学习 Promises,但一直对您似乎无法在“其他地方”解决它们这一事实感到困惑。使用闭包来隐藏实现细节是一个好主意......但事实上我不确定那是你所做的:而不是拥有“伪”私有变量我很确定有一种方法可以完全地隐藏那些应该不可访问的变量……这就是闭包的真正含义……
          • > 闭包是一段代码,可以通过访问封闭范围的变量来引用(和传递)。变种_resolve,_reject;是封闭范围。
          • 是的,很公平。实际上,在我看来,我的回答过于复杂,而且您的回答可以简化:您只需要转到promise.resolve_ex = _resolve; promise.reject_ex = _reject; ... 仍然可以正常工作。
          • 附加一个函数来扩展承诺本身。“ - 不要那样做。承诺是结果值,它们不应该提供解决它们的能力。你不想传递那些扩展的。
          • 问题是如何在范围之外解决它。这是一个有效的解决方案,在我们的生产中,我们实际上有必要这样做。我不明白为什么解决所述问题值得投反对票。
          【解决方案14】:

          是的你可以。通过为浏览器环境使用 CustomEvent API。并在 node.js 环境中使用事件发射器项目。由于问题中的 sn-p 是针对浏览器环境的,这里有一个相同的工作示例。

          function myPromiseReturningFunction(){
            return new Promise(resolve => {
              window.addEventListener("myCustomEvent", (event) => {
                 resolve(event.detail);
              }) 
            })
          }
          
          
          myPromiseReturningFunction().then(result => {
             alert(result)
          })
          
          document.getElementById("p").addEventListener("click", () => {
             window.dispatchEvent(new CustomEvent("myCustomEvent", {detail : "It works!"}))
          })
          &lt;p id="p"&gt; Click me &lt;/p&gt;

          我希望这个答案有用!

          【讨论】:

            【解决方案15】:

            感谢在此主题中发帖的所有人。我创建了一个模块,其中包含前面描述的 Defer() 对象以及构建在其上的其他一些对象。它们都利用 Promises 和简洁的 Promise 回调语法来实现程序中的通信/事件处理。

            • 延迟:可以远程解决的承诺失败(在其主体之外)
            • 延迟:在给定时间后自动解决的承诺
            • 超时:在给定时间后自动失败的承诺。
            • Cycle:可重新触发的 promise 以使用 Promise 语法管理事件
            • Queue:基于 Promise 链的执行队列。

            rp = require("openpromise")

            https://github.com/CABrouwers/openpromise https://www.npmjs.com/package/openpromise

            【讨论】:

              【解决方案16】:

              类版本,在 Typescript 中:

              export class Deferred<T> {
                  public readonly promise: Promise<T>
                  private resolveFn!: (value: T | PromiseLike<T>) => void
                  private rejectFn!: (reason?: any) => void
              
                  public constructor() {
                      this.promise = new Promise<T>((resolve, reject) => {
                          this.resolveFn = resolve
                          this.rejectFn = reject
                      })
                  }
              
                  public reject(reason?: any): void {
                      this.rejectFn(reason)
                  }
              
                  public resolve(param: T): void {
                      this.resolveFn(param)
                  }
              }
              

              【讨论】:

                【解决方案17】:

                我为此写了一个小库。 https://www.npmjs.com/package/@inf3rno/promise.exposed

                我使用了其他人编写的工厂方法方法,但我也覆盖了 thencatchfinally 方法,因此您也可以通过这些方法解决原始承诺。

                在没有执行者的情况下从外部解决承诺:

                const promise = Promise.exposed().then(console.log);
                promise.resolve("This should show up in the console.");
                

                从外部与执行者的 setTimeout 赛跑:

                const promise = Promise.exposed(function (resolve, reject){
                    setTimeout(function (){
                        resolve("I almost fell asleep.")
                    }, 100000);
                }).then(console.log);
                
                setTimeout(function (){
                    promise.resolve("I don't want to wait that much.");
                }, 100);
                

                如果不想污染全局命名空间,可以使用无冲突模式:

                const createExposedPromise = require("@inf3rno/promise.exposed/noConflict");
                const promise = createExposedPromise().then(console.log);
                promise.resolve("This should show up in the console.");
                

                【讨论】:

                  【解决方案18】:

                  我创建了一个名为 manual-promise 的库,它可以替代 Promise。这里的其他答案都不能替代Promise,因为它们使用代理或包装器。

                  yarn add manual-promise

                  npn install manual-promise

                  
                  import { ManualPromise } from "manual-promise";
                  
                  const prom = new ManualPromise();
                  
                  prom.resolve(2);
                  
                  // actions can still be run inside the promise
                  const prom2 = new ManualPromise((resolve, reject) => {
                      // ... code
                  });
                  
                  
                  new ManualPromise() instanceof Promise === true
                  
                  

                  https://github.com/zpxp/manual-promise#readme

                  【讨论】:

                    【解决方案19】:

                    只是从外部解决 Promise 的另一种解决方案

                     class Lock {
                            #lock;  // Promise to be resolved (on  release)
                            release;  // Release lock
                            id;  // Id of lock
                            constructor(id) {
                                this.id = id
                                this.#lock = new Promise((resolve) => {
                                    this.release = () => {
                                        if (resolve) {
                                            resolve()
                                        } else {
                                            Promise.resolve()
                                        }
                                    }
                                })
                            }
                            get() { return this.#lock }
                        }
                    

                    用法

                    let lock = new Lock(... some id ...);
                    ...
                    lock.get().then(()=>{console.log('resolved/released')})
                    lock.release()  // Excpected 'resolved/released'
                    

                    【讨论】:

                      【解决方案20】:

                      如何创建一个函数来劫持拒绝并返回它?

                      function createRejectablePromise(handler) {
                        let _reject;
                      
                        const promise = new Promise((resolve, reject) => {
                          _reject = reject;
                      
                          handler(resolve, reject);
                        })
                      
                        promise.reject = _reject;
                        return promise;
                      }
                      
                      // Usage
                      const { reject } = createRejectablePromise((resolve) => {
                        setTimeout(() => {
                          console.log('resolved')
                          resolve();
                        }, 2000)
                      
                      });
                      
                      reject();
                      

                      【讨论】:

                        【解决方案21】:

                        我整理了一个要点来完成这项工作:https://gist.github.com/thiagoh/c24310b562d50a14f3e7602a82b4ef13

                        以下是您应该如何使用它:

                        import ExternalizedPromiseCreator from '../externalized-promise';
                        
                        describe('ExternalizedPromise', () => {
                          let fn: jest.Mock;
                          let deferredFn: jest.Mock;
                          let neverCalledFn: jest.Mock;
                          beforeEach(() => {
                            fn = jest.fn();
                            deferredFn = jest.fn();
                            neverCalledFn = jest.fn();
                          });
                        
                          it('resolve should resolve the promise', done => {
                            const externalizedPromise = ExternalizedPromiseCreator.create(() => fn());
                        
                            externalizedPromise
                              .promise
                              .then(() => deferredFn())
                              .catch(() => neverCalledFn())
                              .then(() => {
                                expect(deferredFn).toHaveBeenCalled();
                                expect(neverCalledFn).not.toHaveBeenCalled();
                                done();
                              });
                        
                            expect(fn).toHaveBeenCalled();
                            expect(neverCalledFn).not.toHaveBeenCalled();
                            expect(deferredFn).not.toHaveBeenCalled();
                        
                            externalizedPromise.resolve();
                          });
                          ...
                        });
                        

                        【讨论】:

                          【解决方案22】:

                          由于我没有找到我要找的东西,所以当我结束这个问题时,我将分享我真正想要实现的目标。

                          设想:我有 3 个不同的 API,具有相同的可能响应,因此我想在单个函数中处理承诺的完成和错误处理。这就是我所做的:

                          1. 创建处理函数:
                              private handleHttpPromise = (promise: Promise<any>) => {
                                promise
                                  .then((response: any) => {
                                    // do something with the response
                                    console.log(response);
                                  })
                                  .catch((error) => {
                                    // do something with the error
                                    console.log(error);
                                  });
                              };
                            
                            1. 将您的承诺发送给创建的处理程序
                              switch (method) {
                                case 'get': {
                                  this.handleHttpPromise(apiService.get(url));
                                  break;
                                }
                                case 'post': {
                                  if (jsonData) {
                                    this.handleHttpPromise(apiService.post(url, jsonData));
                                  }
                                  break;
                                }
                                // (...)
                              }
                            

                          【讨论】:

                            【解决方案23】:

                            我想分享一些不同的东西,这个话题的延伸。

                            有时您希望“任务承诺”在解决时在同一地址(属性或变量)自动重新创建。可以创建一个执行此操作的外部解析器。

                            使用外部解析器的重复承诺示例。每当调用解析器时,都会在相同的地址/变量/属性上创建一个新的承诺。

                            let resolvePromise;
                            let thePromise;
                            
                            const setPromise = (resolve) => {
                              resolvePromise = () => {
                                resolve();
                                thePromise = new Promise(setPromise);   
                              }
                            }
                            thePromise = new Promise(setPromise);
                            
                            (async () => {
                              let i = 0;
                              while (true) {
                                let msg = (i % 2 === 0) ? 'Tick' : 'Tock';
                                document.body.innerHTML = msg;
                                setTimeout(resolvePromise, 1000);
                                await thePromise;
                                i++;
                              }
                            })();
                            

                            https://jsfiddle.net/h3zvw5xr

                            【讨论】:

                              【解决方案24】:

                              如果(像我一样)你不喜欢增加本机实例,也不喜欢笨重“。承诺”properties ...但确实喜欢代理和 mangling 类,那么这个适合你:

                              class GroovyPromise {
                                constructor() {
                                  return new Proxy(new Promise((resolve, reject) => {
                                    this.resolve = resolve;
                                    this.reject = reject;
                                  }), {
                                    get: (target, prop) =>
                                      this[prop] || target[prop].bind(target),
                                  });
                                }
                              }
                              

                              像这样使用:

                              const groovypromise = new GroovyPromise();
                              setTimeout(() => groovypromise.resolve('groovy'), 1000);
                              console.log(await groovypromise);
                              

                              当然你也可以将课程重命名为沉闷的东西“延期”

                              【讨论】:

                                【解决方案25】:

                                首先在浏览器或节点上启用 --allow-natives-syntax

                                const p = new Promise(function(resolve, reject){
                                    if (someCondition){
                                        resolve();
                                    } else {
                                        reject();
                                    } 
                                });
                                
                                onClick = function () {
                                    %ResolvePromise(p, value)
                                }
                                
                                

                                【讨论】:

                                  猜你喜欢
                                  • 2014-11-26
                                  • 2020-06-10
                                  • 2020-05-23
                                  • 1970-01-01
                                  • 2015-08-15
                                  • 1970-01-01
                                  • 1970-01-01
                                  • 2015-07-14
                                  相关资源
                                  最近更新 更多