cari
Rumahhujung hadapan webtutorial jsCipta Janji anda sendiri dalam JavaScript

Create your own Promise in JavaScript

Kenapa?

Untuk mendapatkan idea bagaimana JavaScript Promises menjalankan panggilan balik secara tidak segerak di bawah hud.

Mari kita cipta Janji kita sendiri dalam JavaScript! Kami akan mengikut spesifikasi Promise/A, yang menggariskan cara janji mengendalikan operasi async, menyelesaikan, menolak dan memastikan pengendalian rantaian dan ralat yang boleh diramal.

Untuk memastikan perkara mudah, kami akan menumpukan pada peraturan utama yang ditandai dengan ✅ dalam spesifikasi Promises/A. Ini bukan pelaksanaan penuh, tetapi versi yang dipermudahkan. Inilah yang akan kami bina:

1. Terminologi

1.1 'janji' ialah objek atau fungsi dengan kaedah kemudian yang tingkah lakunya mematuhi spesifikasi ini.

1.2 thenable' ialah objek atau fungsi yang mentakrifkan kaedah kemudian.

1.3 'nilai' ialah mana-mana nilai JavaScript yang sah (termasuk tidak ditentukan, boleh kemudian atau janji).

1.4 'pengecualian' ialah nilai yang dilemparkan menggunakan pernyataan lontaran.

1.5 'sebab' ialah nilai yang menunjukkan sebab janji ditolak.

2. Keperluan

2.1 Negara Janji

Janji mestilah dalam salah satu daripada tiga keadaan: belum selesai, ditepati atau ditolak.

2.1.1. Apabila belum selesai, janji: ✅

⟶ boleh beralih kepada sama ada keadaan dipenuhi atau ditolak.

2.1.2. Apabila ditepati, janji: ✅

⟶ tidak boleh beralih ke mana-mana negeri lain.

⟶ mesti mempunyai nilai, yang tidak boleh berubah.

2.1.3. Apabila ditolak, janji: ✅

⟶ tidak boleh beralih ke mana-mana negeri lain.

⟶ mesti ada sebab, yang mesti tak berubah.

2.2 Kaedah kemudian

Janji mesti menyediakan kaedah kemudian untuk mengakses nilai atau sebab semasa atau akhirnya.

Kaedah janji menerima dua hujah:

promise.then(onFulfilled, onRejected);

2.2.1. Kedua-dua onFulfilled dan onRejected ialah hujah pilihan: ✅

⟶ Jika onFulfilled bukan fungsi, ia mesti diabaikan.

⟶ Jika onRejected bukan fungsi, ia mesti diabaikan.

2.2.2. Jika onFulfilled ialah fungsi: ✅

⟶ ia mesti dipanggil selepas janji dipenuhi, dengan nilai janji sebagai hujah pertamanya.

⟶ ia tidak boleh dipanggil sebelum janji ditepati.

⟶ ia tidak boleh dipanggil lebih daripada sekali.

2.2.3. Jika onRejected ialah fungsi, ✅

⟶ ia mesti dipanggil selepas janji ditolak, dengan alasan janji sebagai hujah pertamanya.

⟶ ia tidak boleh dipanggil sebelum janji ditolak.

⟶ ia tidak boleh dipanggil lebih daripada sekali.

2.2.4. onFulfilled atau onRejected tidak boleh dipanggil sehingga tindanan konteks pelaksanaan hanya mengandungi kod platform. ✅

2.2.5. onFulfilled dan onRejected mesti dipanggil sebagai fungsi (iaitu tanpa nilai ini). ✅

2.2.6. kemudian boleh dipanggil beberapa kali pada janji yang sama. ✅

⟶ Jika/apabila janji ditepati, semua panggilan balik onFulfilled masing-masing mesti dilaksanakan mengikut urutan panggilan asalnya pada masa itu.

⟶ Jika/apabila janji ditolak, semua panggilan balik onRejected masing-masing mesti dilaksanakan mengikut urutan panggilan asalnya pada masa itu.

2.2.7. maka mesti membalas janji. ✅

promise.then(onFulfilled, onRejected);

