【问题标题】:Resolve Javascript Promise outside the Promise constructor scope解决函数范围之外的 Javascript Promise
【发布时间】:2014-11-26 19:36:31
【问题描述】:

我一直在使用 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,其中一些可能会重复出现。
  • 我认为 Promise API“建议”始终将它们用作返回值,而不是您可以访问或调用的对象。换句话说,迫使我们将它们视为返回值,而不是我们可以访问的对象或我们可以调用的函数,或者我们可以通过变量引用或作为参数传递的东西等。如果您开始将 Promise 用作任何其他对象,您可能会最终需要像你的问题一样从外部解决它......话虽如此,我也认为应该有一种正式的方式来做到这一点......而 Deferred 对我来说似乎只是一种解决方法。

标签: javascript promise es6-promise


【解决方案1】:

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

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

⚠️ 编者注:我不再推荐这种模式,因为在撰写本文时,Promise.prototype.finally 还不是一个东西,然后它变成了一个东西......这可能发生在其他方法,所以我建议您使用 resolvereject 函数来扩充 Promise 实例:

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 模块,或者如果需要我可以创建一个,它会很棒。这种方法是新的 async / await 以及旧 Parse 平台如何处理 promise en.wikipedia.org/wiki/Parse_(platform) 的一个很好的混搭
  • 别忘了Promise.prototype.finally
  • 很好@КонстантинВан,我一分钟没看到这个答案,我不再推荐这个了。我已经更新了答案以反映
  • 好吧,如果你担心Promise 的方法将来可能发生变化,你也可以通过循环Promise 的属性来概括映射工作,不是吗?
【解决方案2】:

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

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

【讨论】:

    【解决方案3】:

    我想分享一些不同的东西,这个主题的扩展。

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

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

    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

    【讨论】:

      【解决方案4】:

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

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

      rp = require("openpromise")

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

      【讨论】:

        【解决方案5】:

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

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

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

        【讨论】:

          【解决方案6】:

          我在 2015 年为我的框架提出的解决方案。我将这种类型的承诺称为 Task

          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?我习惯了常规线程,而不是异步事件,所以我可能会有点困惑。
          【解决方案7】:

          从外部解决 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'
          

          【讨论】:

            【解决方案8】:

            我发现自己在某些情况下也缺少延迟模式。你总是可以在 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);
                }
            }
            

            【讨论】:

            • 我喜欢这个。我只是将签名从拒绝更改为拒绝(原因:任何)
            【解决方案9】:

            接受的答案是错误的。使用范围和引用非常容易,尽管它可能会让 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 重新发明 Deferred 模式,这当然是可能的,并且您的方法有效(作为初始 OP 代码),但由于接受的答案中描述的“抛出安全原因”,这不是最佳实践。
            【解决方案10】:

            我创建了一个名为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

            【讨论】:

              【解决方案11】:

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

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

              【讨论】:

                【解决方案12】:

                这里的许多答案与this article 中的最后一个示例相似。 我正在缓存多个 Promise,resolve()reject() 函数可以分配给任何变量或属性。结果,我可以使这段代码更紧凑:

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

                这是一个使用此版本的defer()FontFace load 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();
                

                【讨论】:

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

                我整理了一个可以完成这项工作的要点: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();
                  });
                  ...
                });
                

                【讨论】:

                  【解决方案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】:

                    您可以将 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.
                    

                    【讨论】:

                      【解决方案16】:

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

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

                      【讨论】:

                        【解决方案17】:

                        我正在使用辅助函数来创建我所谓的“平面承诺”-

                        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 获得。

                        【讨论】:

                          【解决方案18】:

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

                          我使用了其他人写的工厂方法方法,但我也覆盖了thencatchfinally 方法,所以你也可以解决那些最初的承诺。

                          在没有外部执行者的情况下解决 Promise:

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

                          【讨论】:

                            【解决方案19】:

                            辅助方法可以减轻这种额外的开销,并给您同样的 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
                                });
                            });
                            

                            【讨论】:

                              【解决方案20】:

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

                              这是模式:

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

                              【讨论】:

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

                              在这里聚会有点晚了,但另一种方法是使用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 完全一样,只是没有 throw 安全性。这个问题的重点是如何在创建 Promise 时节省几行代码。
                              • 使用延迟是通常的方法,我不知道为什么这不是更高
                              • 优秀的答案!正在寻找 jQuery 提供的延迟功能。
                              • Deferred 是否已弃用?
                              【解决方案22】:

                              简单:

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

                              【讨论】:

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

                              不,没有其他方法可以做到这一点 - 我只能说这个用例不是很常见。就像 Felix 在评论中所说的那样 - 你所做的一切都会持续有效。

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

                              出于这个抛出安全的原因,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 做同样的事情?
                              • 不常见?我最终几乎每个项目都需要它。
                              • 对于用例,请考虑在触发事件并发生其他事情后您需要做一些事情。您想将事件转换为一个承诺并将其与另一个承诺结合起来。对我来说似乎是一个普遍的问题。
                              • @BenjaminGruenbaum - 另一个用例是如果您正在与网络工作者通信。如果您期望多条信息通过网络工作者消息(以未知的顺序)到达,最好为每条信息做出一个承诺 p[i],因此该信息的消费者可以等待该承诺或注册一个通过 p[i].then(callme) 回调。这个 Promise 需要由 worker.onmessage 来解决,而不是由 Promise 创建时提供的代码来解决。 (或者被 worker.onerror 中的代码拒绝。)基本上任何时候异步进程触发多个无序回调,你都想要 OP 所说的内容。
                              猜你喜欢
                              • 2023-01-18
                              • 1970-01-01
                              • 1970-01-01
                              • 2014-10-06
                              • 1970-01-01
                              • 2012-05-25
                              • 2022-01-17
                              • 1970-01-01
                              相关资源
                              最近更新 更多