Promise polyfill
Тут задавали вопрос, что внутри Deferred, а еще нативная поддержка Promise появилась в браузерах. Чтобы окончательно разобраться в «обещаниях», решил свой полифил написать
ES6 Promise polyfill на GitHub, для работы требуется setImmediate. Реализовано поведение, максимально похожее на native Promise в Chrome и Aurora. Можно использовать в Nodejs:
var Promise = require('es6-promises');
Установка: Bower bower install promises npm npm install es6-promises |
По поводу полифилов. Ты зачем перезаписываешь свойства:
Object.keys = Object.keys || function().. Это вобще дикость какая-то: Object(object) !== object Кстати, может кто пояснить, в каком стандарте писаны методы Array.slice и прочие? |
Цитата:
|
Добавлю ссылок:
An open standard for sound, interoperable JavaScript promises—by implementers, for implementers MDN Promise --- Object(this).constructor !== Promise // -> isPromise(object) - такие штуки тоже не люблю var results = Array(promises.length); на мой взгляд new надо писать для наглядности - ну и по возможности я бы запихнул функции function nextResolve(data) { function nextReject(error) { function resolve(data) { function reject(error) { в прототип как приватные (чтобы не создавались каждый раз) - а в целом выглядит симпатично :) Еще я вспомнил, что у тебя была тема про асинхронность. Так вот setImmediate там бы вписалась очень хорошо) --- Цитата:
Цитата:
--- GOD, пошел отсюда далеко и надолго :) |
Цитата:
Цитата:
В Aurora 29
Array.slice.toString()
"function slice() {
[native code]
}"
Цитата:
Object(object) === object стандартная проверка, сто лет так делаю, до этого никто не удивлялся :)http://kangax.github.io/es5-compat-table/ http://kangax.github.io/es5-compat-table/es6/ http://kangax.github.io/es5-compat-table/non-standard/ http://people.mozilla.org/~jorendorf...ototype-object не нахожу здесь Object.isObject или чего-то подобного, в глобале создавать такую функцию не хочу, а с неймспейсом запись не намного короче будет. Мне больше нравится запись if (Object(arg).length), чем if (isObject(arg) && arg.length).Object.is не подходит, потому что Object.is(null, null) → true. Поэтому не вижу особой необходимости создавать isObject для полифила, в библиотеке или фреймворке — без проблем.Цитата:
this.constructor, потому что в strict режиме this может быть undefined.Да isPromise добавлю, думаю ни один раз понадобится, там надо разобраться, что происходит, когда в дженерики promise передают. Или на this instanceof Promise заменю.Цитата:
Цитата:
|
Цитата:
Цитата:
Цитата:
|
Цитата:
Цитата:
typeof null → "object". Обсуждали как этот вариант лучше пропускать. В prototype.js полно таких проверок. |
Цитата:
|
Цитата:
Цитата:
|
Цитата:
|
Короче магическим образом заставил IE8 работать: переименовал параметры функции и параметр в try-catch, так чтобы они не совпадали. Повторить баг не получилось, но reason не понятно когда становился undefined :D
function (reason) {
…
try {
…
}
catch (*!*reason*/!*) {
…
}
…
}
вторая причина тут http://javascript.ru/forum/misc/4588...-funkcijj.html |
Накопилось много вопросов. Мужайся :)
1. Закончен ли полифил? (ие8 меня не интересует) 2. Покрыт ли он тестами? 3. Будет ли выложен на гитхаб? 4. Планируется ли адаптация (setImmediate -> nextTick, ...) под node.js? |
Цитата:
Цитата:
Цитата:
Цитата:
var setImmediate = process.nextTick; ну и там всякие Object.assign и Array generic methods npm установщик никогда не делал, надо будет разбираться -------------------------------- хм Цитата:
а тут http://esdiscuss.org/topic/promise-c...romise-resolve вроде спорят, что это разные методы были ------------------ чорт баг нашел: resolver только один раз может выполнится, то есть реюз обещания не возможен, но при этом then'ы все должны выполнятся, даже если promise уже settled |
Цитата:
А ваще: https://github.com/NobleJS/setImmediate |
О точно есть, забыл, что в node-webkit его из global надо вытаскивать, когда проверял
|
Короче у меня уже promise мозга :D
Чтобы сделать обещания одноразовыми, почти все заново переписал… |
Цитата:
|
Octane, сейчас пытаюсь установить твой promise-polyfill и понимаю, что это не так просто сделать :)
Ситуация такая: я использую es5-shim, т.е. es5 у меня можно сказать есть. Для того, чтобы твой полифил запустился, мне необходимо еще установить: Object.assign Array.slice Array.forEach Array.every window.setImmediate Можно это дело отразить хотя бы в комментариях к полифилу? А то получается, каждый разработчик, кот. захочет воспользоваться твоим promise-полифилом, обязан прочитать код и проверить его на наличие es6 фич в том случае, если он не использует все твои полифилы. И идеале, было бы хорошо ссылок набросать на required для es3 и es5 для данного полифила. Лично я бы выкинул из реализации Object.assign, т.к. без него можно обойтись. Иными словами, ты заставляешь меня тянуть Object.assign :) А также Array.slice Array.forEach Array.every несмотря на то, что es5 у меня есть. |
Как?! как можно жить без
Object.assign?! :D Да, вечером оформлю.Пока что вот ссылки на гитхаб: Object.assign
//using Object.keys: goo.gl/0QNMDz
//several sources: twitter.com/rwaldron/status/454114058640183296
//people.mozilla.org/~jorendorff/es6-draft.html#sec-object.assign
if (!Object.assign) {
Object.assign = function (target) {
Array.prototype.slice.call(arguments, 1).forEach(function (source) {
Object.keys(source).forEach(function (key) {
target[key] = source[key];
});
});
return target;
};
}
Array generics
//Array generic methods
new function () {
function fastApply(method, args) {
var target = args[0];
switch (args.length) {
case 1:
return method.call(target);
case 2:
return method.call(target, args[1]);
case 3:
return method.call(target, args[1], args[2]);
}
return method.apply(target, Array.prototype.slice.call(args, 1));
}
function createGeneric(method) {
return function () {
return fastApply(method, arguments);
};
}
function createGenerics(source, names) {
return names.reduce(function (methods, name) {
methods[name] = createGeneric(source[name]);
return methods;
}, {});
}
function implement(object, methods) {
Object.keys(methods).forEach(function (name) {
if (!(name in object)) {
object[name] = methods[name];
}
});
}
implement(Array, createGenerics(Array.prototype, [
'concat', 'every', 'fill', 'filter', 'find',
'findIndex', 'forEach', 'indexOf', 'join',
'lastIndexOf', 'map', 'pop', 'push', 'reduce',
'reduceRight', 'reverse', 'shift', 'slice',
'some', 'sort', 'splice', 'unshift'
]));
};
setImmediate IE9+
window.setImmediate || Object.assign(window, window.msSetImmediate ? {
//IE10
setImmediate: window.msSetImmediate,
clearImmediate: window.msClearImmediate
} : new function () {
var id = 0,
storage = {},
firstCall = true,
message = 'setImmediatePolyfillMessage';
function fastApply(args) {
var func = args[0];
switch (args.length) {
case 1:
return func();
case 2:
return func(args[1]);
case 3:
return func(args[1], args[2]);
}
return func.apply(window, Array.prototype.slice.call(args, 1));
}
function callback(event) {
var data,
key = event.data;
if ('string' == typeof key && key.startsWith(message)) {
data = storage[key];
if (data) {
fastApply(data);
delete storage[key];
}
}
}
return {
setImmediate: function () {
var key = message + ++id;
storage[key] = arguments;
if (firstCall) {
firstCall = false;
window.addEventListener('message', callback);
}
window.postMessage(key, '*');
return id;
},
clearImmediate: function (id) {
delete storage[message + id];
}
};
});
сам Promise polyfill правда я там в последней версии дописал window. перед setImmediate, потому что 'setImmediate' in Window.prototype → true, не знаю, может зря так сделал, если кто в Nodejs захочет подключить, работать не будет, хотя для ноды и так миллион полифилов есть… сделать через global?---------- Наверное отдельный самодостаточный репозиторий на гитхабе сделаю |
Я еще немного покритиХую :)
--- На мой взгляд, ты заставляешь тянуть es6 код в проект. Не каждому проекту он нужен. Поэтому, как мне кажется, логичным было бы сделать возможность его не тянуть. Например, в виде версий для es5 и es6. По поводу ноды - я за универсальность (по возможности). Допустим, есть миллион полифилов, но я работаю с твоим на клиенте. Я уже знаю, что он фуричит, проверен. Почему бы не использовать его и на сервере? |
Promise уже не ES5, логично предполагать наличие es6-shim, но не составит труда убрать ES6-Object.assign и мозиловские Array generics. Ок, сделаю отдельно, будет только @requires setImmediate.У меня опыт Nodejs только в составе node-webkit, поэтому особо не суюсь в серверные скрипты. |
Хы пока выносил в отдельный репозиторий, нашел различие в поведении нативной реализации в Chrome и Firefox:
var p1 = Promise.resolve(),
p2 = Promise.resolve();
p1.then(p2).then(function () {
console.log('Firefox!'); //сработает только в Firefox
});
и что-то не найду, как должно быть, везде описан случай:
var p1 = Promise.resolve(),
p2 = Promise.resolve();
p1.then(function () {
return p2;
}).then(function () {
console.log('Works well!'); //тут оба браузера сработают, но не полифил
});
щас буду исправлять :(--------------- Отдельный репозиторий Promise не требующий Object.assign и Array generics. В ноде подключается так:
var Promise = require('es6-promises').Promise;
|
Octane,
Крутяк :victory: |
Цитата:
|
Спасибо)
--------------------------------------
var p1 = new Promise(function (resolve) {
resolve();
}),
p2 = new Promise(function (resolve) {
resolve();
});
p1.then(p2).then(function () {
console.log('Works'); //Aurora 31
}, function () {
console.log('Error'); //Chrome 36
});
и какому варианту следовать? :D |
Цитата:
![]() |
Octane,
а ты этот проект видел https://github.com/slightlyoff/Promises ? |
Я много пересмотрел, в этом какие-то нестандартные Promise.any, Promise.every, Promise.some, Promise.fulfill. Наверное еще по ранним черновикам делал, или сами названия выдумывал. Странно конечно, это же участник ТС39.
|
Цитата:
Может для this._* сделать неперечисляемыми? package.json сделаешь? :) |
process.nextTick это для старых версий Nodejs, сейчас там встроен global.setImmediate. MutationObserver я хз для чего там, поиск не нашел postMessage, наверное события обсервера используют чтобы асинхронно вызывать функции, ну или хз надо будет внимательнее посмотреть.
установку через npm и bower сделаю, как баг исправлю. Цитата:
|
Цитата:
Цитата:
|
у меня тоже не было этого бага, пока не добавил параметр _defer, чтобы resolver при создании promise сразу запускался, а не при первом вызове then:
вся логика в then, только он запускает resolver, чтобы обойтись малой кровью, добавил параметр _defer
function Promise(resolver, _defer) {
...
return _defer ? this ? this.then();
}
Promise.prototype.then = function () {
...
resolver(...)
...
return new Promise(..., _defer = true);
};
но теперь всплыл этот баг. |
неужели промисы так сложно реализуются О_О
у меня промисы получались в 50 строк кода со всеми плюшками. сделать? |
Конечно сделай :)
Что-то у меня голова сегодня не варит ничего исправлять, запилил пока что установку: Bower bower install promises npm npm install es6-promises используем модуль
var Promise = require('es6-promises').Promise;
------------ а readme тут https://www.npmjs.org/package/es6-promises само обновится со временем или надо пепубликовать? |
Цитата:
Цитата:
|
а как должно быть?)
npm же всегда папку создает, просто promise уже занято конечно, пришлось так назвать |
Цитата:
var Promise = require('es6-promises');
PS: глянь как у меня релиз публикуется :) |
ага, спасибо, разобрался, теперь работает так.
ошибку с settled promise тоже исправил |
setImmediate = (global.window || global).setImmediate, Почему не написать посто global.setImmediate? |
А что у тебя с версионностью?
Добавь release таск, он автоматически будет менять циферки и публиковать в npm. Сейчас получается, что ты изменения внес, а npm их нет! ;) |
| Часовой пояс GMT +3, время: 19:48. |