Как стать автором
Обновить

Комментарии 28

Вот вы все только обещаете...


А если серьезно, то спасибо) Вот вроде все понятно, но когда приходится иногда написать что-то подобное, то сразу появляется "две проблемы"©

Обратите внимание на то, что каждая цепочка обещаний заканчивается вызовом catch(). Если этого не делать, то возникающие ошибки будут пропадать в недрах обещаний и, тогда невозможно будет установить, где произошла ошибка.

Неправда, нигде они не теряются и вполне их можно захендлить

window.addEventListener('unhandledrejection', e => { 
    console.log('handle', e);
    return e.preventDefault();
});


Если обработчика не будет, то промис просто кинет exception, который можно увидеть в консоли и принять меры.

А в Хроме можно и без события неперехваченные ошибки в консоли увидеть.

Для тех кто не верит:


К сожалению в node.js это не всегда так. Если обработчика не будет, то скрипт завершится без ошибок, даже если они на самом деле есть.

я написал для этого обработчик, который роняет процесс nodejs, т.к. имхо необработанный reject == исключение.

Выстраивание цепочки обещаний в цикле forEach

Я как раз для этого модуль foreach-timeout написал.
Предположим, нам нужно выполнить какое-либо асинхронное действие для каждого элемента массива array. Пусть это асинхронное действие обернуто в некую функцию doSomething(), которая возвращает обещание выполнить это асинхронное действие. Шаблон того, как в этом случае выстроить цепочку обещаний, как это ни странно, основан не на использовании функции forEach, а на использовании функции reduce


А разве не?

...
Promise
    .all(arr.map((item) => doSomething(item)))
    .then( ... );

Ваш способ запустит все асинхронные действия одновременно, а не последовательно.

В задаче нет упоминания про последовательность.
Как же в цикле последовательно выполнить обещания? [...]
Перейдем к рассмотрению самих механизмов цикличного построения цепочек обещаний. Будем отталкиваться от привычных всем программистам разновидностей циклов: цикл for и цикл forEach.

Это если вы пользуетесь Bluebird.

// Повторное разрешение того же обещания
promise.then(function(result){
  // Теперь уже асинхронный вызов не выполняется.
  // В эту функцию передается сохраненный результат
  // разрешения обещания
});

Асинхронный вызов еще как выполняется.

Думаю, имелось в виду, что executor выполняться второй раз не будет.

Какой executor? Если вы имеете в виду тот, который вернул promise — то он первый раз не выполнялся. Потому что выполнился раньше.

https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise
executor
A function that is passed the arguments resolve and reject. The executor function is executed immediately by the Promise implementation, passing resolve and reject functions (the executor is called before the Promise constructor even returns the created object). The resolve and reject functions, when called, resolve or reject the promise respectively. The executor normally initiates some asynchronous work and then, once that completes, calls either the resolve or reject function to resolve the promise or else reject it if an error occurred.

Да, он выполняется при создании промиса не зависимо от того, сколько раз у него вызывался метод then() (даже если 0 раз). Думаю, это хотел сказать автор, просто выразил свою мысль некорректно. Executor кстати не асинхронно запускается, другое дело, что внутри него как правило есть асинхронный код. А в целом, все эти моменты легко понять, если на вывод этого кода внимательно посмотреть:
p = new Promise(r => { console.log('executor'); r(); });
console.log('after creation');
p.then(() => console.log('in chain 1')).then(() => console.log('in chain 2'));
p.then(() => console.log('in chain 3'));
console.log('after chaining');

// Первое разрешение обещания
promise.then(function(result){
  // При разрешении обещания происходит асинхронный вызов,
  // результат которого передается в эту функцию
});
// Повторное разрешение того же обещания
promise.then(function(result){
  // Теперь уже асинхронный вызов не выполняется.
  // В эту функцию передается сохраненный результат
  // разрешения обещания
});

Не верно это.
Получение результата промиса происходит во время синхронной инициализации самого промиса:


console.log('1');
const promise = new Promise(resolve => {
    resolve('result');
    console.log('2');
});
console.log('3');

/*
В консоль выведется 1,2,3, а promise уже содержит готовый результат 'result'
*/

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

результат всегда получается по время инициализации самого промиса

Всегда, кроме тех случаев, когда он получается асинхронно :)

Да, неверно сформулировал.
Имелось в виду, что получение результата происходит в функции инициализации, а синхронно или асинхронно вызывается resolve — не суть важно.

Формулировка "получение результата происходит в функции инициализации" как раз и означает синхронное получение.

НЛО прилетело и опубликовало эту надпись здесь
А почему у вас не написано про конструкции типа:
promise.then(function (result){
  // success
}, function (err) {
  // error
});


Это имеет смысл, когда у вас есть вложенные promise, например:
promise1.then(function(result){
  // success promise1
  return promise2.then(function() {
     // success promise2
  });
}, function (err) {
  // error promise1
}).catch(function(err) {
  // error promise2
});
вложенные promise


Это антипаттерн :)
Представим ситуацию, когда серверу из вашего примера одновременно приходит два запроса, для простоты положим, что до этого запросов к серверу не было и переменная requestQueue равна Promise.resolve()

И у вас одновременно запускается два обработчика
function processRequest(req, res){
  requestQueue = requestQueue.then(function(){
    ...
  });
}

И запросы пришли настолько одновременно, что при вычислении requestQueue в правой части они оба получили начальное состояние Promise.resolve() и, соответственно, выполнятся не последовательно. Или нам кто-то (стандарт или движок ecmascript/javascript?) гарантирует атомарность такой операции? Мне кажется, что нет.
Но даже если да, то в нашем случае получается что сам веб-сервер превращается в синхронный, что означает бессмысленность использования Promise.

Так как же бороться за атомарность получения И присвоения значения переменной в случае асинхронных вызовов? Я уж надеюсь, что стандарт нам хотя бы гарантирует атомарность присвоения значения, верно?
Не знаю, почему так многих восхищают эти промисы, хотя они делают код чуть лучше, хотя на вкус те же спагети.
Другое дело генераторы.
sync(getData('habrahabr.ru', 'js@generator.com'))((data) => console.log(data))

*getData(url, email) {
  const password = yield getPassword(email) // return function(callback) { Account.findOne({email: email}, (error, data) => { callback(data.password) })
  const result = yield sync(request(url, email, password))
  if (result.error) new Error(result.error)
  return result.data
}
//Обвертка для вызова ген-фу
function sync(iterator) {
  let job = iterator.next()
  let done = () => {}
  const next = () => {
    if (typeof(job.value) == "function") {
      job.value(function(val) {
        job = iterator.next(val)
        if (!job.done) next()
        else done(job.value)
      })
    } else done(job.value)
  }
  return (callback) => {
    done = callback
    next()
  }
}

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории