Bluebird NPM: Bluebird JS Promise พร้อมตัวอย่าง

⚡ สรุปอย่างชาญฉลาด

Bluebird JS เป็นไลบรารี Promise ที่มีคุณสมบัติครบครันสำหรับ Javaสคริปต์ที่มีความสามารถหลักคือการแปลงโมดูล Node ที่ใช้ callback ให้เป็นโมดูลที่ส่งคืน promise ดังนั้นจึงสามารถใช้ไลบรารีทั้งหมดเช่นนี้ได้ MongoDB ไดรเวอร์สามารถใช้งานแบบอะซิงโครนัสได้

  • 🔵 ความสามารถหลัก: promisifyAll จะห่อหุ้มทุกเมธอดของโมดูล โดยเพิ่มคำต่อท้าย Async เพื่อบ่งบอกว่าเมธอดนั้นจะส่งคืน Promise แล้ว
  • 📦 การติดตั้ง: คำสั่ง `npm install bluebird` เพียงคำสั่งเดียวจะเพิ่มไลบรารี จากนั้นคำสั่ง `require` จะเปิดเผยอ็อบเจ็กต์ Promise ออกมา
  • 🔗 การผูกมัด: จากนั้นแต่ละส่วนจะได้รับค่าความละเอียดก่อนหน้า ซึ่งจะแทนที่การเรียกกลับแบบซ้อนกันด้วยลำดับขั้นตอนแบบเรียบง่าย
  • 🏷️ กฎการตั้งชื่อ: เฉพาะเวอร์ชันที่มีคำต่อท้ายว่า Async เท่านั้นที่จะส่งคืน Promise ส่วนเมธอด callback ดั้งเดิมยังคงไม่เปลี่ยนแปลง
  • 🛡️ เส้นทางความล้มเหลว: การจับเพียงจุดเดียวที่ปลายสุดของห่วงโซ่ จะได้รับการปฏิเสธจากทุกขั้นตอนก่อนหน้า
  • 🇧🇷 บริบทสมัยใหม่: ปัจจุบัน ฟังก์ชัน native promises และ async await ครอบคลุมฟังก์ชันส่วนใหญ่ที่ Bluebird เคยมีให้ใช้งานเฉพาะในอดีตแล้ว

บลูเบิร์ด เจเอส โพรมีส

บลูเบิร์ด JS คืออะไร?

Bluebird JS เป็นไลบรารี Promise ที่มีคุณสมบัติครบครันสำหรับ JavaScript มีคุณสมบัติเด่นที่สุดคือ ช่วยให้คุณสามารถ "แปลง" โมดูล Node อื่นๆ ให้เป็น Promise เพื่อใช้งานแบบอะซิงโครนัสได้ Promiseify เป็นแนวคิดที่นำมาใช้กับฟังก์ชัน callback และรับประกันว่าทุกฟังก์ชัน callback ที่ถูกเรียกใช้จะส่งคืนค่า

ดังนั้นถ้าก Node.js โมดูลนี้มีฟังก์ชันเรียกกลับ (callback function) ที่ไม่ส่งค่ากลับ ซึ่งการใช้ Promise จะทำให้โมดูลนี้แก้ไขฟังก์ชันทั้งหมดในโมดูลโดยอัตโนมัติ เพื่อให้แต่ละฟังก์ชันส่งค่ากลับ

นั่นหมายความว่าคุณสามารถใช้ Bluebird ในการสร้างได้ MongoDB โมดูลทำงานแบบอะซิงโครนัส ซึ่งช่วยเพิ่มความสะดวกสบายอีกระดับเมื่อเขียนแอปพลิเคชัน Node.js

ตัวอย่างด้านล่างนี้ เริ่มต้นด้วยการสร้างการเชื่อมต่อกับคอลเลกชัน “Employee” ในฐานข้อมูล “EmployeeDB” เมื่อสร้างการเชื่อมต่อแล้ว ระบบจะดึงข้อมูลทั้งหมดในคอลเลกชันและแสดงผลในคอนโซล

วิธีสร้างสัญญาด้วย Bluebird JS Library

ต่อไปนี้เป็นตัวอย่างทีละขั้นตอนที่แสดงวิธีการสร้าง Promise โดยใช้ไลบรารี Bluebird JS

ขั้นตอนที่ 1) การติดตั้งโมดูล NPM

ในการใช้งาน Bluebird ภายในแอปพลิเคชัน Node.js จำเป็นต้องติดตั้งโมดูล Bluebird โดยใช้คำสั่งด้านล่าง:

npm install bluebird

ขั้นตอนที่ 2) รวมโมดูล Bluebird เข้าไปด้วย

