【JavaScript进阶】深入理解JavaScript中ES6的Promise的作用并实现一个自己的Promise
1.Promise的基本使用
// 需求分析: 封装一个方法用于读取文件路径,返回文件内容
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);
})
// 2. 使用ES6中的Promise对象,来解决回调地狱的问题
// 本质:本质是为了解决回调地狱的问题,并不能帮我们减少代码量
// 转换成为一个串联的函数串
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的更多相关文章
- JavaScript 开发进阶:理解 JavaScript 作用域和作用域链(转载 学习中。。。)
作用域是JavaScript最重要的概念之一,想要学好JavaScript就需要理解JavaScript作用域和作用域链的工作原理.今天这篇文章对JavaScript作用域和作用域链作简单的介绍,希望 ...
- JavaScript 开发进阶:理解 JavaScript 作用域和作用域链
作用域是JavaScript最重要的概念之一,想要学好JavaScript就需要理解JavaScript作用域和作用域链的工作原理.今天这篇文章对JavaScript作用域和作用域链作简单的介绍,希望 ...
- JavaScript大杂烩1 - 理解JavaScript的类型系统
随着硬件水平的逐渐提高,浏览器的处理能力越来越强大,本人坚信,客户端会越来越瘦,瘦到只用浏览器就够了,服务端会越来越丰满:虽然很多大型的程序,比如3D软件,客户端仍然会存在,但是未来的主流必将是浏览器 ...
- 深入理解JavaScript系列+ 深入理解javascript之执行上下文
http://www.cnblogs.com/TomXu/archive/2011/12/15/2288411.html http://blog.csdn.net/hi_kevin/article/d ...
- JavaScript 进阶教程一 JavaScript 中的事件流 - 事件冒泡和事件捕获
先看下面的示例代码: <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Jav ...
- JavaScript大杂烩6 - 理解JavaScript中的this
在JavaScript开发中,this是很常用的一个关键字,但同时也是一个很容易引入bug的一个关键字,在这里我们就专门总结一下页面中可能出现的this关键字(包括几种在其他页面文件中出现的this) ...
- 理解React中es6方法创建组件的this
首发于:https://mingjiezhang.github.io/(转载请说明此出处). 在JavaScript中,this对象是运行时基于函数的执行环境(也就是上下文)绑定的. 从react中的 ...
- 【JavaScript】深入理解JavaScript之强大的原型和原型链
由于JavaScript是唯一一个被广泛使用的基于原型继承的语言,所以理解两种继承模式的差异是需要一定时间的,今天我们就来了解一下原型和原型链. AD: hasOwnProperty函数: hasOw ...
- JavaScript篇 深入理解JavaScript函数
JavaScript中的函数 1. 函数的定义 两种定义形式: 通过函数定义表达式来定义 通过函数声明语句来定义 函数声明语句定义一个函数 //计算阶乘的递归函数 function factorial ...
随机推荐
- Data Url生成工具之HTML5 FileReader实现
百度经验版本号:怎样用HTML5的FileReader生成Data Url 上一篇讲了:用Visual Studio 2010编写Data Url生成工具C#版 今天用HTML5 FileReader ...
- mysql创建用户,并授予权限
mysql> GRANT ALL PRIVILEGES ON *.* TO jiqing@"%" IDENTIFIED BY '123456'; Query OK, 0 ro ...
- luogu 3690 【模板】 Link Cut Tree (动态树)
原来的代码有一些问题. 主要是对于不一定存在的边如何去判断,首先要保证在一个splay里,然后保证彼此之间直接联通且x的右儿子是空的 #include<iostream> #include ...
- B1299 [LLH邀请赛]巧克力棒 博弈论
这个题一看就是nim游戏的变形.每次先手取出巧克力就是新建一个nim,但假如先手取一个为0的而且无论后手怎么取剩下的都无法为零就行了.然后用dfs跑. 题干: Description TBL和X用巧克 ...
- JSP-Runoob:JSP 语法
ylbtech-JSP-Runoob:JSP 语法 1.返回顶部 1. JSP 语法 本小节将会简单地介绍一下JSP开发中的基础语法. 脚本程序 脚本程序可以包含任意量的Java语句.变量.方法或表达 ...
- 53. 部门信息显示 EXTJS 单击树节点
1. /** * @author sux * @time 2011-1-14 * @desc 部门信息显示 */ deptInfoGridPanel = Ext.extend(Ext.grid.Edi ...
- IOException 简单解决方法
java.lang.IllegalStateException异常解决方法 这个异常大多数是由文件读取,下载时抛出,但是偶尔也会由类型转换时异常抛出此异常. 错误:Optional int param ...
- quill支持json吗
RT quill目前的驱动(2.4.2版本)不支持json,等待作者更新版本吧
- GoLang 编译exe添加ICO图标
我们在做Go开发的时候在Window平台下编译出来的exe后大部分都是没有图标,看起来很难看.下面我们说下如何添加一个图标. 1.首先在根目录下,exe的同级目录下创建.rc文件, IDI_ICON1 ...
- scrapy 框架持久化存储
1.基于终端的持久化存储 保证爬虫文件的parse方法中有可迭代类型对象(通常为列表或字典)的返回,该返回值可以通过终端指令的形式写入指定格式的文件中进行持久化操作. # 执行输出指定格式进行存储:将 ...
