JS Promises PDF
Document Details
Uploaded by FavoriteConstructivism6060
Tags
Summary
This document covers the concept of promises in JavaScript. It details how promises can be used to handle asynchronous operations, and provides examples on how to use promises.
Full Transcript
Promises CPEN320 What is a Promise 1. What is a Promise 2. How to use Promises 3. Asynchronous Programming with Promises 2 What is a Promise Promise is a new built-in object introduced in ES6 Provides a cleaner interface for handling asynchronous...
Promises CPEN320 What is a Promise 1. What is a Promise 2. How to use Promises 3. Asynchronous Programming with Promises 2 What is a Promise Promise is a new built-in object introduced in ES6 Provides a cleaner interface for handling asynchronous operations When multiple asynchronous operations need to be made, the callback pattern becomes hard to follow ○ Scope of variables in multiple nested closures ○ Error handling for each of the callback steps 3 Why use Promise? Consider a function first with the following signature: ○ function first(arg, callback) ○ arg is some data ○ callback is a function accepting 2 arguments: error and result 1 function first (arg, callback){ 2 var result = null; 3 // do some asynchronous stuff... 4 callback(result); 5 //... do some other stuff 6 } 7 8 first("Hello World", (error, result)=> { 9 console.log(error ? "ERROR!" : result); 10 }); 4 Why use Promise? Consider 2 more functions with similar function signatures: ○ function second(arg, callback) ○ function third(arg, callback) How to create a new function that calls the 3 functions in sequence? 1 function first (arg, callback){ }; 2 function second (arg, callback){ }; 3 function third (arg, callback){ }; 4 5 function do123(arg, callback){ 6 10 } 5 Why use Promise? Consider 2 more functions with similar function signatures: ○ function second(arg, callback) ○ function third(arg, callback) How to create a new function that calls the 3 functions in sequence? do123 first second third 6 Why use Promise? How to create a new function that calls the 3 functions in sequence? 1 function do123(arg, callback){ 2 3 4 5 6 7 8 9 } 10 11 12 7 Why use Promise? How to create a new function that calls the 3 functions in sequence? 1 function do123(arg, callback){ 2 first(arg, (err1, result1)=> { 3 4 5 6 7 8 }); 9 } 10 11 12 8 Why use Promise? How to create a new function that calls the 3 functions in sequence? 1 function do123(arg, callback){ 2 first(arg, (err1, result1)=> { 3 second(result1, (err2, result2)=> { 4 5 6 7 }); 8 }); 9 } 10 11 12 9 Why use Promise? How to create a new function that calls the 3 functions in sequence? 1 function do123(arg, callback){ 2 first(arg, (err1, result1)=> { 3 second(result1, (err2, result2)=> { 4 third(result2, (err3, result3)=> { 5 6 }); 7 }); 8 }); 9 } 10 11 12 10 Why use Promise? How to create a new function that calls the 3 functions in sequence? 1 function do123(arg, callback){ 2 first(arg, (err1, result1)=> { 3 second(result1, (err2, result2)=> { 4 third(result2, (err3, result3)=> { 5 callback(null, result3); 6 }); 7 }); 8 }); 9 } 10 11 12 11 Why use Promise? How to create a new function that calls the 3 functions in sequence? 1 function do123(arg, callback){ 2 first(arg, (err1, result1)=> { 3 if (err1) callback(err1); 4 else second(result1, (err2, result2)=> { 5 third(result2, (err3, result3)=> { 6 callback(null, result3); 7 }); 8 }); 9 }); 10 } 11 12 12 Why use Promise? How to create a new function that calls the 3 functions in sequence? 1 function do123(arg, callback){ 2 first(arg, (err1, result1)=> { 3 if (err1) callback(err1); 4 else second(result1, (err2, result2)=> { 5 if (err2) callback(err2); 6 else third(result2, (err3, result3)=> { 7 callback(null, result3); 8 }); 9 }); 10 }); 11 } 12 13 Why use Promise? How to create a new function that calls the 3 functions in sequence? 1 function do123(arg, callback){ 2 first(arg, (err1, result1)=> { 3 if (err1) callback(err1); 4 else second(result1, (err2, result2)=> { 5 if (err2) callback(err2); 6 else third(result2, (err3, result3)=> { 7 if (err3) callback(err3); 8 else callback(null, result3); 9 }); 10 }); 11 }); 12 } 14 Why use Promise? How to create a new function that calls the 3 functions in sequence? 1 function do123(arg, callback){ 2 first(arg, (err1, result1)=> { 3 if (err1) callback(err1); 4 else second(result1, (err2, result2)=> { 5 if (err2) callback(err2); 6 else third(result2, (err3, result3)=> { 7 if (err3) callback(err3); 8 else callback(null, result3); 9 }); 10 }); Callback Hell 11 }); 12 } 15 Why use Promise? Problem with callbacks: the code structure does not follow the logical structure 1 function do123(arg, callback){ do123 2 first(arg, (err1, result1)=> { 3 if (err1) callback(err1); first 4 else second(result1, (err2, result2)=> { 5 if (err2) callback(err2); 6 else third(result2, (err3, result3)=> { second 7 if (err3) callback(err3); 8 else callback(null, result3); 9 }); third 10 }); 11 }); 12 } Success Error 16 Why use Promise? It would be nice if the code structure followed the logical structure 1 function do123(arg, callback){ do123 2 3 first 4 5 6 second 7 8 9 third 10 11 12 } Success Error 17 Why use Promise? Consider the same first function using a Promise-based interface ○ function first(arg) - notice the lack of a callback argument ○ arg is some data ○ returns a Promise object 1 function first (arg){ 2 return new Promise((resolve, reject)=> { 3 var result = null; 4 // do some asynchronous stuff... 5 resolve(result); 6 //... do some other stuff 7 }); 8 } 9 first("Hello World") 10.then(console.log, (error)=> console.log("ERROR!")); 18 Why use Promise? Using ES5 Callbacks Using ES6 Promises 1 function do123(arg, callback){ 1 function do123(arg){ 2 first(arg, 2 return first(arg) 3 (err1, result1)=> { 3.then(second) 4 if (err1) callback(err1); 4.then(third) 5 else second(result1, 5 } 6 (err2, result2)=> { 6 7 if (err2) callback(err2); 7 8 else third(result2, 8 9 (err3, result3)=> { 9 10 if (err3) callback(err3); 10 11 else 11 12 callback(null, result3); 12 13 }); }); }); 13 14 } 14 19 How to use Promises 1. What is a Promise 2. How to use Promises 3. Asynchronous Programming with Promises 20 Promise Promise is an object with the following methods ○ then (onResolve, onReject): used to register resolve and reject callbacks ○ catch (onReject): used to register reject callback ○ finally (onComplete): used to register settlement callback Promise will be in one of the three states: pending, resolved, rejected Promise also has static methods ○ resolve (value): returns a Promise that resolves immediately to value ○ reject (error): returns a Promise that rejects immediately to error ○ all (promises): returns a Promise that resolves when all promises resolve ○ race (promises): returns a Promise that resolves if any of the promises resolve 21 Promise Creating a Promise object ○ new Promise(func): The Promise constructor expects a single argument func, which is a function with 2 arguments: resolve, reject ○ resolve and reject are callback functions for emitting the result of the operation resolve(result) to emit the result of a successful operation reject(error) to emit the error from a failed operation 1 var action = new Promise((resolve, reject)=> { 2 var result = null; 3 // do some asynchronous stuff... 4 if (noError) resolve(result); 5 else reject(new Error("Something Wrong")); 6 //... do some other stuff 7 }); 22 Promise Creating a Promise object ○ new Promise(func): The Promise constructor expects a single argument func, which is a function with 2 arguments: resolve, reject ○ resolve and reject are callback functions for emitting the result of the operation resolve(result) to emit the result of a successful operation reject(error) to emit the error from a failed operation 1 var action = new Promise((resolve, reject)=> { 2 setTimeout(()=> { 3 if (Math.random() > 0.5) resolve("Success!"); 4 else reject(new Error("LowValueError")); 5 }, 1000); 6 }); 7 23 Promise Using the result of a Promise fulfillment through the then method ○ then(onResolve, onReject): used to register callbacks for handling the result of the Promise. It returns another Promise, making this function chainable ○ onResolve is called if the previous Promise resolves; it receives the resolved value as the only argument ○ onReject is called if the previous Promise rejects or throws an error; it receives the rejected value or the error object as the only argument 1 action.then( 2 (result)=> console.log(result), // result: "Success!" 3 (error)=> console.log(error) // error: Error("LowValueError") 4 ); 5 6 24 Promise Using the result of a Promise fulfillment through the then method ○ then(onResolve, onReject): used to register callbacks for handling the result of the Promise. It returns another Promise, making this function chainable ○ onResolve is called if the previous Promise resolves; it receives the resolved value as the only argument ○ onReject is called if the previous Promise rejects or throws an error; it receives the rejected value or the error object as the only argument 1 action.then( 2 (result)=> console.log(result), // result: "Success!" 3 (error)=> console.log(error) // error: Error("LowValueError") 4 ) 5.then(()=> console.log("A")); 6 25 Promise Using the result of a Promise fulfillment through the then method ○ then(onResolve, onReject): used to register callbacks for handling the result of the Promise. It returns another Promise, making this function chainable ○ onResolve is called if the previous Promise resolves; it receives the resolved value as the only argument ○ onReject is called if the previous Promise rejects or throws an error; it receives the rejected value or the error object as the only argument 1 action.then( 2 (result)=> console.log(result), // result: "Success!" 3 (error)=> console.log(error) // error: Error("LowValueError") 4 ) 5.then(()=> console.log("A")) 6.then(()=> console.log("B")); 26 Example: Loading data after a delay (without Promises) function fetchData(callback) { console.log("Fetching data..."); setTimeout(() => { const user = { id: 1, name: "John Doe" }; callback(user); // Pass the data to the callback after 2 seconds }, 2000); // 2 seconds delay } // Handle the data once it's fetched function handleData(data) { console.log("Data fetched:", data); } // Call the function and pass the handleData as the callback fetchData(handleData); 27 Example: Loading data after a delay (with Promises) function fetchData() { return new Promise((resolve, reject) => { console.log("Fetching data..."); setTimeout(() => { const user = { id: 1, name: "John Doe" }; resolve(user); // Resolve the promise with the data after 2 seconds }, 2000); }); } // Call the function and use.then() to handle the resolved data fetchData().then((data) => { console.log("Data fetched:", data); // Handle the data once it's resolved }).catch((error) => { console.log("Error:", error); // Catch any errors }); 28 Class Activity: Promise Chaining Create a resolveAfter function that resolves after a specified amount of time, returning a Promise object ○ The function should print the given time before resolving Using the resolveAfter function and the then method to chain the promises, make the program print 500, 1000, 1500 one after another 1 function resolveAfter (time){ 2 // to implement 3 } 4 5 resolveAfter(500) 6.then() 29 Class Activity: Promise Chaining Solution function resolveAfter (time){ return new Promise((resolve) => { console.log(time); // Print the time setTimeout(() => { resolve(time); // Resolve the promise after the specified time }, time); }); } resolveAfter(500).then(() => resolveAfter(1000)) \\ arrow function () => to chain.then(() => resolveAfter(1500)); 30 Promise The catch method is used to handle the result of a rejected Promise ○ catch(onReject): used to register a callback for handling the result of the failed Promise. It returns another Promise, making this function chainable ○ onReject is called if the previous Promise rejects or throws an error; it receives the rejected value or the error object as the only argument 1 action.then( 2 (result)=> console.log(result), // result: "Success!" 3 (error)=> console.log(error) // error: Error("LowValueError") 4 ) 5.catch((err)=> console.log(err)); // any error on the chain 6 31 Promise The finally method is used to register a callback to be called when a Promise is settled, regardless of the result ○ finally(onComplete): It returns another Promise, making this function chainable ○ onComplete is called if the previous Promise is settled 1 action.then( 2 (result)=> console.log(result), // result: "Success!" 3 (error)=> console.log(error) // error: Error("LowValueError") 4 ) 5.catch((err)=> console.log(err)) 6.finally(()=> console.log("The End!")); 32 Promise The static functions Promise.resolve and Promise.reject are used to create a Promise object that immediately resolves or rejects with the given data ○ Useful when the next asynchronous operation expects a Promise object 1 action.then( 2 (result)=> console.log(result), // result: "Success!" 3 (error)=> console.log(error) // error: Error("LowValueError") 4 ) 5.catch((err)=> console.log(err)) 6.finally(()=> console.log("The End!")); 33 Promise The return values of the callback functions given to then, catch, and finally method are wrapped as a resolved Promise, if it is not already a Promise 1 action.then( 2 (result)=> { 3 return Promise.reject("Action Resolved") 4 }, 5 (error)=> { 6 return Promise.resolve("Action Rejected") 7 }) 8.then((result)=> console.log("Success: " + result), 9 (error)=> console.log("Error: " + error.message)); 10 11 // if action resolves, what is printed? what if it rejects? 35 How to use Promises 1. What is a Promise 2. How to use Promises 3. Asynchronous Programming with Promises 38 Asynchronous Programming JavaScript involves a lot of asynchronous operations ○ The Internet is where JavaScript is used: this involves a lot of AJAX requests ○ The I/O model for the JavaScript VM is asynchronous: files, sockets, processes, Inter-process communication, and I/O streams all handled by asynchronous API The Promise API makes it easy to compose a sequence of asynchronous operations as a dataflow pipeline 39 Asynchronous Programming Example: Node.js application providing a document signing service 1 function signDocument(userID, fileURL){ 2 return getUser(userID) 3.then((user)=> downloadFile(fileURL, user.apiKey)) 4.then((file)=> requestNotary(file, user.cert)) 5.then((signed)=> updateRecord(userID, signed.hash)) 6.then(()=> (true), (err)=> Promise.reject(err)) 7 } 8 9 var app = express(); 10 app.post("/sign-request", (req, res)=> { 11 signDocument(req.session.username, req.body.fileURL) 12.then(()=> res.status(200).send("Successful")) 13.catch((err)=> res.status(500).send("Server Error")) 14 }); 40 Promise Using the static function Promise.all, we can wait for multiple concurrent Promises to be resolved (sort of like joining threads) ○ Promise.all accepts an Array of promises and returns a Promise that resolves to an array of results (in the same order as the promises given) 1 var multi = Promise.all([ 2 new Promise((resolve)=> setTimeout(()=> resolve("A"), 2000)), 3 new Promise((resolve)=> setTimeout(()=> resolve("B"), 3000)), 4 new Promise((resolve)=> setTimeout(()=> resolve("C"), 1000)), 5 ]); 6 7 multi.then( 8 (results)=> console.log(results), 9 (error)=> console.log(error)); 10 41 11 Promise Using the static function Promise.race, we can retrieve the first Promise to resolve out of a set of concurrent Promises ○ Promise.race accepts an Array of promises and returns the first Promise that resolves 1 var multi = Promise.race([ 2 new Promise((resolve)=> setTimeout(()=> resolve("A"), 2000)), 3 new Promise((resolve)=> setTimeout(()=> resolve("B"), 3000)), 4 new Promise((resolve)=> setTimeout(()=> resolve("C"), 1000)), 5 ]); 6 7 multi.then( 8 (result)=> console.log(result), 9 (error)=> console.log(error)); 10 42 11 Class Activity Write a node.js program to read from two different text files and concatenate their contents using Promises. After both reads are complete, you should write the contents of the two files to a third file. You can assume that the order of reads is not important. You should not block for file read, nor read the files sequentially. How will you modify the above program if you wanted to write to the third file without waiting for both files to complete reading, again using promises ? Make sure that you follow the same constraints. 43