ขั้นตอนต่อไปคือการรวมโมดูล Bluebird เข้ากับโค้ดของคุณและแปลงโค้ดทั้งหมดให้เป็น Promise MongoDB โมดูล การใช้ Promise ในที่นี้หมายความว่า Bluebird จะรับประกันว่าทุกเมธอดที่กำหนดไว้ในโมดูลนั้นเป็นไปตามเงื่อนไขที่กำหนด MongoDB ห้องสมุดคืนคำสัญญา

รวมโมดูล Bluebird

Code คำอธิบาย:

  1. การขอ require คำสั่งนี้รวมถึงไลบรารี Bluebird ด้วย
  2. บลูเบิร์ด .promisifyAll() เมธอดนี้จะสร้างเวอร์ชันแบบอะซิงโครนัสของทุกเมธอด MongoDB โมดูลแต่ละตัวจะทำงานในพื้นหลังและส่งคืนค่า Promise

ขั้นตอนที่ 3) เชื่อมต่อกับฐานข้อมูล

ขั้นตอนสุดท้ายคือการเชื่อมต่อกับฐานข้อมูล ดึงข้อมูลทั้งหมดในชุดข้อมูล และแสดงผลในคอนโซลล็อก

เชื่อมต่อกับฐานข้อมูล

Code คำอธิบาย:

  1. สังเกตเห็น connectAsync ใช้วิธีนี้แทนวิธีปกติ connect วิธีการ Bluebird เพิ่มต่อท้าย อะซิงโครนัส คำต่อท้ายสำหรับแต่ละวิธีใน MongoDB ไลบรารีนี้ใช้แยกแยะการเรียกใช้ฟังก์ชันที่ส่งคืน Promise ออกจากการเรียกใช้ฟังก์ชันที่ไม่ส่งคืน Promise เมธอดที่ไม่มีคำต่อท้าย Async จะไม่รับประกันเช่นนั้น
  2. คล้ายกับ connectAsyncที่ findAsync เมธอดนี้จะส่งคืนเรคอร์ดทั้งหมดใน MongoDB คอลเลกชัน “พนักงาน”
  3. If findAsync เมื่อแก้ไขปัญหาสำเร็จแล้ว บล็อกต่อไปนี้จะวนลูปผ่านแต่ละเรคอร์ดในคอลเลกชันและแสดงผลในคอนโซลล็อก

หากดำเนินการตามขั้นตอนข้างต้นอย่างถูกต้อง เอกสารทั้งหมดในคอลเลกชันพนักงานจะปรากฏในคอนโซล ดังที่แสดงในผลลัพธ์ด้านล่าง

บลูเบิร์ดให้สัญญาเรื่องผลผลิต

นี่คือโค้ดฉบับสมบูรณ์สำหรับการอ้างอิง:

var Promise = require('bluebird');

// promisifyAll adds an Async variant of every MongoDB method
var mongoClient = Promise.promisifyAll(require('mongodb')).MongoClient;

mongoClient.connectAsync('mongodb://localhost/EmployeeDB')

    .then(function(db) {
        return db.collection('Employee').findAsync({});
    })
    .then(function(cursor) {
        cursor.each(function(err, doc) {
            console.log(doc);
        });
    });

⚠️ หมายเหตุเกี่ยวกับเวอร์ชันไดรเวอร์: โค้ดด้านบนมีเป้าหมายที่ MongoDB ไดรเวอร์ Node เวอร์ชัน 2.x ซึ่ง connect แก้ไขด้วยอ็อบเจ็กต์ฐานข้อมูล จากไดรเวอร์ 3.0 เป็นต้นไป มันแก้ไขด้วย MongoClientดังนั้นห่วงโซ่จึงต้องเรียก client.db('EmployeeDB').collection('Employee') แทน db.collection('Employee')ไดรเวอร์เวอร์ชันใหม่ๆ ยังส่งคืนค่า Promise ดั้งเดิมอยู่แล้ว ซึ่งทำให้ promisifyAll ไม่จำเป็นสำหรับ MongoDB เฉพาะ

Bluebird กับ Native Promises: ควรใช้ตัวไหนดีกว่ากัน

เมื่อ Bluebird ถูกเขียนขึ้นครั้งแรก Node.js ยังไม่มีการรองรับ Promise เลย ดังนั้นไลบรารีนี้จึงเข้ามาเติมเต็มช่องว่างที่แท้จริงในแพลตฟอร์ม Node.js ได้เพิ่มการรองรับ Promise แบบเนทีฟตั้งแต่เวอร์ชัน 4 แล้ว async/await ตั้งแต่เวอร์ชัน 7.6 เป็นต้นมา ซึ่งได้เปลี่ยนแปลงวิธีการคำนวณอย่างมากสำหรับทุกคนที่เริ่มต้นโครงการในปัจจุบัน

