было бы более справедливое сравнение.

romises

Обещания ES6 являются конечными автоматами и, следовательно, требуют сложных реализаций. Помимо этого, в спецификации Promise / A + есть много нюансов:

перегруженныйthen (Карта / цепь)рекурсивное сплющивание / затем ассимиляцияавтоматический подъемнесколько подписчиков (многоадресная рассылка)нетерпеливая оценка

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

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

Стиль прохождения продолжения

Стиль передачи продолжения абстрагируется от асинхронных потоков управления, поскольку он избавляется отreturn заявление. Чтобы восстановить сочетаемость, нам просто нужен функтор в контексте продолжений:

const compk = (f, g) => x => k => f(x) (x => g(x) (k));


const inck = x => k => setTimeout(k, 0, x + 1);

const log = prefix => x => console.log(prefix, x);


compk(inck, inck) (0) (log("async composition:")); // 2

Конечно, мы хотим составить более двух функций. Вместо того, чтобы писать вручнуюcompk3 = (f, g, h) => x => k => f(x) (x => g(x) (y => h(y) (k))) и т. д. желательно программное решение:

const compkn = (...fs) => k => 
 fs.reduceRight((chain, f) => x => f(x) (chain), k);


const inck = x => (res, rej) => setTimeout(res, 0, x + 1);

const log = prefix => x => console.log(prefix, x);


compkn(inck, inck, inck) (log("async composing n functions:")) (0); // 3

В этом подходе полностью отсутствует обработка исключений. Давайте наивно адаптируем общий шаблон обратного вызова:

const compk = (f, g) => x => (res, rej) =>
 f(x) (x => g(x) (res), x => rej(x));

const compkn = (...fs) => (res, rej) =>
 fs.reduceRight((chain, f) => x => f(x) (chain, x => rej(x)), res);


const inc = x => x + 1;

const lift = f => x => k => k(f(x));

const inck = x => (res, rej) => setTimeout(res, 0, x + 1);

const decUIntk = x => (res, rej) =>
 setTimeout(x => x < 0 ? rej("out of range " + x) : res(x), 0, x - 1);

const log = prefix => x => console.log(prefix, x);


compk(decUIntk, inck) (0)
 (log("resolved with:"), log("rejected with:")); // rejected

compkn(inck, decUIntk, inck)
 (log("resolved with:"), log("rejected with:")) (0); // resolved

Это всего лишь эскиз - нужно приложить немало усилий, чтобы найти правильное решение. Но это доказательство концепции, я думаю.compk/compkn очень просты, потому что они не должны бороться с государством.

Итак, каковы преимущества сложных обещаний ES6 перед стилем передачи продолжения и соответствующими DSL, такими как функтор / монада продолжения?

Ответы на вопрос(1)

Ваш ответ на вопрос