JS Promise - instantly retrieve some data from a function that returns a Promise

前端 未结 6 1169
生来不讨喜
生来不讨喜 2021-01-04 20:07

Can anyone recommend a pattern for instantly retrieving data from a function that returns a Promise?

My (simplified) example is an AJAX preloader:

lo         


        
6条回答
  •  离开以前
    2021-01-04 20:41

    Promises are beautiful. I don't think there is any reason that you can not handle this with promises. There are three ways that i can think of.

    1. The simplest way to handle this is within the executer. If you would like to cancel the promise (like for instance because of timeout) you just define a timeout flag in the executer and turn it on with a setTimeout(_ => timeout = true, 5000) instruction and resolve or reject only if timeout is false. ie (!timeout && resolve(res) or !timeout && reject(err)) This way your promise indefinitely remains unresolved in case of a timeout and your onfulfillment and onreject functions at the then stage never gets called.
    2. The second is very similar to the first but instead of keeping a flag you just invoke reject at the timeout with proper error description. And handle the rest at the then or catch stage.
    3. However if you would like to carry the id of your asych operation to the sync world then you can also do it as follows;

    In this case you have to promisify the async function yourself. Lets take an example. We have an async function to return the double of a number. This is the function

    function doubleAsync(data,cb){
      setTimeout(_ => cb(false, data*2),1000);
    }
    

    We would like to use promises. So normally we need a promisifier function which will take our async function and return another function which when run, takes our data and returns a promise. Right..? So here is the promisifier function;

    function promisify(fun){
      return (data) => new Promise((resolve,reject) => fun(data, (err,res) => err ? reject(err) : resolve(res)));
    }
    

    Lets se how they work together;

    function promisify(fun){
      return (data) => new Promise((resolve,reject) => fun(data, (err,res) => err ? reject(err) : resolve(res)));
    }
    
    function doubleAsync(data,cb){
      setTimeout(_ => cb(false, data*2),1000);
    }
    
    var doubleWithPromise = promisify(doubleAsync);
    doubleWithPromise(100).then(v => console.log("The asynchronously obtained result is: " + v));

    So now you see our doubleWithPromise(data) function returns a promise and we chain a then stage to it and access the returned value.

    But what you need is not only a promise but also the id of your asynch function. This is very simple. Your promisified function should return an object with two properties; a promise and an id. Lets see...

    This time our async function will return a result randomly in 0-5 secs. We will obtain it's result.id synchronously along with the result.promise and use this id to cancel the promise if it fails to resolve within 2.5 secs. Any figure on console log Resolves in 2501 msecs or above will result nothing to happen and the promise is practically canceled.

    function promisify(fun){
      return function(data){
               var result = {id:null, promise:null};       // template return object
               result.promise = new Promise((resolve,reject) => result.id = fun(data, (err,res) => err ? reject(err) : resolve(res)));
               return result;
             };
    }
    
    function doubleAsync(data,cb){
      var dur = ~~(Math.random()*5000);                    // return the double of the data within 0-5 seconds.
      console.log("Resolve in " + dur + " msecs");
      return setTimeout(_ => cb(false, data*2),dur);
    }
    
    var doubleWithPromise = promisify(doubleAsync),
           promiseDataSet = doubleWithPromise(100);
    
    setTimeout(_ => clearTimeout(promiseDataSet.id),2500); // give 2.5 seconds to the promise to resolve or cancel it.
    promiseDataSet.promise
                  .then(v => console.log("The asynchronously obtained result is: " + v));

提交回复
热议问题