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

前端 未结 6 1205
生来不讨喜
生来不讨喜 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:45

    You can kinda do this, but AFAIK it will require hacky workarounds. Note that exporting the resolve and reject methods is generally considered a promise anti-pattern (i.e. sign you shouldn't be using promises). See the bottom for something using setTimeout that may give you what you want without workarounds.

    let xhrRequest = (path, data, method, success, fail) => {
      const xhr = new XMLHttpRequest();
    
      // could alternately be structured as polymorphic fns, YMMV
      switch (method) {
        case 'GET':
          xhr.open('GET', path);
          xhr.onload = () => {
              if (xhr.status < 400 && xhr.status >= 200) {
                success(xhr.responseText);
                return null;
              } else {
                fail(new Error(`Server responded with a status of ${xhr.status}`));
                return null;
              }
            };
            xhr.onerror = () => {
              fail(networkError);
              return null;
            }
            xhr.send();
            return null;
          }
    
          return xhr;
    
        case 'POST':
          // etc.
          return xhr;
    
        // and so on...
    };
    
    // can work with any function that can take success and fail callbacks
    class CancellablePromise {
      constructor (fn, ...params) {
        this.promise = new Promise((res, rej) => {
          this.resolve = res;
          this.reject = rej;
          fn(...params, this.resolve, this.reject);
          return null;
        });
      }
    };
    
    let p = new CancellablePromise(xhrRequest, 'index.html', null, 'GET');
    
    p.promise.then(loadPage).catch(handleError);
    
    // times out after 2 seconds
    setTimeout(() => { p.reject(new Error('timeout')) }, 2000);
    
    // for an alternative version that simply tells the user when things 
    // are taking longer than expected, NOTE this can be done with vanilla 
    // promises:
    
    let timeoutHandle = setTimeout(() => {
      // don't use alert for real, but you get the idea
      alert('Sorry its taking so long to load the page.');
    }, 2000);
    
    p.promise.then(() => clearTimeout(timeoutHandle));
    

提交回复
热议问题