Слушайте, когда обещание разрешается внутри функции исполнителя - PullRequest
0 голосов
/ 27 апреля 2018
  return new Promise(function(resolve, reject {
      const to = setTimeout(function(){

      });
  });

представьте, что я хочу убедиться, что ресурсы очищены из функции executor.

Я бы хотел сделать что-то вроде этого:

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

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

, но this недоступно в функции выполнения обещания. Есть ли способ очистить асинхронные ресурсы в исполнителе обещаний?

Полагаю, вы могли бы очистить их перед разрешением / отклонением вызова, но в некоторых случаях это сложнее.

Ответы [ 3 ]

0 голосов
/ 27 апреля 2018

Внутри исполнителя обещания вы не можете получить доступ к обещанию. Он еще не был назначен ни для чего, что может достичь ваш код.

Итак, у вас есть два варианта.

  1. Вы можете поместить свой код очистки вне исполнителя, чтобы получить доступ к возвращенному обещанию с помощью p.finally(). Затем вам также придется отслеживать ваши ресурсы за пределами исполнителя (что, возможно, неудобно).
  2. Вы можете заменить обратные вызовы resolve() и reject() вашей собственной заглушкой, которая выполняет очистку, а затем вызывает фактические resolve() или reject().
  3. Вы можете использовать Отложенный объект, который позволяет вам вызывать разрешение / отклонение извне исполнителя обещания, таким образом предоставляя вам доступ к 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() - все в одной области, что делает некоторые вещи чище (например, то, что вы пытаетесь сделать).

Сначала простая оболочка обещания, которая дает нам отложенный объект:

// 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;
}
0 голосов
/ 10 мая 2018

Этот OP описывает одного из уродливых snafus с 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;
   });

проблема с этим решением заключается в том, что обратный вызов в тогда называется асинхронным, так что может быть возможно, что таймер разрешается в промежуточный период? не уверен.

0 голосов
/ 27 апреля 2018

Не уверен, если вам нужно очистить таймаут после его срабатывания, но вы можете попробовать следующее:

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)
    }
  );
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...