Saya pernah bekerja sebagai pembangun Java dan saya ingat buat kali pertama apabila saya berhubung dengan janji dalam JavaScript. Walaupun konsepnya kelihatan mudah, saya masih tidak dapat memahami sepenuhnya cara Janji berfungsi. Ia berubah apabila saya mula menggunakannya dalam projek dan memahami kes yang mereka selesaikan. Kemudian datang saat AHA dan semuanya menjadi lebih jelas. Lama kelamaan, Janji menjadi senjata berharga pada tali pinggang alat saya. Agak memuaskan apabila saya boleh menggunakannya di tempat kerja dan menyelesaikan pengendalian async antara fungsi.
Anda mungkin pertama kali menemui Promises apabila mengambil data daripada API, yang juga merupakan contoh yang paling biasa. Baru-baru ini, saya telah ditemu bual, dan teka apakah soalan pertama "Bolehkah anda beritahu saya perbezaan antara Janji dan Async Await?". Saya mengalu-alukannya kerana saya melihatnya sebagai titik permulaan yang baik untuk mengetahui dengan lebih baik cara pemohon memahami cara mekanisme tersebut berfungsi. Walau bagaimanapun, dia kebanyakannya menggunakan perpustakaan dan rangka kerja lain. Ia membenarkan saya menulis perbezaan dan menerangkan amalan baik untuk mengendalikan ralat fungsi async.
Mari kita mulakan dengan soalan awal: “Apakah Janji itu?” Promise ialah pemegang tempat untuk nilai yang belum kami ketahui tetapi kami akan mendapatkannya hasil daripada pengiraan/fungsi tak segerak. Jika janji berjalan lancar, barulah kita akan dapat hasilnya. Jika janji tidak berjalan dengan baik, maka janji itu akan membalas kesilapan.
Anda mentakrifkan Janji dengan memanggil pembinanya dan menghantar dua fungsi panggil balik: selesaikan dan tolak.
const newPromise = new Promise((resolve, reject) => { resolve('Hello'); // reject('Error'); });
Kami memanggil fungsi menyelesaikan apabila kami ingin berjaya menyelesaikan Janji. menolak adalah untuk menolak janji dalam kes apabila ralat berlaku semasa menilai logik kami.
Kami menggunakan fungsi terbina dalam kemudian untuk mendapatkan hasil Janji. Ia mempunyai dua panggilan balik yang diluluskan, hasil dan ralat. Keputusan dipanggil apabila Janji berjaya diselesaikan oleh penyelesaian fungsi. Jika Janji tidak diselesaikan, ralat fungsi kedua dipanggil. Fungsi ini dicetuskan sama ada oleh penolakan atau oleh ralat lain yang dilemparkan.
newPromise.then(result => { console.log(result); // Hello }, error => { console.log("There shouldn't be an error"); });
Dalam contoh kami, kami akan mendapat hasil Hello kerana kami berjaya menyelesaikan Janji.
Apabila Janji ditolak maka panggilan balik ralat kedua sentiasa dipanggil.
const newPromise1 = new Promise((resolve, reject) => { reject('An error occurred in Promise1'); }); newPromise1.then( (result) => { console.log(result); // It is not invoked }, (error) => { console.log(error); // 'An error occurred in Promise1' } );
Pendekatan yang lebih disyorkan untuk kejelasannya ialah menggunakan kaedah tangkapan terbina dalam.
const newPromise2 = new Promise((resolve, reject) => { reject('An error occurred in Promise2'); }); newPromise2 .then((result) => { console.log(result); // It is not invoked }) .catch((error) => { console.log(error); // 'An error occurred in Promise2' });
kaedah tangkapan dirantai dan telah menyediakan panggilan balik ralatnya sendiri. Ia akan dipanggil apabila Janji ditolak.
Kedua-dua versi berfungsi dengan baik tetapi rantaian IMO lebih mudah dibaca dan ia berguna apabila menggunakan kaedah terbina dalam lain yang kami bahas lebih lanjut.
Hasil janji mungkin janji lain. Dalam kes itu, kita boleh merantai nombor arbitrari fungsi kemudian.
getJSON('categories.json') .then(categories => { console.log('Fetched categories:', categories); return getJSON(categories[0].itemsUrl); }) .then(items => { console.log('Fetched items:', items); return getJSON(items[0].detailsUrl); }) .then(details => { console.log('Fetched details:', details); }) .catch(error => { console.error('An error has occurred:', error.message); });
Dalam contoh kami, ia berfungsi untuk mengecilkan hasil carian untuk mendapatkan data butiran. Setiap fungsi kemudian juga boleh mempunyai panggilan balik ralatnya. Jika kita hanya mengambil berat tentang menangkap sebarang ralat dalam rantaian panggilan, maka kita boleh memanfaatkan fungsi tangkapan. Ia akan dinilai jika mana-mana Janji mengembalikan ralat.
Kadang-kadang kita mahu menunggu hasil janji yang lebih bebas dan kemudian bertindak atas hasilnya. Kita boleh menggunakan fungsi Promise.all terbina dalam jika kita tidak mengambil berat tentang susunan cara Janji diselesaikan.
Promise.all([ getJSON('categories.json'), getJSON('technology_items.json'), getJSON('science_items.json') ]) .then(results => { const categories = results[0]; const techItems = results[1]; const scienceItems = results[2]; console.log('Fetched categories:', categories); console.log('Fetched technology items:', techItems); console.log('Fetched science items:', scienceItems); // Fetch details of the first item in each category return Promise.all([ getJSON(techItems[0].detailsUrl), getJSON(scienceItems[0].detailsUrl) ]); }) .then(detailsResults => { const laptopDetails = detailsResults[0]; const physicsDetails = detailsResults[1]; console.log('Fetched laptop details:', laptopDetails); console.log('Fetched physics details:', physicsDetails); }) .catch(error => { console.error('An error has occurred:', error.message); });
Promise.all mengambil pelbagai Janji dan mengembalikan pelbagai hasil. Jika salah satu Janji ditolak maka Janji.semuanya juga ditolak.
Satu lagi fungsi terbina dalam ialah Promise.race. Ia digunakan apabila anda mempunyai berbilang fungsi tak segerak - Janji - dan anda mahu berlumba dengannya.
Promise.race([ getJSON('technology_items.json'), getJSON('science_items.json') ]) .then(result => { console.log('First resolved data:', result); }) .catch(error => { console.error('An error has occurred:', error.message); });
Pelaksanaan Janji boleh mengambil masa yang berbeza dan Promise.race menilai Janji pertama yang diselesaikan atau ditolak daripada tatasusunan. Ia digunakan apabila kami tidak mengambil berat tentang pesanan tetapi kami mahukan hasil panggilan tak segerak terpantas.
Seperti yang anda lihat, menulis Janji memerlukan banyak kod boilerplate. Nasib baik, kami mempunyai ciri Async Awaiit asli, yang menjadikan penggunaan Promises lebih mudah. Kami menandakan fungsi dengan perkataan async dan dengan itu, kami mengatakan bahawa di suatu tempat dalam kod kami akan memanggil fungsi asynchronous dan kami tidak perlu menunggunya. Kemudian fungsi async dipanggil dengan perkataan tunggu.
const fetchData = async () => { try { // Fetch the categories const categories = await getJSON('categories.json'); console.log('Fetched categories:', categories); // Fetch items from the first category (Technology) const techItems = await getJSON(categories[0].itemsUrl); console.log('Fetched technology items:', techItems); // Fetch details of the first item in Technology (Laptops) const laptopDetails = await getJSON(techItems[0].detailsUrl); console.log('Fetched laptop details:', laptopDetails); } catch (error) { console.error('An error has occurred:', error.message); } }; fetchData();
Our fetchData is marked as async and it allows us to use await to handle asynchronous calls inside the function. We call more Promises and they will evaluated one after the other.
We use try...catch block if we want handle the errors. Rejected error is then caught in the catch block and we can act on it like logging the error.
They are both features of JavaScript handling with asynchronous code. The main difference is in the syntax when Promises use chaining with then and catch but async await syntax is more in synchronous way. It makes it easier to read. Error handling for async await is more straightforward when it leverages try...catch block. This is a question that you can easily get at the interview. During the answer, you can get deeper into the description of both and highlight those differences.
Promise features
Of course, you can use all the features with async await. For example Promise.all.
const fetchAllData = async () => { try { // Use await with Promise.all to fetch multiple JSON files in parallel const [techItems, scienceItems, laptopDetails] = await Promise.all([ getJSON('technology_items.json'), getJSON('science_items.json'), getJSON('laptops_details.json') ]); console.log('Fetched technology items:', techItems); console.log('Fetched science items:', scienceItems); console.log('Fetched laptop details:', laptopDetails); } catch (error) { console.error('An error occurred:', error.message); } };
Promises are a fundamental feature in JavaScript for handling asynchronous code. Here are the main ways it is used:
As was already shown in the examples above, this is one of the most used use cases for Promises and you work with it daily.
Reading and writing files asynchronously can be done using promises, especially by Node.js module fs.promises
import * as fs from 'fs/promises'; const writeFileAsync = async (filePath, content, options = {}) => { try { await fs.writeFile(filePath, content, options); console.log(`File successfully written to ${filePath}`); } catch (error) { console.error(`Error writing file to ${filePath}:`, error.message); } }; const filePath = 'output.txt'; const fileContent = 'Hello, this is some content to write to the file!'; const fileOptions = { encoding: 'utf8', flag: 'w' }; // Optional file write options writeFileAsync(filePath, fileContent, fileOptions);
Axios is library that you should be familiar with. Axios handles HTTP requests in client and is vastly used.
Express is a web framework for Node.js. It makes it easy to build web apps and APIs, and when you use promises with Express, your code stays clean and easy to manage.
All the examples can be found at: https://github.com/PrincAm/promise-example
Promises are a fundamental part of JavaScript, essential for handling asynchronous tasks in web development. Whether fetching data, working with files, or using popular libraries like Axios and Express, you’ll frequently use promises in your code.
In this article, we explored what Promises are, how to define and retrieve their results, and how to handle errors effectively. We also covered key features like chaining, Promise.all, and Promise.race. Finally, we introduced async await syntax, which offers a more straightforward way to work with promises.
Understanding these concepts is crucial for any JavaScript developer, as they are tools you’ll rely on daily.
If you haven’t tried it yet, I recommend writing a simple code snippet to fetch data from an API. You can start with a fun API to experiment with. Plus, all the examples and code snippets are available in this repository for you to explore.
Atas ialah kandungan terperinci Janji dalam JavaScript: Memahami, Mengendalikan dan Menguasai Kod Async. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!