ES6 обещал решить обратный вызов?

Я хочу запустить одно и то же действие, независимо от того, успешно ли выполнено мое обещание или нет. Я не хочу связывать одну и ту же функцию с обоими аргументами .then. Разве нет .always, как jQuery? Если нет, как мне это достичь?

Ответ 1

Не существует ли .always как jQuery?

Нет, там нет (пока). Хотя есть активное предложение , возможно, ES2018.

Если нет, как мне это достичь?

Вы можете реализовать метод finally самостоятельно следующим образом:

Promise.prototype.finally = function(cb) {
    const res = () => this
    const fin = () => Promise.resolve(cb()).then(res)
    return this.then(fin, fin);
};

или более широко, с передачей информации разрешения для обратного вызова:

Promise.prototype.finally = function(cb) {
    const res = () => this
    return this.then(value =>
        Promise.resolve(cb({state:"fulfilled", value})).then(res)
    , reason =>
        Promise.resolve(cb({state:"rejected", reason})).then(res)
    );
};

Оба гарантируют, что исходное разрешение поддерживается (когда в обратном вызове нет исключения) и ожидается, что promises.

Ответ 2

С помощью async/await вы можете сочетать await с try/finally, например:

async function(somePromise) {
  try {
    await somePromise();
  } finally {
    // always run this-- even if `somePromise` threw something
  }
}

Вот реальный пример, который я запускаю в работе с Node, используя плагин Babel async-to-generator.

// Wrap promisified function in a transaction block
export function transaction(func) {
  return db.sequelize.transaction().then(async t => {
    Sequelize.cls.set('transaction', t);
    try {
      await func();

    } finally {
      await t.rollback();
    }
  });
}

Я использую этот код внутри теста мокки рядом с Sequelize ORM, чтобы начать транзакцию БД, и независимо от результата вызовов БД внутри тест, всегда откат в конце.

Это примерно аналогично методу Bluebird .finally(), но IMO, гораздо более приятный синтаксис!

( Примечание. В случае, если вам интересно, почему я не await на первом обещании - это деталь реализации Sequelize. Он использует CLS "привязать" транзакцию SQL к цепочке Promise. Все, что происходит внутри одной и той же цепочки, привязано к транзакции. Ничего снаружи нет. Поэтому ожидание на Promise будет "закрыл" блок транзакций и сломал цепочку. Я привел этот пример, чтобы показать вам, как 'vanilla' Обработка обещаний может быть смешана вместе с асинхронными функциями и хорошо сочетаться.)

Ответ 3

Если вы не обновляете прототип/не можете, способ взломать наконец-то:

executeMyPromise()
.then(function(res){ return {res: res}; })
.catch(function(err){ return {err: err}; })
.then(function(data) {
    // do finally stuff
    if (data.err) {
        throw data.err;
    }
    return data.res;
}).catch(function(err) {
    // handle error
});

Ответ 4

Вот моя реализация .finally().

Promise.prototype.finally = function(cb) {
   return this.then(v=>Promise.resolve(cb(v)),
                    v=>Promise.reject(cb(v)));
};

Я протестировал его:

(new Promise((resolve,reject)=>{resolve(5);})).finally(x=>console.log(x));  //5

(new Promise((resolve,reject)=>{reject(6);})).finally(x=>console.log(x));  //6

(new Promise((resolve,reject)=>{reject(7);}))
.then(x=>x,y=>y)
.catch(x=>{throw "error";}) 
.finally(x=>{console.log(x); throw "error"; return x;})  // 7
.then(x=>console.log(x),y=>console.log('e'));  //e
// Uncaught (in promise) undefined

Ответ 5

Не нужно вводить новые понятия

const promise = new Promise((resolve, reject) => {
  /*some code here*/
});

promise.then(() => {
  /* execute success code */
}, () => {
  /* execute failure code here */
}).then(() => {}, () => {}).then(() => {
  /* finally code here */
});

Ответ 6

Чтобы продлить ответ Берги.

Возвращение Promise.reject() в обработчике улова предотвратит финализацию "then" для вызова.

Поэтому, если вы собираетесь обрабатывать обещание с ошибкой 2+, вы должны использовать шаблонный шаблон следующим образом:

return myPromise()
.then(() => ... )
.catch((error) => {
  ...
  myFinnaly();
  return Promise.reject(error);
})
.then(() => myFinnaly());