แง่มุม นกชนิดหนึ่ง คำสัญญาของชนพื้นเมือง
การอยู่ที่ แพ็กเกจ npm สำหรับติดตั้งและบำรุงรักษา สร้างขึ้นในระหว่างการทำงาน
การเรียกกลับที่มีแนวโน้มที่ดี promisifyAll() แปลงโมดูลทั้งหมด util.promisify() แปลงฟังก์ชันหนึ่ง
ผู้ช่วยพิเศษ แผนที่, ตัวกรอง, คุณสมบัติ, แต่ละรายการ, หมดเวลา, การยกเลิก ทั้งหมด, ตกลงกัน, ใดๆ, เฉพาะเชื้อชาติ
กองยาว traces ใช่ เมื่อเปิดใช้งานแล้ว ปรับปรุงแล้วแต่สั้นลง
เหมาะสำหรับ ไลบรารีเรียกกลับแบบดั้งเดิม ตัวช่วยในการทำงานพร้อมกัน โค้ดใหม่ และทุกอย่างที่ใช้ async await

เลือกใช้ native promises สำหรับงานใหม่ เนื่องจากไม่จำเป็นต้องพึ่งพาไลบรารีใดๆ และสามารถทำงานร่วมกับ async await ได้โดยตรง ส่วน Bluebird นั้น หากไลบรารีนั้นยังคงแสดงเฉพาะ callback หรือเมื่อใช้ตัวช่วยในการจัดการการทำงานพร้อมกัน เช่น... Promise.map ด้วยการจำกัดการทำงานพร้อมกัน จะช่วยลดปริมาณโค้ดได้อย่างมาก

วิธีจัดการข้อผิดพลาดด้วย Bluebird Promises

ตัวอย่างข้างต้นไม่มีเส้นทางที่จะเกิดข้อผิดพลาด หาก MongoDB หากกระบวนการไม่ทำงาน หรือชื่อคอลเลกชันไม่ถูกต้อง เชนจะปฏิเสธและไม่มีอะไรแสดงออกมา — กระบวนการจะหยุดทำงานโดยไม่มีคำอธิบายใดๆ เชนของ Promise ทุกตัวจำเป็นต้องมีตัวจัดการการสิ้นสุด (terminal handler)

บลูเบิร์ดสนับสนุน .catch() สำหรับการปฏิเสธและ .finally() สำหรับกระบวนการล้างข้อมูลที่ต้องดำเนินการไม่ว่าในกรณีใดก็ตาม นอกจากนี้ยังรองรับการดักจับแบบระบุประเภท ซึ่งจะจัดการข้อผิดพลาดประเภทหนึ่งในขณะที่ปล่อยให้ข้อผิดพลาดประเภทอื่นแพร่กระจายต่อไป

var Promise = require('bluebird');
var mongoClient = Promise.promisifyAll(require('mongodb')).MongoClient;

var connection;

mongoClient.connectAsync('mongodb://localhost/EmployeeDB')
    .then(function(db) {
        connection = db;
        return db.collection('Employee').findAsync({});
    })
    .then(function(cursor) {
        return cursor.toArrayAsync();
    })
    .then(function(docs) {
        docs.forEach(function(doc) { console.log(doc); });
    })
    .catch(Promise.TimeoutError, function(err) {
        console.error('The database did not respond in time.');
    })
    .catch(function(err) {
        // Any other rejection from any step above arrives here
        console.error('Query failed:', err.message);
    })
    .finally(function() {
        // Runs on success and on failure, so the socket always closes
        if (connection) { connection.close(); }
    });

มีนิสัยสำคัญสามอย่างที่นี่ อย่างแรกคือ การจัดสถานที่ .catch() ในตอนท้ายแทนที่จะเป็นหลังจากแต่ละขั้นตอน เพราะตัวจัดการปลายทางหนึ่งตัวจะได้รับการปฏิเสธจากทุกลิงก์ก่อนหน้าในห่วงโซ่ ประการที่สอง ให้ใช้ .finally() สำหรับการปล่อยทรัพยากร เช่น การเชื่อมต่อฐานข้อมูล เนื่องจากทำงานทั้งในกรณีที่สำเร็จและล้มเหลว ประการที่สาม อย่าปล่อยให้ห่วงโซ่ไม่มีตัวดักจับ: การปฏิเสธที่ไม่ได้จัดการจะทำให้กระบวนการ Node ยุติลงในเวอร์ชันปัจจุบัน และ Bluebird จะพิมพ์คำเตือนอย่างชัดเจนเกี่ยวกับเรื่องนี้ล่วงหน้า การเปิดใช้งานสแต็กแบบยาว tracระหว่างการพัฒนาด้วย Promise.config({ longStackTraces: true }) ทำให้การระบุที่มาของการปฏิเสธทำได้ง่ายขึ้นมาก

