JavaScript进阶深入理解JavaScript中ES6的Promise的作用并实现一个自己的Promise
Posted 52tech
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JavaScript进阶深入理解JavaScript中ES6的Promise的作用并实现一个自己的Promise相关的知识,希望对你有一定的参考价值。
1.Promise的基本使用
1 // 需求分析: 封装一个方法用于读取文件路径,返回文件内容 2 3 const fs = require(‘fs‘); 4 const path = require(‘path‘); 5 6 7 /** 8 * 把一个回调函数才分成两个回调函数 9 * @param filename 10 * @param successCallback 11 * @param errorCallback 12 */ 13 function getFileByPath(filename, successCallback, errorCallback) { 14 fs.readFile(filename, ‘utf-8‘, (err, data) => { 15 if (err) { 16 return errorCallback(err); 17 } 18 successCallback(data); 19 }); 20 } 21 22 23 let filename1 = path.join(__dirname, ‘./files/1.txt‘); 24 let filename2 = path.join(__dirname, ‘./files/2.txt‘); 25 let filename3 = path.join(__dirname, ‘./files/3.txt‘); 26 27 28 // 1. 普通的函数调用方式【回调嵌套的问题???, 会产生一个回调地狱】 29 getFileByPath(filename1, function (data) { 30 // 成功的回调函数 31 console.log(data); 32 // 2. 如何实现文件1 2 3 按顺序读取数据 33 getFileByPath(filename2, function (data) { 34 console.log(data); 35 // 2. 如何实现文件1 2 3 按顺序读取数据 36 getFileByPath(filename3, function (data) { 37 console.log(data); 38 }, function (err) { 39 console.log(err); 40 }) 41 }, function (err) { 42 console.log(err); 43 }) 44 }, function (err) { 45 // 失败的回调函数 46 console.log(err.message); 47 }) 48 49 50 51 52 // 2. 使用ES6中的Promise对象,来解决回调地狱的问题 53 // 本质:本质是为了解决回调地狱的问题,并不能帮我们减少代码量 54 // 转换成为一个串联的函数串
2. 形式上的和具体的Promise异步执行操作的区别
为什么要使用Promise???
使用ES6中的Promise对象,来解决回调地狱的问题
// 本质:本质是为了解决回调地狱的问题,并不能帮我们减少代码量 // 转换成为一个串联的函数串 // ========================================================================================== // Promise的基本使用及注意事项: // 2.1 Promise实际上是一个构造函数,我们是可以直接通过new Promise() 的方式来得到一个Promise的实例的 // 2.2 在Promise上面的 两个函数, resolve 是一个成功之后的回调函数, 和 reject是一个失败的回调函数 // 2.3 在 Promise构造函数的prototype 上面有一个.then 的方法, 只要是Promise 构造函数创建的 实例对象,都是可以访问到.then这个方法的 // 2.4 Promise表示一个异步操作,每当们创建一个新的Promise 实例, 就表示创建了一个异步操作 // 2.5 异步操作的状态只能有两种状态 // 2.5.1 异步执行成功: 会执行成功的回调函数resolve,把成功的结果返回给调用者 // 2.5.2 异步执行失败: 会执行失败的回调函数reject, 把错误的结果返回给调用者 // 2.5.3 Promise的实例是一个异步操作,因此我么是无法直接通过 return来吧操作的结果返回给调用者的;就只能通过回调函数的方式吧成功或者失败的结果返回个调用者 // 2.6 我们可以在new 出来的Promise实例对象身上调用.then() 方法, 预先为这个Promise异步操作, 预先指定成功(resolve)和失败(rejecy)的回调函数。 // 2.7 也就是.then(resolve, reject) 里面传递的是一个实参对象, 然后我们到时候直接调用的实际上是一个resolve, reject的形参对象 // ==========================================================================================
// 需求分析: 封装一个方法用于读取文件路径,返回文件内容 const fs = require(‘fs‘); const path = require(‘path‘); /** * 把一个回调函数才分成两个回调函数 * @param filename * @param successCallback * @param errorCallback */ function getFileByPath(filename, successCallback, errorCallback) { fs.readFile(filename, ‘utf-8‘, (err, data) => { if (err) { return errorCallback(err); } successCallback(data); }); } let filename1 = path.join(__dirname, ‘./files/1.txt‘); let filename2 = path.join(__dirname, ‘./files/2.txt‘); let filename3 = path.join(__dirname, ‘./files/3.txt‘); // 1. 普通的函数调用方式【回调嵌套的问题???, 会产生一个回调地狱】 getFileByPath(filename1, function (data) { // 成功的回调函数 console.log(data); // 2. 如何实现文件1 2 3 按顺序读取数据 getFileByPath(filename2, function (data) { console.log(data); // 2. 如何实现文件1 2 3 按顺序读取数据 getFileByPath(filename3, function (data) { console.log(data); }, function (err) { console.log(err); }) }, function (err) { console.log(err); }) }, function (err) { // 失败的回调函数 console.log(err.message); }) // 创建一个promise 实例对象, 这里的这个promise,只是代表一个【形式上】的异步操作, 也就是我们只找到这是一个异步操作, 还不清楚下一步需要执行的操作??? // var promise = new Promise(); // 这是一个具体的异步操作, 通过使用function来实际上指定了一个具体的异步操作 var promise = new Promise(function () { // 在这个里面指定了一个具体的异步操作 类似于fs.readFile()这个异步操作 }); // 此时的promise就是一个异步执行的结果, 每当new 一个Promise实例, 就会执行这个异步操作中的代码 // 处理创建一个实例对象,还会立即调用这个Promise构造函数中传递的哪一个函数function, 执行function里面的代码 var promise = new Promise(function () { fs.readFile(filename1, ‘utf-8‘, function (err, data) { if (err) { throw err; } console.log(‘数据读取成功:‘, data); }) }) // 为了实现按需读取,可以把Promise放在一个函数中 /** * 使用Promise实现的一个数据读取并返回 * @param filename */ function getFileByFilename(filename) { // JS 中的函数作用域: 内部的成员只要没有return出去, 外部就是不能访问到的 var promise = new Promise(function (resolve, reject) { fs.readFile(filename, ‘utf-8‘, function (err, data) { if (err) { // throw err; return reject(err); } // console.log(‘数据‘ + filename + ‘中的数据读取成功:‘, data); resolve(‘数据‘ + filename + ‘中的数据读取成功:‘ + data) }) }) return promise; } // 获取到一个promise var promise = getFileByFilename(filename3); console.log(‘我是一个promise实例对象‘, promise); // 通过.then 预先指定了一个执行成功/失败的回调函数 promise.then(function (data) { console.log(data, ‘数据获取成功————————————————‘); }, function (err) { console.log(err, ‘数据获取失败——————————————‘); })
3. Promise执行的步骤分析
// 第0步:先在内存中定义了一个getFileByFilename方法 function getFileByFilename(filename) { // 第二步: 创建一个promise对象,并立即执行后面的 function函数 var promise = new Promise(function (resolve, reject) { console.log(resolve, reject); // 这个函数在创建Promise实例对象的时候就会立即执行,但是这里是一个异步执行,就会放到一个事件队列中去,等待执行 // 第六步:.then执行完毕之后就会执行这部分,此时上面的resolve和reject已经被绑定为刚开始设置的两个参数(形参和实参建立了联系)【异步事件放在事件队列中去】 fs.readFile(filename, ‘utf-8‘, function (err, data) { console.log(resolve, reject); if (err) { // 第七步:函数执行完毕之后开始去访问这个函数或者resolve函数(由于.then 函数是先执行的 ,因此此时的这个resolve 函数就指向了传过来的两个参数) return reject(err); } resolve(‘数据‘ + filename + ‘中的数据读取成功:‘ + data) }) }) // console.log(resolve, reject); // 第三步: 直接返回创建的这个promise对象实例 return promise; } // 第一步: 调用getgetFileByFilename函数 / 第四步: 在这里得到创建好的对象实例 var promise = getFileByFilename(filename3); // 第五步:通过.then 预先指定了一个执行成功/失败的回调函数(读取文件的操作是异步的,这里的操作相当于是一个给resolve和reject这两个函数来绑定一个函数, 传进去的是两个实参对象) promise.then(function (data) { console.log(data, ‘数据获取成功————————————————‘); }, function (err) { console.log(err, ‘数据获取失败——————————————‘); })
4. Promise捕获异常的两种方式
// 读取文件1 /** * 在上一个.then 中,返回一个新的 promise实例, 可以继续使用下一个.then来处理(类似于JQuery中的链式访问) * 【注意事项1】:如果前面的Promise执行失败, 我们不想让后续的Promise终止,可以为每一个promise指定失败的回调 * 【注意事项2】:如果前面的Promise执行失败, 后面没有继续向下执行的意义了,一旦有错误,就立即终止所有的Promise(不在每一个里面指定失败的回调函数) */ getFileByFilename(filename1) .then(function (data) { console.log(data); // 读取文件2 return getFileByFilename(filename2); }/*, function (err) { console.log(‘程序出错:‘, err.message); // 失败之后也要return 一个新的promise return getFileByFilename(filename2); }*/).then(function (data) { console.log(data); // 读取文件3 return getFileByFilename(filename3); }).then(function (data) { console.log(data); }).catch(function (err) { // catch 这个函数的错误的作用:只要前面有任何promise执行失败,就会立即终止所有的promise的执行,然后就会进入到catch里面的回调函数了 console.log(‘我是一个用来捕获程序错误的小东东……………………‘ + err.message); })
5.使用JQuery中的Promise发送Ajax请求数据
$.ajax({ url : ‘http://192.168.1.106:8081/api/getBroadcastPictures‘, type : ‘GET‘, dataType : ‘json‘, }).then(function (data) { // 前面返回的是一个promise对象 console.log(data); })
6. 实现一个自己封装的Promise对象
"use strict"; // 实现一个简单的Promise function Promise(executor) { // 第三步:这里的executor 是一个执行器, 是用户传递过来的一个参数信息(初始化实例对象中的所有参数信息) this.status = ‘pending‘; // 初始的状态信息 this.success = undefined; // 执行成供的值 this.error = undefined; // 执行失败的值 var self = this; function resolve(data) { // 如果执行成功的话 if (self.status === ‘pending‘) { // 重置状态码 self.status = ‘resolved‘; self.success = data; } } function reject(err) { // 如果执行失败的话 if (self.status === ‘pending‘) { self.status = ‘rejected‘; self.error = err; } } // 第四步:开始执行传递过来的两个函数参数 executor(resolve, reject); } /** * 传递的是两个参数,表示的是两个函数(这是一个异步执行的函数) * @param resolve * @param reject */ Promise.prototype.then = function (resolve, reject) { if (this.status === ‘resolved‘) { // 执行成功 resolve(); } if (this.status === ‘rejected‘) { // 执行失败 reject(); } } // 测试用例 function getData() { // 第二步: 创建一个Promise的实例对象,里面的函数是立即执行的 var promise = new Promise(function (resolve, reject) { // 这里是一个异步操作 setTimeout(function () { console.log(‘这里是一个十分耗时的操作!‘); // 如果执行成功的话 if(1 === 0) { console.log(‘执行成功!‘) resolve(true); } else { console.log(‘执行失败!‘) reject(false); } }, 1000) }); return promise; } // 这是一个对象, 对象身上有一个then 方法 // 第一步:开始执行getData() 函数 getData().then(function (data) { console.log(data); }, function (err) { console.log(err); });
以上是关于JavaScript进阶深入理解JavaScript中ES6的Promise的作用并实现一个自己的Promise的主要内容,如果未能解决你的问题,请参考以下文章