在promise执行函数内部解析时监听

时间:2018-04-27 17:18:36

标签: javascript node.js es6-promise

  return new Promise(function(resolve, reject {
      const to = setTimeout(function(){

      });
  });

想象一下,我想确保从执行器函数内部清理资源。

我想做这样的事情:

  return new Promise(function(resolve, reject {
      const to = setTimeout(function(){

      });
      this.finally(function(){
        clearTimeout(to);
      });
  });

this在promise执行函数中不可用。 有没有办法在promise执行器中清理异步资源?

我想你可以在致电解决/拒绝之前清理它们,但有一些情况会更难。

3 个答案:

答案 0 :(得分:1)

不确定是否需要在触发后清除超时但您可以尝试以下操作:

var someTest = () => {
  var t;
  var p = new Promise(
    (resole)=>{
      t = setTimeout(resole,2000)
    }
  );
  p.finally(
    ()=>console.log(t,clearTimeout(t))
  )
  return p;
}
someTest();

或者您可以尝试以下方法:

var someTest = () =>
  new Promise(
    (resole)=>{
      t = setTimeout(resole,2000)
    }
  ).then(
    result=>{
      //clean up
      return result
    },
    error=>{
      //clean up
      return Promise.reject(error)
    }
  );

答案 1 :(得分:1)

从承诺执行者内部,您无法访问承诺。尚未将其分配给您的代码可以访问的任何内容。

所以,你有两个选择。

  1. 您可以将清理代码放在执行程序之外,您可以使用p.finally()访问返回的承诺。然后,您还必须在执行者之外跟踪您的资源(这可能不方便)。
  2. 您可以使用自己的存根替换resolve()reject()回调,然后调用实际的resolve()reject()
  3. 您可以使用Deferred对象,该对象允许您从promise执行者外部调用resolve / reject,从而使您可以在同一范围内访问p.finally()resolve()以及reject()(这真是原始挑战的源头。)
  4. 以下是选项#2的示例:

    return new Promise(function(rv, rj) {
        // have to try/catch here because an execption will automatically reject
        // without us having seen it
        try {
            // declare wrappers that should be called by code in this executor
            // do not call rv() and rj() directly
            function resolve(arg) {
                finally();
                rv(arg);
            }
            function reject(arg) {
                finally();
                rj(arg);
            }
    
            // cleanup code that is only ever called once
            let finallyCalled = false;
            function finally() {
                if (!finallyCalled) {
                    clearTimeout(to);
                    finallyCalled = true;
                }
            }
    
            const to = setTimeout(function(){
    
            });
    
            // elsewhere in this executor it should call resolve() or reject()
    
        } catch(e) {
            reject(e);
        }
    });
    

    以下是选项#3的示例。

    通常不建议使用延迟对象,但它们确实允许您访问.finally()resolve()reject()所有相同的范围,这样可以使某些内容更清晰(就像您所做的那样)重新尝试)。

    首先是一个简单的promise包装器,它为我们提供了一个Deferred对象:

    // can be used as either:
    //    let d = Promise.Deferred();
    //    let d = new Promise.Deferred();
    //    d.then(...)
    //    d.resolve(x);
    //    d.finally(...)
    Promise.Deferred = function() {
        if (!(this instanceof Promise.Deferred)) {
            return new Promise.Deferred();
        }
        let p = this.promise = new Promise((resolve, reject) => {
            this.resolve = resolve;
            this.reject = reject;
        });
        this.then = p.then.bind(p);
        this.catch = p.catch.bind(p);
        this.finally = p.finally.bind(p);
    }
    

    然后,您可以像这样使用它:

    // usage
    function yourFunction() {
        let d = new Promise.Deferred();
        const to = setTimeout(...);
    
        // other code here that will call d.resolve() or d.reject()
    
        // cleanup code
        d.finally(function() {
            clearTimeout(to);
        });
        return d.promise;
    }
    

答案 2 :(得分:0)

这个OP用Promises imo描述了一个丑陋的snafus,但这可能有用:

 return new Promise(function(resolve, reject {
      const to = setTimeout(function(){
           console.error('timed out');
           reject('timed out');
      });

      doSomething(function(err, data){
           if(!to._called){
            resolve({to, data})
           } 
      });
  })
  .then(function(v){
       clearTimeout(v && v.to);
       return v && v.data;
   });
使用此解决方案的问题是,then中的回调称为异步,因此定时器可能会在临时解析?不确定。