ข้อผิดพลาดและวิธีแก้ไขทั่วไปของ Bluebird Promisify

ปัญหาส่วนใหญ่ของ Bluebird เกิดจากรูปแบบการตั้งชื่อที่ใช้ Promise หรือจากการผสมผสานการเรียก Callback และ Promise ในลำดับเดียวกัน มากกว่าความผิดพลาดใดๆ ในตัวไลบรารีเอง อาการแต่ละอย่างด้านล่างจะระบุสาเหตุและวิธีแก้ไข

  • “connectAsync ไม่ใช่ฟังก์ชัน”: จำเป็นต้องใช้โมดูลโดยตรงแทนที่จะผ่านทาง promisifyAll()ดังนั้นจึงไม่มีเวอร์ชันแบบอะซิงโครนัส ให้ห่อการเรียกใช้ require ตามที่แสดงด้านบน
  • เรียกใช้เมธอดแบบธรรมดาแล้วได้ค่า undefined: connect() ยังคงคาดหวังการเรียกกลับ (callback) อยู่ เฉพาะเวอร์ชันที่มีคำต่อท้ายว่า Async เท่านั้นที่จะส่งคืน Promise
  • การส่งฟังก์ชัน callback ไปยังเมธอดแบบอะซิงโครนัส: อย่าส่งการโทรกลับหรือ await และคำสัญญาจะได้รับการแก้ไขโดยไม่มีใครสังเกตเห็น ควรใช้รูปแบบเดียวต่อการเรียกใช้งาน ไม่ควรใช้ทั้งสองรูปแบบ
  • ใช้คำสั่ง promisifyAll กับไลบรารีที่ใช้ Promise อยู่แล้ว: ไม่เป็นอันตรายแต่ไร้ประโยชน์ และทำให้เกิดชื่อที่มีคำต่อท้ายซ้ำซ้อนซึ่งทำให้สับสน ตรวจสอบเอกสารประกอบของไลบรารีก่อน
  • แก้ไขข้อผิดพลาดโดยไม่แจ้งให้ทราบ: โซ่ที่ไม่มี .catch() ซ่อนเหตุผลการปฏิเสธจนกว่า Node จะรายงานการปฏิเสธที่ไม่ได้จัดการและออกจากโปรแกรม ควรปิดการทำงานด้วย catch เสมอ แม้แต่ในสคริปต์สั้นๆ ก็ตาม

คำถามที่พบบ่อย

promisifyAll จะเพิ่มสำเนาของแต่ละเมธอดแทนที่จะแทนที่เมธอดเดิม ดังนั้นเวอร์ชัน callback เดิมจึงยังคงใช้งานได้ คำต่อท้าย Async จะบ่งบอกถึงสำเนาที่ส่งคืน promise สามารถกำหนดค่าคำต่อท้ายนี้ได้ผ่านตัวเลือก promisifier

ใช่แล้ว ผลิตภัณฑ์ของ Bluebird เป็นไปตามมาตรฐาน Promises/A+ ดังนั้น await รองรับโมดูลเหล่านั้นเหมือนกับโมดูลดั้งเดิมทุกประการ วิธีนี้ช่วยให้คุณแปลงโมดูลเก่าให้เป็น Promise แล้วใช้งานด้วยไวยากรณ์สมัยใหม่ได้

ใช่. AI ผู้ช่วยจะเขียนฟังก์ชันเรียกกลับแบบซ้อนกันใหม่ให้เป็นสายโซ่ของ Promise หรือ async await อย่างน่าเชื่อถือ ตรวจสอบการจัดการข้อผิดพลาดในภายหลัง เนื่องจากการแปลงที่สร้างขึ้นมักจะละเว้นส่วน catch ในตอนท้าย

เครื่องมือ AI trace ซึ่งลิงก์ในห่วงโซ่นั้นขาดคำสั่งส่งคืนค่า ซึ่งเป็นสาเหตุปกติของการถูกปฏิเสธ escapingนอกจากนี้ พวกเขายังแจ้งเตือนถึงโค้ดส่วนที่ขาดการดักจับข้อผิดพลาดขั้นสุดท้าย ซึ่งเป็นสิ่งที่ทำให้ข้อผิดพลาดที่ได้รับการจัดการแล้วกลายเป็นการหยุดทำงานโดยไม่คาดคิด

Promise.all จะรอการทำงานของอาร์เรย์ของ Promise ที่มีอยู่แล้ว ในขณะที่ Promise.map ของ Bluebird จะสร้าง Promise เหล่านั้นจากค่าต่างๆ และยอมรับขีดจำกัดการทำงานพร้อมกัน ซึ่งจะป้องกันไม่ให้คำขอหลายพันรายการพร้อมกันทำให้ซ็อกเก็ตหมดลง

สรุปโพสต์นี้ด้วย: