TL&DR: We are inventing cancellable promises here.
Well.. OK. Some infrastructure. This is a typical example where you really need Promise.cancel()
However we don't have it in ES6 native promises. Being a library agnostic person i just go ahead and invent one by Promise sub-classing.
The following function takes a promise and makes it cancellable by adding a non-enumerable and non-configurable property called __cancelled__
It also adds .then()
and .cancel()
methods to it's property chain without modifying the Promise.prototype
. Since cancellable promise object's proptotype's prototype is Promise.prototype
, our cancellable promise has access to all Promise thingies. Ah.. before i forget; cancellable prototype's then
method also returns a cancellable promise.
function makePromiseCancellable(p){
Object.defineProperty(p,"__cancelled__", { value: false,
writable: true,
enumerable: false,
configurable: false
});
Object.setPrototypeOf(p,makePromiseCancellable.prototype);
return p;
}
makePromiseCancellable.prototype = Object.create(Promise.prototype);
makePromiseCancellable.prototype.then = function(callback){
return makePromiseCancellable(Promise.prototype.then.call(this,function(v){
!this.__cancelled__ && callback(v);
}.bind(this)));
};
makePromiseCancellable.prototype.cancel = function(){
this.__cancelled__ = true;
return this;
};
So we have a utility function called getAsyncData()
which returns us a standard ES6 promise which resolves in 2000 msecs. We will obtain two promises from this function, and turn them into cancellable promises called cp0
and cp1
. Then we will cancel cp0
at 1000 msecs and see what happens.
function getAsyncData(){
var dur = 2000;
return new Promise((v,x) => setTimeout(v.bind(this,"promise id " + pid++ + " resolved at " + dur + " msec"),dur));
}
function makePromiseCancellable(p){
Object.defineProperty(p,"__cancelled__", { value: false,
writable: true,
enumerable: false,
configurable: false
});
Object.setPrototypeOf(p,makePromiseCancellable.prototype);
return p;
}
makePromiseCancellable.prototype = Object.create(Promise.prototype);
makePromiseCancellable.prototype.then = function(callback){
return makePromiseCancellable(Promise.prototype.then.call(this,function(v){
!this.__cancelled__ && callback(v);
}.bind(this)));
};
makePromiseCancellable.prototype.cancel = function(){
this.__cancelled__ = true;
};
var pid = 0,
cp0 = makePromiseCancellable(getAsyncData());
cp1 = makePromiseCancellable(getAsyncData());
cp0.then(v => console.log(v));
cp1.then(v => console.log(v));
setTimeout(_ => cp0.cancel(),1000);
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…