簡體   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