⟶ Jika sama ada onFulfilled atau onRejected mengembalikan nilai x, jalankan Prosedur Penyelesaian Janji [[Resolve]](promise2, x). ❌

⟶ Jika sama ada onFulfilled atau onRejected melemparkan pengecualian e, promise2 mesti ditolak dengan e sebagai alasan. ❌

⟶ Jika onFulfilled bukan fungsi dan promise1 dipenuhi, promise2 mesti ditunaikan dengan nilai yang sama seperti promise1. ❌

⟶ Jika onRejected bukan fungsi dan promise1 ditolak, promise2 mesti ditolak dengan alasan yang sama seperti promise1. ❌

Perlaksanaan

Janji JavaScript mengambil fungsi pelaksana sebagai hujah, yang dipanggil serta-merta apabila Janji dibuat:

promise2 = promise1.then(onFulfilled, onRejected);
new Promise(excecutor);

Spesifikasi teras Janji/A tidak berurusan dengan cara mencipta, memenuhi atau menolak janji. Terpulang kepada anda. Tetapi pelaksanaan yang anda sediakan untuk pembinaan janji harus serasi dengan API tak segerak dalam JavaScript. Berikut ialah draf pertama kelas Promise kami:

const promise = new Promise((resolve, reject) => {
    // Runs some async or sync tasks
});

Peraturan 2.1 (Negara Janji) menyatakan bahawa janji mesti berada dalam salah satu daripada tiga keadaan: belum selesai, dipenuhi atau ditolak. Ia juga menerangkan perkara yang berlaku di setiap negeri ini.

Apabila dipenuhi atau ditolak, janji tidak boleh beralih ke mana-mana negeri lain. Oleh itu, kita perlu memastikan janji berada dalam keadaan belum selesai sebelum membuat sebarang peralihan:

class YourPromise {
    constructor(executor) {
        this.state = 'pending';
        this.value = undefined;
        this.reason = undefined;

        const resolve = value => {
            if (this.state === 'pending') {
                this.state = 'fulfilled';
                this.value = value;
            }
        };

        const reject = reason => {
            if (this.state === 'pending') {
                this.state = 'rejected';
                this.reason = reason;
            }
        };

        try {
            executor(resolve, reject);  // The executor function being called immediately
        } catch (error) {
            reject(error);
        }
    }
}

Kami sudah mengetahui bahawa keadaan awal janji belum selesai, dan kami memastikan ia kekal sehingga dipenuhi atau ditolak secara jelas:

const resolve = value => {
    if (this.state === 'pending') {
        this.state = 'fulfilled';
        this.value = value;
    }
};

const reject = reason => {
    if (this.state === 'pending') {
        this.state = 'rejected';
        this.reason = reason;
    }
};

Memandangkan fungsi pelaksana dipanggil serta-merta selepas instantiasi janji, kami memanggilnya dalam kaedah pembina:

this.state = 'pending';

Draf pertama kelas YourPromise kami selesai di sini.

Spesifikasi Promise/A kebanyakannya tertumpu pada penentuan kaedah interoperable then() . Kaedah ini membolehkan kami mengakses nilai atau sebab semasa atau akhirnya janji itu. Mari kita mendalaminya.

Peraturan 2.2 (Kaedah kemudian) menyatakan bahawa janji mesti mempunyai kaedah then(), yang menerima dua hujah:

try {
    executor(resolve, reject);
} catch (error) {
    reject(error);
}

Kedua-dua onFulfilled dan onRejected mesti dipanggil selepas janji dipenuhi atau ditolak, melepasi nilai janji atau alasan sebagai hujah pertama mereka jika ia adalah fungsi:

class YourPromise {
    constructor(executor) {
        // Implementation
    }

    then(onFulfilled, onRejected) {
        // Implementation
    }
}

Selain itu, mereka tidak boleh dipanggil sebelum janji ditunaikan atau ditolak, atau lebih daripada sekali. Kedua-dua onFulfilled dan onRejected adalah pilihan dan harus diabaikan jika ia bukan fungsi.

Jika anda melihat Peraturan 2.2, 2.2.6 dan 2.2.7, anda akan melihat bahawa janji mesti mempunyai kaedah then(), kaedah then() boleh dipanggil beberapa kali dan ia mesti mengembalikan a janji:

promise.then(onFulfilled, onRejected);

Untuk memastikan perkara mudah, kami tidak akan berurusan dengan kelas atau fungsi yang berasingan. Kami akan mengembalikan objek janji, melepasi fungsi pelaksana:

promise2 = promise1.then(onFulfilled, onRejected);

Dalam fungsi pelaksana, jika janji dipenuhi, kami memanggil panggilan balik onFulfilled dan menyelesaikannya dengan nilai janji. Begitu juga, jika janji ditolak, kami memanggil panggilan balik onRejected dan menolaknya dengan alasan janji itu.

Soalan seterusnya ialah apa yang perlu dilakukan dengan panggilan balik onFulfilled dan onRejected jika janji masih dalam keadaan belum selesai? Kami beratur untuk dipanggil kemudian, seperti berikut:

new Promise(excecutor);

Kami sudah selesai. Berikut ialah draf kedua kelas Promise kami, termasuk kaedah then():

const promise = new Promise((resolve, reject) => {
    // Runs some async or sync tasks
});

Di sini, kami memperkenalkan dua medan: onFulfilledCallbacks dan onRejectedCallbacks sebagai baris gilir untuk menahan panggilan balik. Baris gilir ini diisi dengan panggilan balik melalui panggilan then() semasa janji belum selesai dan ia dipanggil apabila janji ditepati atau ditolak.

Teruskan uji kelas Promise anda:

class YourPromise {
    constructor(executor) {
        this.state = 'pending';
        this.value = undefined;
        this.reason = undefined;

        const resolve = value => {
            if (this.state === 'pending') {
                this.state = 'fulfilled';
                this.value = value;
            }
        };

        const reject = reason => {
            if (this.state === 'pending') {
                this.state = 'rejected';
                this.reason = reason;
            }
        };

        try {
            executor(resolve, reject);  // The executor function being called immediately
        } catch (error) {
            reject(error);
        }
    }
}

Ia sepatutnya mengeluarkan:

const resolve = value => {
    if (this.state === 'pending') {
        this.state = 'fulfilled';
        this.value = value;
    }
};

const reject = reason => {
    if (this.state === 'pending') {
        this.state = 'rejected';
        this.reason = reason;
    }
};

Sebaliknya, jika anda menjalankan ujian berikut:

this.state = 'pending';

Anda akan mendapat:

try {
    executor(resolve, reject);
} catch (error) {
    reject(error);
}

Sebaliknya:

class YourPromise {
    constructor(executor) {
        // Implementation
    }

    then(onFulfilled, onRejected) {
        // Implementation
    }
}

Kenapa? Isunya terletak pada cara kaedah then() memproses panggilan balik apabila contoh YourPromise sudah diselesaikan atau ditolak pada masa then() dipanggil. Khususnya, apabila keadaan janji tidak belum selesai, kaedah then() tidak menangguhkan pelaksanaan panggilan balik dengan betul ke baris gilir tugas mikro seterusnya. Dan itu menyebabkan pelaksanaan segerak. Dalam ujian contoh kami:

⟶ Janji segera diselesaikan dengan nilai 'Segera diselesaikan'.

⟶ Apabila promise.then() dipanggil keadaan sudah dipenuhi, jadi panggilan balik onFulfilled dilaksanakan terus tanpa ditunda ke baris gilir tugas mikro seterusnya.

Di sini Peraturan 2.2.4 mula dimainkan. Peraturan ini memastikan bahawa panggil balik then() (onFulfilled atau onRejected) dilaksanakan secara tidak segerak, walaupun janji telah diselesaikan atau ditolak. Ini bermakna panggilan balik tidak boleh dijalankan sehingga timbunan pelaksanaan semasa benar-benar jelas dan hanya kod platform (seperti gelung acara atau baris gilir tugas mikro) sedang dijalankan.

Mengapa peraturan ini penting?

Peraturan ini ialah salah satu peraturan terpenting dalam spesifikasi Promise/A. Kerana ia memastikan bahawa:

