Спасибо за мнение! К сожалению ваш код не решает проблему,
promise = new Promise(function(resolve){
setTimeout(function(){console.log("first run"); resolve(100)}, 1000)
})
Здесь resolve(100) не может быть вызвано раньше, чем сработает setTimeout...
Сообщение от fuckingquest
|
А какой смысл его заставлять выполнится, если данные еще не готовы?
|
Они готовы, но находятся не внутри функций "промиса". Другой вариант -- заставить "промис" передумать, т. е. как вызвать reject() извне?
Простая обёртка вокруг каждого "промиса" позволяет добиться такого результата
function defer(promise) {
var resolvingFunctions;
var promise = new Promise(function(resolve, reject) {
resolvingFunctions = { resolve, reject };
});
promise.resolve = resolvingFunctions.resolve;
promise.reject = resolvingFunctions.reject;
return promise;
}
// Пример
var promise = defer();
promise.then(function() {
console.log("5+");
});
// "промис", выполнись!
promise.resolve();
Однако мне не нравится отдельный объект(который впринципе не нужен) и то, что придётся оборачивать "промисы", поэтому вопрос о том, как вызвать resolve() остаётся актуальным.
Т. е. как написать resolve/reject в Promise.prototype, я не представляю... Проблема в том, что нет доступа к resolvingFunctions из 8 пункта.
When the Promise function is called with argument executor the following steps are taken:
1. If NewTarget is undefined, throw a TypeError exception.
2. If IsCallable(executor) is false, throw a TypeError exception.
3. Let promise be OrdinaryCreateFromConstructor(NewTarget, "%PromisePrototype%", «[[PromiseState]], [[PromiseResult]], [[PromiseFulfillReactions]], [[PromiseRejectReactions]]» ).
4. ReturnIfAbrupt(promise).
5. Set promise's [[PromiseState]] internal slot to "pending".
6. Set promise's [[PromiseFulfillReactions]] internal slot to a new empty List.
7. Set promise's [[PromiseRejectReactions]] internal slot to a new empty List.'
8. Let resolvingFunctions be CreateResolvingFunctions(promise).
9. Let completion be Call(executor, undefined, «resolvingFunctions.[[Resolve]], resolvingFunctions.[[Reject]]»).
10. If completion is an abrupt completion, then
a. Let status be Call(resolvingFunctions.[[Reject]], undefined, «completion.[[value]]»).
b. ReturnIfAbrupt(status).
11. Return promise.
(Цитата из спецификации ECMA
http://www.ecma-international.org/ec...omise-executor)
Эта цитата навеяла меня на то, что если resolvingFunctions в 9 пункте используются в функций, к которой есть доступ, то можно переписать конструктор "промиса"
(function(root, nativePromise) {
function Promise(executor) {
var resolvingFunctions;
var promise = new nativePromise(function(resolve, reject) {
resolvingFunctions = { resolve, reject };
executor.call(undefined, resolve, reject);
});
promise.resolve = resolvingFunctions.resolve;
promise.reject = resolvingFunctions.reject;
return promise;
}
// это потребовалось, поскольку переопределён конструктор
// и следовательно статичные методы улетели, возвращаем на место
"race reject resolve".split(" ").forEach(function(method) {
Promise[method] = nativePromise[method];
});
// теперь Promise.resolve() instanceof Promise === false
// поскольку nativePromise !== Promise, исправляем
Object.defineProperty(Promise, Symbol.hasInstance, {
value: function(instance) {
return instance instanceof nativePromise;
}
})
Promise.prototype.constructor = Promise;
root.Promise = Promise;
})(this, Promise);
Можно сказать проблема решена, если кто более гениально не придумает!
Впринципе теперь можно легко создать промис, который может передумать!
var promise = new Promise(function(resolve) {
setTimeout(resolve, 2500);
});
promise.then(function() {
alert("Свершилось!");
});
// Если вызвать эту функцию раньше чем выполнится "промис",
// то он никогда не выполнится
function nowIThinkAnotherWay() {
promise.reject();
}
Рабочии пример
http://codepen.io/Malleys/pen/VmqdeN?editors=0010