繁体   English   中英

侦听Promise在执行程序函数内部解析的时间

[英]Listen for when promise resolves inside executor function

  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并不是一个承诺执行功能的使用。 有什么办法可以清除诺言执行器中的异步资源?

我猜您可以在呼叫解决/拒绝之前清理它们,但是在某些情况下,这样做比较困难。

不知道触发后是否需要清除超时,但是您可以尝试以下操作:

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. 您可以将清除代码放在执行程序之外,您可以在其中使用p.finally()访问返回的promise。 然后,您还必须在执行程序之外跟踪资源(这可能很不方便)。
  2. 您可以使用自己的存根来替换resolve()reject()回调,以进行清理,然后调用实际的resolve()reject()
  3. 您可以使用Deferred对象,该对象允许您从p.finally()执行程序外部调用resolve / reject,从而使您可以访问p.finally()以及resolve()reject()都在同一范围内(这实际上是原始挑战)。

这是选项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()都在同一范围内,这会使某些事情变得更.finally() (例如您要执行的操作)。

首先是一个简单的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;
}

此OP描述了Promises imo的其中一个丑陋之处,但这可能起作用:

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

此解决方案的问题在于,那么的回调称为异步,因此计时器可能会在过渡期间解析? 不确定。

暂无
暂无

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

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