1. 程式人生 > 實用技巧 >從外部改變promise內部狀態

從外部改變promise內部狀態

promise是什麼?

1、主要用於非同步計算
2、可以將非同步操作佇列化,按照期望的順序執行,返回符合預期的結果
3、可以在物件之間傳遞和操作promise,幫助我們處理佇列

為什麼會有promise?

為了避免介面凍結(任務)

  • 同步:假設你去了一家飯店,找個位置,叫來服務員,這個時候服務員對你說,對不起我是“同步”服務員,我要服務完這張桌子才能招呼你。那桌客人明明已經吃上了,你只是想要個選單,這麼小的動作,服務員卻要你等到別人的一個大動作完成之後,才能再來招呼你,這個便是同步的問題:也就是“順序交付的工作1234,必須按照1234的順序完成”。

  • 非同步:則是將耗時很長的A交付的工作交給系統之後,就去繼續做B交付的工作,。等到系統完成了前面的工作之後,再通過回撥或者事件,繼續做A剩下的工作。
    AB工作的完成順序,和交付他們的時間順序無關,所以叫“非同步”。

而官方文件則表示

Promise 物件的狀態不受外界影響。Promise 物件代表一個非同步操作,有三種狀態:Pending(進行中)、Resolved(已完成,又稱 Fulfilled)和 Rejected(已失敗)。只有非同步操作的結果,可以決定當前是哪一種狀態,任何其他操作都無法改變這個狀態。這也是 Promise 這個名字的由來,它的英語意思就是「承諾」,表示其他手段無法改變。

但是經過實際測試從外部控制promise狀態的事其實是可以辦到的:

1、Promise的狀態取決於promise主體中是否呼叫了resolved或者reject或者在呼叫resolved和reject前就發生異常(將會直接進入 reject狀態)

2、Promise也是js物件(雖然它實際是個函式)、逃不開按地址引用帶來的副作用,呼叫reject,但是沒有設定fn的reject,或者catch,故會報錯。Promise允許不設定resolved方法(即如果直接呼叫obj.ok()是沒問題的,不會報錯,promise狀態也會變為resolved)、但如果出現異常或者主動呼叫進入reject而沒有設定reject方法 或catch方法,則會報錯。

具體實現程式碼demo

  let obj = {} // 用於儲存promise裡的resolve和reject方法
  let a = function(){
    let p = new Promise(function(resolve,reject){
      obj.ok = resolve;
      obj.cancel = reject;
    });
    return p;
  }
  async function test () { // 使用async/await測試效果
    console.log('test開始')
    let c = await a();
    console.log(c)
    console.log('test結束');
  }
  test()
  setTimeout(function(){
    obj.ok('哈哈哈哈哈')
  },2000)

結果為

試驗證明在promise外部通過地址引用的方式進行改變promise內部狀態是可以實現的。

思路來源於

https://segmentfault.com/u/joey_5a961933efd3e

這位老哥在

https://segmentfault.com/q/1010000011145129

這篇博文裡的評論。