promise 是可取消的,但是怎么取消呢?


一個正在執行中的promise怎樣被取消?

其實就像一個執行中的ajax要被取消一樣,ajaxabort()進行取消,而且fetch api 也有了相關的規范-【AbortController】。

fetch 怎樣取消?

先來看下如何取消一個fetch請求

const url = "https://bigerfe.com/api/xxxx"
let controller;
let signal;
 
function requestA(){
 if (controller !== undefined) {
        controller.abort(); //終止請求
    }
 
    if ("AbortController" in window) {
        controller = new AbortController;
        signal = controller.signal;
    }
 
    fetch(url, {signal})
        .then((response) => {
            //do xxx
            updateAutocomplete()
        })
        .catch((error) => {
            //do xxx
            handleError(error);
        })
    });
}

怎樣實現實現promise的取消?

方案1 - 借助reject 方法

我們都知道一個promise對象狀態的改變是通過resolvereject來執行的。那是不是可以借助reject方法來模擬呢?

上代碼

//返回一個promise和abort方法
function getPromise() {
  let _res, _rej;
  
  const promise = new Promise((resolve, reject) => {
    _res = resolve;
    _rej = reject;
    setTimeout(() => {
      resolve('123')
    }, 5000);
  });
  return {
    promise,
    abort: () => {
      _rej({
        name: "abort",
        message: "the promise is aborted",
        aborted: true,
      });
    }
  };
}
 
const { promise, abort } = getPromise();
promise.then(console.log).catch(e => {
  console.log(e);
});
 
abort();

上面的方法可以正常執行,但是不夠通用,可以將Promise構造函數內的邏輯提取出來,作為一個回調傳進去。

改造一下

function getPromise(cb) {
  let _res, _rej;
  
  const promise = new Promise((res, rej) => {
    _res = res;
    _rej = rej;
    cb && cb(res,rej);
  });
  return {
    promise,
    abort: () => {
      _rej({
        name: "abort",
        message: "the promise is aborted",
        aborted: true,
      });
    }
  };
}
 
//主邏輯提取出來
function runCb(resolve,reject){
    setTimeout(()=>{
        resolve('1111')
    },3000)
}
 
const { promise, abort } = getPromise(runCb);
promise.then(console.log).catch(e => {
  console.log(e);
});

方案2 - 借助 Promise.race() 方法

相信大家都知道race方法的作用,這里還是簡單介紹下。

當有若干個promise, p1, p2, p3…在調用, let p = Promise.race([p1, p2, p3,…])的時候,返回的p也是一個promise。那么p什么時候會被resolve或者被reject呢?

看race我們知道它是競速或賽跑的意思,所以p1, p2, p3 … 最先一個被resolve或者被reject的結果就是p的resolve或者reject的結果。所以后續的promise的resolve和reject都不會再被執行了。

代碼很簡單,其實夠短小精悍。

//傳入一個正在執行的promise
function getPromiseWithAbort(p){
    let obj = {};
    //內部定一個新的promise,用來終止執行
    let p1 = new Promise(function(resolve, reject){
        obj.abort = reject;
    });
    obj.promise = Promise.race([p, p1]);
    return obj;
}

調用

var promise  = new Promise((resolve)=>{
 setTimeout(()=>{
  resolve('123')
 },3000)
})
 
var obj = getPromiseWithAbort(promise)
 
obj.promise.then(res=>{console.log(res)})
 
//如果要取消
obj.abort('取消執行')

控制面板輸出

error 取消執行

借助race方法明顯的更簡潔,更易用。

最后

其實取消promise執行和取消請求是一樣的,並不是真的終止了代碼的執行,而是對結果不再處理。另外fetch api雖然增加了新的標准實現,但仍然存在兼容問題,而且只能在瀏覽器中使用。那么非瀏覽器的環境中呢?比如RN?所以如果想要達到一種通用的方式,那么本文的取消promise的方式應該是個不錯的方式。

目前知名的axios庫也有abort能力,回頭看下它的實現方式,也歡迎小伙伴們留言討論。

---end,希望對你有用。

————————————————

原文鏈接:https://blog.csdn.net/zz_jesse/article/details/113154610


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM