深入理解ES6 011【學習筆記】

Promise 與非同步程式設計

因為執行引擎是單執行緒的,所以需要追蹤即將執行的程式碼,那些程式碼被放在一個任務佇列中,每當一段程式碼準備執行時,都會被新增到任務佇列中,每當引擎中的一段程式碼結束執行,事件迴圈會執行佇列中的下一個任務。

Promise相當於非同步操作結果佔位符,它不會去訂閱一個事件,也不會傳遞一個回呼函式給目標函式,而是讓函式回傳一個 Promise,就像這樣

// readFile 承諾在未來的某個時刻完成
let promise = readFile('txx.txt')

Promise 的生命週期

  • pending
  • fulfilled 成功
  • rejected 程式錯誤或其他原因

[[PromiseState]]內部屬性被用來表示 Promise 的三種狀態,這個屬性不暴露於 Promise 物件上,所以不能以程式設計的方式偵測 Promise 的狀態,只有當 Promise 狀態改變時,透過 then() 方法來採取特定的行為。所以 Promise 都有 then 方法,它接受兩個參數,fulfilled 和 rejected 時的兩個回呼函式

如果一個物件實作了上述的 then 方法,那這個物件我們就稱之為 thenable 物件,所有的 Promise 物件都是 thenable 物件,但並非所有 thenable 物件都是 Promise。

let promise = readFile("example.txt");
promise.then(function(contents){
  // 完成
},function(err){
  // 拒絕
})
promise.then(function(contents){
  // 完成
})

promise.then(null,function(err){
  // 拒絕
})
// catch等同於上面這種
promise.catch(function(err){
  // 拒絕
})

如果向 Promise.resolve() 方法或 Promise.reject() 方法傳入一個 Promise,那麼這個 Promise 會被直接回傳

Node.js 環境的拒絕處理

  • unhandledRejection
  • rejectionHandled
let rejected;
process.on("unhandledRejection",function(reason,promise){
  console.log(reason.message); // "Explosin"
  console.log(rejected === promise); // "Explosin"
})
rejected = Promise.reject(new Error('Explosin'))

串聯 Promise 及鏈式回傳值

let p1 = new Promise(function(resolve,reject){
  resolve(42)
})
p1.then(function(value){
  console.log(value)
  return value+1;
})
.then(function(value){
  console.log(value); // "43"
})

let p1 = new Promise(function(resolve,reject){
  reject(42)
})
p1.catch(function(value){
  console.log(value) // 42
  return value+1;
})
.then(function(value){
  console.log(value); // "43"
})

在 Promise 鏈回傳 Promise

Promise.all()

只接受一個參數並回傳一個 Promise,該參數是一個含有多個受監測 Promise 的可迭代物件,只有當可迭代物件中所有 Promise 都被解決後,回傳的 Promise 才會被解決,只有當可迭代物件中所有 Promise 都完成後,回傳的 Promise 才會被完成。只要有一個 reject,就不用等所有的都完成就會被 reject。

let p1 = new Promise(function(resolve,reject){
  resolve(42)
})
let p2 = new Promise(function(resolve,reject){
  reject(43)
})
let p3 = new Promise(function(resolve,reject){
  resolve(44)
})
let p4 =  Promise.all([p1,p2,p3])
p4.catch(function(value){
  console.log(Array.isArray(value)); //false
  console.log(value); // 43
})

Promise.race()

只要有一個 resolve,不用等所有的都被完成。一旦陣列中的某個 Promise 被完成,Promise.race() 方法也會像 Promise.all() 方法一樣回傳一個特定的 Promise

Promise 繼承

class MyPromise extends Promise {
  // 使用預設的建構函式

  success(resolove,reject){
    return this.then(resolove,reject)
  }
  failure(reject){
    return this.catch(reject)
  }
}
let promise = new MyPromise(function(resolve,reject){
  resolve(42)
})
promise.success(function(value){
  console.log(value) // 42
})
.failure(function(value){
  console.log(value)
})

基於 Promise 的非同步任務執行

改造之前的文件讀取功能。只要每個非同步操作都回傳 Promise,就可以極大地簡化並能實用化這個過程。以 Promise 作為通用介面用於所有非同步程式碼可以簡化任務執行器。