⟶ Walaupun janji diselesaikan serta-merta, panggilan balik then() itu tidak akan dilaksanakan sehingga tanda seterusnya bagi gelung acara.

⟶ Tingkah laku ini sejajar dengan kelakuan API tak segerak yang lain dalam JavaScript seperti setTimeout atau process.nextTick.

Bagaimanakah kita boleh mencapai ini?

Ini boleh dicapai sama ada dengan mekanisme tugasan makro seperti setTimeout atau setImmediate, atau dengan mekanisme tugasan mikro seperti queueMicrotask atau process.nextTick. Kerana panggilan balik dalam tugasan mikro atau tugasan makro atau mekanisme serupa akan dilaksanakan selepas konteks pelaksanaan JavaScript semasa selesai.

Untuk menyelesaikan isu di atas, kami perlu memastikan bahawa walaupun keadaan telah dipenuhi atau ditolak, panggilan balik yang sepadan (onFulfilled atau onRejected) dilaksanakan secara tidak segerak menggunakan queueMicrotask. Berikut ialah pelaksanaan yang diperbetulkan:

promise.then(onFulfilled, onRejected);

Jalankan semula kod ujian contoh sebelumnya. Anda sepatutnya mendapat output berikut:

promise2 = promise1.then(onFulfilled, onRejected);

Itu sahaja.

Setakat ini, anda sepatutnya mempunyai pemahaman yang jelas tentang cara panggilan balik dari then() ditangguhkan dan dilaksanakan dalam baris gilir tugas mikro seterusnya, yang membolehkan gelagat tak segerak. Pemahaman yang kukuh tentang konsep ini adalah penting untuk menulis kod tak segerak yang berkesan dalam JavaScript.

Apa yang seterusnya? Memandangkan artikel ini tidak merangkumi spesifikasi penuh Janji/A, anda boleh cuba melaksanakan yang lain untuk mendapatkan pemahaman yang lebih mendalam.

Memandangkan anda telah berjaya sejauh ini, semoga anda menikmati bacaannya! Sila kongsi artikel.

Ikuti saya di:
LinkedIn, Sederhana dan Github

Atas ialah kandungan terperinci Cipta Janji anda sendiri dalam JavaScript. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Aliran node.js dengan typescriptAliran node.js dengan typescriptApr 30, 2025 am 08:22 AM

Node.js cemerlang pada I/O yang cekap, sebahagian besarnya terima kasih kepada aliran. Aliran memproses data secara berperingkat, mengelakkan beban memori-ideal untuk fail besar, tugas rangkaian, dan aplikasi masa nyata. Menggabungkan sungai dengan keselamatan jenis typescript mencipta powe

Python vs JavaScript: Pertimbangan Prestasi dan KecekapanPython vs JavaScript: Pertimbangan Prestasi dan KecekapanApr 30, 2025 am 12:08 AM

Perbezaan prestasi dan kecekapan antara Python dan JavaScript terutamanya dicerminkan dalam: 1) sebagai bahasa yang ditafsirkan, Python berjalan perlahan tetapi mempunyai kecekapan pembangunan yang tinggi dan sesuai untuk pembangunan prototaip pesat; 2) JavaScript adalah terhad kepada benang tunggal dalam penyemak imbas, tetapi I/O multi-threading dan asynchronous boleh digunakan untuk meningkatkan prestasi dalam node.js, dan kedua-duanya mempunyai kelebihan dalam projek sebenar.

Asal JavaScript: Meneroka Bahasa PelaksanaannyaAsal JavaScript: Meneroka Bahasa PelaksanaannyaApr 29, 2025 am 12:51 AM

JavaScript berasal pada tahun 1995 dan dicipta oleh Brandon Ike, dan menyedari bahasa itu menjadi C. 1.C Language menyediakan keupayaan pengaturcaraan prestasi tinggi dan sistem untuk JavaScript. 2. Pengurusan memori JavaScript dan pengoptimuman prestasi bergantung pada bahasa C. 3. Ciri lintas platform bahasa C membantu JavaScript berjalan dengan cekap pada sistem operasi yang berbeza.

