Ability to abort asynchronous call

后端 未结 3 1632
天命终不由人
天命终不由人 2020-12-31 08:24

I\'m using babeljs with es7 style async/await methods. I have a main script that will call a async method on an array of objects that all return promises. I use Promise.al

相关标签:
3条回答
  • 2020-12-31 08:53

    Native ES6 promises currently do not support cancellation directly. There are talks about it all the time in many places but it's not there yet.

    Since native promises don't support it and async/await works on promises, there is currently no built in easy way to abort it. One common approach is to use a token when creating the action returning a promise.

    Let's say you've promisified XHR GET:

    // simplification
    function ajax(url){
        return new Promise((resolve, reject) => {
            let xhr = new XMLHttpRequest;
            xhr.open("GET", url);
            xhr.onload = () => resolve(xhr.responseText);
            xhr.onerror = reject;
            xhr.send();
        });
    }
    

    Now you want to use it:

    async function foo(){
        let result = await ajax("/myApi");
        let result2 = await ajax("/myApi2?token=" + result);
    }
    

    Now, let's say we want to cancel the AJAX in some cases, we can pass a token as such:

    function ajax(url, token = {}){
        return new Promise((resolve, reject) => {
            let xhr = new XMLHttpRequest;
            xhr.open("GET", url);
            Object(token).cancel = () => { xhr.abort(), reject(); };
            xhr.onload = () => resolve(xhr.responseText);
            xhr.onerror = reject;
            xhr.send();
        });
    }
    

    This would let you do:

    async function foo(){
        let token = {};
        let req = ajax("/myApi", token); // note no await
        // now let's say we want to abort the request since we don't 
        // need the data
        token.cancel(); // this will abort the token
    }
    

    This approach needs work to work with chaining, luckily with ES6 syntax this is not as big of a deal. Good luck and happy coding.

    0 讨论(0)
  • 2020-12-31 09:04

    If you can migrate to Typescript (in which types are optional and es6 and some es7 features are supported out of the box) instead of Babel and use Bluebird promises, the kind of cancellation semantics you are looking for can be achieved.

    I've created a simple module which replaces the default Typescript __awaiter helper with one that supports Bluebird cancellations: https://www.npmjs.com/package/cancelable-awaiter

    With it you can use aync/await syntax in conjunction with promise.cancel() and promise.finally() which Bluebird gives you.

    0 讨论(0)
  • 2020-12-31 09:04

    This really depends on the API you need to use. Most of the current async API methods of node aren't easily "interruptible" (readfileasync and the likes), unless you yourself do your own implementation of them.

    There is no easy way to easily cancel a scheduled dispatch. The API so far is not built with this thing in mind. Promises also can't help when low level implementations of API don't support aborting.

    But in some API's you get to intercept process "steps", such as streams on data events and the "next tick" implementations. There you can abort the further processing. (Streams are actually pretty good candidate for implementing intercept-able IO stuff)

    The classic node example, where a fibonacci sequence calculation of input "n" is served per request, the logic is implemented via "next tick". There you can actually set a timeout on the calculation and server automatically kicks long running requests:

    var do_fibonacci_async = function(a,limiter,callback){
        if(limiter.halt){
            callback(limiter.msg);
        }
        else if(a <= 2){
            callback(limiter.halt ? limiter.msg : 1);
        }else{
            process.nextTick(function(){
                do_fibonacci_async(a - 1,limiter, function(val1){
                    do_fibonacci_async(a - 2,limiter, function(val2){
                        callback(limiter.halt ? limiter.msg : val1+val2);
                    });
                });
            });
        }
    }
    
    exports.fibonacci_async = function(a,callback){
                if(!a || isNaN(a)){
            callback(new out("fibonacci", [], ""));
            return;
        }
    
        var limiter = {halt:false, msg:"Too large to compute"};
        setTimeout(function(){
            limiter.halt = true;
        },5000);
    
        do_fibonacci_async(a,limiter,function(val){
            callback(new out("fibonacci", [a], val));
        });
    }
    
    0 讨论(0)
提交回复
热议问题