let fs = require("fs");

function run(taskDef){
  // 建立迭代器
  let task = taskDef()

  // 開始執行任務
  let result = task.next();

  // 遞迴函式遍歷
  (function step(){
    // 如果有更多任務要做
    if(!result.done){
      // 用一個 Promise 來解決會簡化問題
      let promise = Promise.resolove(result.value);
      promise.then(function(value){
        result = task.next(value);
        step()
      })
      .catch(function(error){
        result = task.throw(error);
        step();
      })
    }

  }())
}
// 定義一個可用於任務執行器的函式
function readFile(filename){
  return new Promise(function(resolove,reject){
    fs.readFile(filename,function(err,contents){
      if(err){
        reject(err);
      } else {
        resolove(contents)
      }
    })
  })
}

// 執行一個任務
run(function *(){
  let contents = yield readFile("config.json");
  doSomethingWith(contents);
  console.log("Done")
})

主題測試文章,只做測試使用。發佈者:Walker,轉轉請注明出處:https://www.walker-learn.xyz/archives/4337

(0)
Walker的頭像Walker
上一篇 2025年3月8日 13:04
下一篇 2025年3月8日 12:52

相關推薦

  • 無畏前行,拳釋力量 🥊💪

    拚搏,是一種態度。生活就像一場比賽,沒有捷徑可走,只有不斷訓練、突破、超越,才能站上屬於自己的舞台。這不僅是一種對抗,更是一種自我的覺醒——敢於迎戰,敢於挑戰,敢於成為更強的自己。 運動中的拚搏精神 無論是拳擊、跑步,還是力量訓練,每一次出拳、每一次揮汗、每一次咬牙堅持,都是對身體與心靈的磨練。拚搏不是單純的對抗,而是一種態度——面對挑戰,不退縮;面對失敗,…

    個人 2025年2月26日
    1.4K00
  • Go 工程師體系課 013【學習筆記】

    訂單事務 先扣庫存 後扣庫存 都會對庫存和訂單都會有影響,所以要使用分散式事務 業務(下單不對付)業務問題 支付成功再扣減(下單了,支付時沒庫存了) 訂單扣減,不支付(訂單超時歸還)【常用方式】 事務和分散式事務 1. 什麼是事務? 事務(Transaction)是資料庫管理系統中的一個重要概念,它是一組資料庫操作的集合,這些操作要麼全部成功執行,要麼全部…

    個人 2025年11月25日
    30200
  • Go工程師體系課 017【學習筆記】

    限流、熔斷與降級入門(含 Sentinel 實戰) 結合課件第 3 章(3-1 ~ 3-9)的影片要點,整理一套面向初學者的服務保護指南,幫助理解「為什麼需要限流、熔斷和降級」,以及如何用 Sentinel 快速上手。 學習路線速覽 3-1 理解服務雪崩與限流、熔斷、降級的背景 3-2 Sentinel 與 Hystrix 對比,明確技術選型 3-3 Sen…

    個人 2025年11月25日
    25500
  • 深入理解ES6 013【學習筆記】

    用模組封裝程式碼 JavaScript 使用「共享一切」的方式載入程式碼,這是該語言中最容易出錯且令人感到困惑的地方。其他語言使用諸如套件(package)之類的概念來定義程式碼作用域。在 ES6 以前,在應用程式的每一個 JavaScript 檔案中定義的一切都共享一個全域作用域。隨著網頁應用程式變得更加複雜,JavaScript 程式碼的使用量也開始增長,這種做法會引起問題,例如命名衝突和安全性問題。ES6 的一個目標是解決作用域問題…

    個人 2025年3月8日
    1.2K00
  • Go工程師體系課 008【學習筆記】

    訂單及購物車 先從庫存服務中將 srv 的服務程式碼框架複製過來,搜尋取代對應的名稱(order_srv) 加密技術基礎 對稱式加密(Symmetric Encryption) 原理: 使用同一個金鑰進行加密和解密 就像一把鑰匙,既能鎖門也能開門 加密速度快,適合大量資料傳輸 使用情境: 本機檔案加密 資料庫內容加密 大量資料傳輸時的內容加密 內部系統間的快速通…

    個人 2025年11月25日
    27900
簡體中文 繁體中文 English