Di sebalik tabir: Apa bahasa JavaScript?Di sebalik tabir: Apa bahasa JavaScript?Apr 28, 2025 am 12:01 AM

JavaScript berjalan dalam penyemak imbas dan persekitaran Node.js dan bergantung pada enjin JavaScript untuk menghuraikan dan melaksanakan kod. 1) menjana pokok sintaks abstrak (AST) di peringkat parsing; 2) menukar AST ke bytecode atau kod mesin dalam peringkat penyusunan; 3) Laksanakan kod yang disusun dalam peringkat pelaksanaan.

Masa Depan Python dan JavaScript: Trend dan RamalanMasa Depan Python dan JavaScript: Trend dan RamalanApr 27, 2025 am 12:21 AM

Trend masa depan Python dan JavaScript termasuk: 1. Kedua -duanya akan terus mengembangkan senario aplikasi dalam bidang masing -masing dan membuat lebih banyak penemuan dalam prestasi.

Python vs JavaScript: Persekitaran dan Alat PembangunanPython vs JavaScript: Persekitaran dan Alat PembangunanApr 26, 2025 am 12:09 AM

Kedua -dua pilihan Python dan JavaScript dalam persekitaran pembangunan adalah penting. 1) Persekitaran pembangunan Python termasuk Pycharm, Jupyternotebook dan Anaconda, yang sesuai untuk sains data dan prototaip cepat. 2) Persekitaran pembangunan JavaScript termasuk node.js, vscode dan webpack, yang sesuai untuk pembangunan front-end dan back-end. Memilih alat yang betul mengikut keperluan projek dapat meningkatkan kecekapan pembangunan dan kadar kejayaan projek.

Adakah JavaScript ditulis dalam C? Memeriksa buktiAdakah JavaScript ditulis dalam C? Memeriksa buktiApr 25, 2025 am 12:15 AM

Ya, teras enjin JavaScript ditulis dalam C. 1) Bahasa C menyediakan prestasi yang efisien dan kawalan asas, yang sesuai untuk pembangunan enjin JavaScript. 2) Mengambil enjin V8 sebagai contoh, terasnya ditulis dalam C, menggabungkan kecekapan dan ciri-ciri berorientasikan objek C. 3) Prinsip kerja enjin JavaScript termasuk parsing, penyusun dan pelaksanaan, dan bahasa C memainkan peranan penting dalam proses ini.

Peranan JavaScript: Membuat Web Interaktif dan DinamikPeranan JavaScript: Membuat Web Interaktif dan DinamikApr 24, 2025 am 12:12 AM

JavaScript adalah di tengah -tengah laman web moden kerana ia meningkatkan interaktiviti dan dinamik laman web. 1) Ia membolehkan untuk menukar kandungan tanpa menyegarkan halaman, 2) memanipulasi laman web melalui Domapi, 3) menyokong kesan interaktif kompleks seperti animasi dan drag-and-drop, 4) mengoptimumkan prestasi dan amalan terbaik untuk meningkatkan pengalaman pengguna.

See all articles

Alat AI Hot

Undresser.AI Undress

Undresser.AI Undress

Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover

AI Clothes Remover

Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool

Undress AI Tool

Gambar buka pakaian secara percuma

Clothoff.io

Clothoff.io

Penyingkiran pakaian AI

Video Face Swap

Video Face Swap

Tukar muka dalam mana-mana video dengan mudah menggunakan alat tukar muka AI percuma kami!

Alat panas

Dreamweaver CS6

Dreamweaver CS6

Alat pembangunan web visual

EditPlus versi Cina retak

EditPlus versi Cina retak

Saiz kecil, penyerlahan sintaks, tidak menyokong fungsi gesaan kod

Penyesuai Pelayan SAP NetWeaver untuk Eclipse

Penyesuai Pelayan SAP NetWeaver untuk Eclipse

Integrasikan Eclipse dengan pelayan aplikasi SAP NetWeaver.

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

Persekitaran pembangunan bersepadu PHP yang berkuasa

Hantar Studio 13.0.1

Hantar Studio 13.0.1

Persekitaran pembangunan bersepadu PHP yang berkuasa