...тема продолжается
Цитата:
Пусть у нас есть «промисы» p1, p2, p3, ... Вот один из вариантов, как их можно запустить последовательно... [ () => p1, () => p2, () => p3, () => p4 ].reduce((seq, p) => seq.then(p), Promise.resolve()); `p1` запускается сразу, как создан, но функция `() => p1` позволяет отложить запуск до того времени, когда она будет вызвана. Обратите внимание, что метод массива `reduce` возвращает в примере выше «промис», который выполнится, когда будут последовательно выполнены все «промисы» из массива. Так что можно дальше вызывать метод `then`. Вот ещё один из вариантов, как можно те же «промисы» запустить последовательно... (async () => [ await p1, await p2, await p3, await p4 ])(); Этот вызов тоже возвращает «промис», который выполнится, когда будут последовательно выполнены все «промисы» из массива... Цитата:
function* getTasks() { const a = Array.from(Array(66), x => 1400 * Math.random() + 100); for(let i = 0, len = a.length; i < len; i+=10) yield Promise.all(a.slice(i, i+ 10).map(delay)); function delay(ms) { return new Promise(r => { setTimeout(() => { r(`done: ${ms}ms`); }, ms); }); } } (async() => { for await(const task of getTasks()) { console.log(task); } console.log("all done"); })(); Цитата:
(async function() { const response = await fetch("https://yesno.wtf/api"); const { answer } = await response.json(); console.log(`Ответ ${answer} без магии`); })(); fetch("https://yesno.wtf/api") .then(response => response.json()) .then(({answer}) => console.log(`Ответ ${answer} без магии`)) ; Ваша конструкция из поста №12 без async/await... они не индентичны в плане трансформации кода, он просто переписан так, чтобы вывод был одинаковый... "use strict"; 'esversion: 6'; function procData(val, i){ return new Promise(resolve => setTimeout(() => { var ret = i + "\t" + val + " #"; console.log(ret); resolve(ret); }, 3000)); } [3, 5, "asdf", 8, 0] .reduce((seq, item, n) => seq .then(retArr => procData(item, n) .then(x => retArr.concat(x)) ), Promise.resolve([])) .then(console.log); Ещё примеры async/await, оба вычисленных выражения обозначают одно и тоже... (async function() { return 5 })(); Promise.resolve(5); (async function() { throw "Упс!" })(); Promise.reject("Упс!"); Цитата:
Такой объект содержит список выражений и объявлений, который выполняется при вызове функции, т. е. как обычная функция, однако ещё имеется выражение с ключевым словом await, например `await b;`. Давайте рассмотрим, как это действует. Пусть у нас есть блок тела из обычной функций типа `Function` cо следующими выражениями: () => { a; b; c; return d; } Когда фукция будет вызвана, сначала вычислится a затем b, c, d. Вычисленное d будет результатом вычисления функции. Порядок вычисления всегда линейный и все понимают как это работает. Теперь рассмотрим блок тела из асинхронной функций типа `AsyncFunction` cо следующими выражениями: async () => { a; await b; c; return d; } Давайте его вычислим. Здесь действуют такие правила(только для вычисления списка выражении): 1. для самого левого выражения с меткой await внутри блока с меткой async: a. произведи следующую замену: i. A = await B; <всё-до-конца-блока> --> return B.then(async A => { <всё-до-конца-блока> }) если подходит ii. await B; <всё-до-конца-блока> --> return B.then(async () => { <всё-до-конца-блока> }) iii. B --> Promise.resolve(B) если B не «промис» b. если ещё есть await см. п. 1 2. для всех блоков с меткой async: a. убери async b. return A --> return Promise.resolve(A) если A не «промис» c. throw A --> return Promise.reject(A) d. добавь в конец блока return Promise.resolve() если нет return получается так(пусть b «промис»): async () => { a; await b; c; return d; } // 1a async () => { a; return b.then(async () => { c; return d; }); } //2a () => { a; return b.then(async () => { c; return d; }); } //2a () => { a; return b.then(() => { c; return d; }); } //2b () => { a; return b.then(() => { c; return Promise.resolve(d); }); } // конечный результат Впринципе видно, что тут нет никакой магии, это просто трансформация кода. Можно сказать, что async/await является синтактическим сахаром для выражения, которое получается после перевода его в обычный синтаксис. Давайте ещё один пример вычислим, который я приводил выше... (async function() { throw "Упс!" })(); //2a (function() { throw "Упс!" })(); //2c (function() { return Promise.reject("Упс!"); })(); // и ещё можно сделать вызов Promise.reject("Упс!"); // конечный результат Из этих преобразовании видно, что асинхронная функция всегда возвращает «промис» Цитата:
«Промисы» обладают интересными свойствами. Обозначим p = какой-либо «промис», id = Promise.resolve.bind(Promise) (типа A => Promise<A>), f, g и h какие-либо функция (типа A => Promise<B>). Тогда выполняется: p.then(id).then(f) === p.then(f).then(id) === p.then(f) p.then(f).then(x => g(x).then(h)) === p.then(x => f(x).then(g)).then(h) === p.then(f).then(g).then(h) p.then(f).then(g) === p.then(x => f(x).then(g)) Для каждой пары Promise<A> и Promise<B> задана операция cвязывания `then` Для Promise<A> задано тождественное cвязывание `Promise.resolve` «Промис» не является цепочкой вызовов. Объект «промис» является контейнером над значением, которое может быть доступно в данный конкретный момент времени, или, возможно, будет доступно только в будущем. #funfact Категории включают объекты и морфизмы. Последние представляют собой вещи и способы перехода от одной вещи к другой. В асинхронных вычислениях JavaScript'а под такими объектами обычно понимаются «промисы», а под морфизмами — методы then, catch и finally, которые переводят состояние одного «промиса» в состояние другого «промиса». Вопросы для исследования: Возможно ли получить мгновенное значение промиса p? Если написать `p.then(console.log);`, а промис ещё не выполнился, то мы ничего не получим. Возможно ли мгновенно узнать состояние промиса? Возможно ли, чтобы промис разрешился другим промисом? Означает ли это, что не существует схлапывания «промиса»? Возможна ли передача состояния между промисами? Представте себе контейнер, назовём его Writer, у которого есть лог в который можно писать и передавать его между промисами, а также возвращаемое значение. Как бы вы такое реализовали? // набросок класса class Writer extends Promise { then() { } runWriter() { return ""; } static tell(log) { return new Writer(r => r([null, log])); } static resolve(value) { return new Writer(r => r([value, ""])); } } // пример тестируемой функции function half(v) { return Writer.tell(`I just halfed ${v}!`).then(_=> v / 2); } // тестирование в консоли // > half(8).then(half); // < Promise { <resolved>: [2, "I just halfed 8!I just halfed 4!"] } // > await half(8).then(half); // < 2 // > half(8).then(half).runWriter(); // < "I just halfed 8!I just halfed 4!" // > |
Цитата:
function Try(fn) { return new Promise(r => r(fn())); } Цитата:
если это наш промис (созданный через new Promise(...)), то в его функцию можно дописать изменение какого-то внешнего флажка, и смотреть этот флажок. А иначе никак - даже если промис уже зарезолвлен, функция в then пойдет следующим микротаском, т.е. синхронно не определить. Можно только асинхронно выяснить, что на момент начала проверки промис "уже был зарезолвлен" :) Цитата:
|
Во втором случе можно такой хак зафигачить)
var p = new Promise(e=>e(1)); Object.defineProperty(p, 'then', { get(){ delete p.then; return; //первый раз возвращаем undefined и обманываем систему :) }, enumerable: true, configurable: true }) new Promise(e=>e(p)).then(res => alert(res instanceof Promise) ); //возвращает промис :) В первом случае тоже можно свою обёртку над стандартным промисом прилепить, которая state будет запоминать. Но зачем?) Вообще, имхо, слишком мудрите вы с этим. |
Цитата:
Цитата:
var oldPromise = Promise; window.Promise = function(f) { console.log('promise'); return new oldPromise(f); };в хроме тот же fetch не подхватывает этот новый Promise проверку можно сделать, но только асинхронно function getPromiseState(p) { var state = 'pending'; p.then(function() { state = 'resolved'; }, function() { state = 'rejected'; }); return Promise.resolve().then(function() { return state; }); } // -------- getPromiseState(promise).then(console.log); |
Alexandroppolus, концептуально как-то так:
(function(prototype){ const then = prototype.then; prototype.state = 'pending'; prototype.then = function(){ const next = then.apply( then.call( this, resolve => { this.state = 'fulfilled'; return resolve; }, reject => { this.state = 'rejected'; throw reject; } ), arguments ); return next; } }(Promise.prototype)); +для Promise.resolve/reject надо перегрузку, ешё мб что-то с catch и final. +отдельно обработку для случаев когда promise возвращает не promise(передавать в таких случаях статус с this на next, ибо оный в любом случае не поменяется) + ... |
Aetae,
state меняется только после вызова then, и то не сразу |
Alexandroppolus, и? Должно быть как-то по другому?)
|
Aetae,
ну вот, например, я открыл консоль на этой странице, выполнил твой код, а потом: > prom = fetch('/') < Promise {<pending>} > prom < Promise {<resolved>: Response} > prom.state < "pending" и немножечко смущает, что вот так. Думаю, Malleys спрашивал про то что в треугольных скобках |
Alexandroppolus, ну без then в промисе смысла особого нет.)
А так просто придётся подменять каждую нужную нам нативную фигню возвращающую промис, т.к. все они хранят в себе ссылку на нативный промис, который нам не подменить. Возможно можно как-то поиграться с Symbol.species, но тут уж хз. |
Цитата:
function getPromiseValue(promise) { return Promise.race([ promise, Promise.resolve() ]); } // > var p = fetch("/"); // getPromiseValue(p); // < Promise { <resolved>: undefined } // > getPromiseValue(p); // < Promise { <resolved>: Response } // > |
Часовой пояс GMT +3, время: 21:25. |