您的位置:首页 > Web前端 > JQuery

es6——promise(解决回调地狱的问题)及 jQuery 中的 promise 应用

2018-10-28 11:54 806 查看
版权声明:未经同意,不得随意转载转载 https://blog.csdn.net/lucky541788/article/details/83473401

注意:里面一些执行报错结果,是为了演示,故意写错地址

1. 首先,提出一个需求:要封装一个方法,使得能够读取文件,并将内容返回

先创建 3个 .txt 文件

1.txt/2.txt/3.txt
,作为我们要读取的文件,内容自己瞎编

  • fs 和 path 模块:
const fs = require('fs');
const path = require('path');
  • 这是普通读取文件的方式:
fs.readFile(path.join(__dirname, './files/1.txt'), 'utf-8', (err, dataStr) => {
if (err) throw err;
console.log(dataStr);
});
  • 升级:
    我们可以规定一下,callback 中,有两个参数,第一个参数,是失败的结果;第二个参数是成功的结果
    同时规定:如果成功后,返回的结果,应该位于 callback 参数的第二个位置,此时,第一个位置由于没有出错,所以放一个 null;如果失败了,则第一个位置放置 Error 对象,第二个位置放置 undefined
function readFile(fpath, callback) {
fs.readFile(fpath, 'utf-8', (err, dataStr) => {
// 如果报错了,则进入 if 分支
if (err) return callback(err);
// return 会返回 undefined
// return dataStr;
callback(null, dataStr);
})
}

/*var result = readFile(path.join(__dirname, './files/1.txt'));
console.log(result);*/

readFile(path.join(__dirname, './files/1.txt'), (err, dataStr) => {
// console.log(dataStr);
if (err) return console.log(err.message);
console.log(dataStr);
});

2. 其次,需求升级:先读取文件1,再读取文件2,最后读取文件3

const fs = require('fs');
const path = require('path');
// 为了方便初学者理解,在这里我把原来 callback 分为 succCB 和 errCB
function getFileByPath(fpath, succCB, errCB) {
fs.readFile(fpath, 'utf-8', (err, dataStr) => {
if (err) return errCB(err);
succCB(dataStr);
})
}
  • 好了,见证回调地狱的时候到了:由于现在是读取三个文件,可能没什么,假如一万个文件。。。。。。呵呵
// 回调地狱
getFileByPath(path.join(__dirname, './files/1.txt'), function (data) {
console.log(data);

getFileByPath(path.join(__dirname, './files/2.txt'), function (data) {
console.log(data);

getFileByPath(path.join(__dirname, './files/3.txt'), function (data) {
console.log(data);
});
});
});

3. 现在引入主题:Promise

使用 ES6 中的 Promise,来解决回调地狱的问题;
注意:promise 只是单纯的解决回调地狱问题,并不是解决代码量;

  1. Promise 是一个构造函数,可以 new Promise() 得到一个 Promise 的实例;
  2. 在 Promise 上,有两个函数,分别叫做 resolve(成功后的回调函数) 和 reject(失败后的回调函数)
  3. 在 Promise 构造函数的 Prototype 属性上,有一个 .then() 方法,也就是说,只要是 Promise 构造函数创建的实例,都可以访问到 .then() 方法
  4. Promise 表示一个异步操作;每当我们 new 一个 Promise 的实例,这个实例,就表示一个具体的异步操作;
  5. 既然 Promise 创建的实例,是一个异步操作,那么这个异步操作的结果,只能有两种状态:
      状态1:异步执行成功了,需要在内部调用 成功的回调函数 resolve 把结果返回给调用者;
    • 状态2:异步执行失败了,需要在内部调用 失败的回调函数 reject 把结果返回给调用者;
    • 由于 Promise 的实例,是一个异步操作,所以,内部拿到操作的结果后,无法使用 return 把操作结果返回给调用者;这时候,只能使用回调函数的形式,来把成功或失败的结果,返回给调用者;
  6. 可以在 new 出来的 Promise 实例上,调用 .then() 方法,【预先】为这个 Promise 异步操作,指定 成功(resolve) 和 失败(reject) 回调函数;

下面代码解释原理:

1

// 注意:这里 new 出来的 promise,只是代表 【形式上】的一个异步操作(空壳);
let promise = new Promise();

2

const fs = require('fs');

// 每当 new 一个 promise 实例的时候,就会立即执行这个异步操作中的代码
// 也就是说,new 的时候,除了能够得到一个 promise 实例之外,还会立即调用我们
// 为 Promise 构造函数传递的那个function,执行这个 function 中的异步操作代码;
let promise = new Promise(function () {
fs.readFile('./files/3.txt', 'utf-8', (err, dataStr) => {
if (err) throw err;
console.log(dataStr);
})
});


3

const fs = require('fs');

// 可以自己决定是否调用 Promise
function getFileByPath(fpath) {
let promise = new Promise(function () {
fs.readFile(fpath, 'utf-8', (err, dataStr) => {
if (err) throw err;
console.log(dataStr);
})
})
}

getFileByPath('./files/3.txt');


4

const fs = require('fs');

// 可以报具体错误
function getFileByPath(fpath) {
let promise = new Promise(function (resolve, reject) {
//*2
fs.readFile(fpath, 'utf-8', (err, dataStr) => {
/*if (err) throw err;
console.log(dataStr);*/
if (err) reject(err);
resolve(dataStr);
})
});
return promise;
}

let p=getFileByPath('./files/.txt');

// 第一个是 resolve,第二个是 reject
//*1
p.then(function (data) {
console.log('执行成功:'+data);
},function (err) {
console.log('执行失败:'+err.message);
});

注意:执行步骤是先

*1
*2

// 优化写法
getFileByPath('./files/.txt').then(function (data) {
console.log('执行成功:' + data);
}, function (err) {
console.log('执行失败:' + err.message);
});

解决回调地狱的问题:

const fs = require('fs');

function getFileByPath(fpath) {
let promise = new Promise(function (resolve, reject) {
fs.readFile(fpath, 'utf-8', (err, dataStr) => {
if (err) reject(err);
resolve(dataStr);
})
});
return promise;
}

// 注意:通过 .then 指定回调函数的时候,成功的函数,
// 必须传,但是失败的回调可以省略
// 在上一个 .then 中,返回一个新的 promise 实例,可以继续用下一个 .then 来处理
getFileByPath('./files/1.txt')
.then(function (data) {
console.log(data);

// 读取文件2,下面的以此类推
return getFileByPath('./files/2.txt')
})
.then(function (data) {
console.log(data);
return getFileByPath('./files/3.txt')
})
.then(function (data) {
console.log(data);
});

如果前面的 Promise 执行失败,我们不想让后续的 Promise 操作被终止,可以为每个 Promise 指定失败的回调

getFileByPath('./files/.txt')
.then(function (data) {
console.log(data);

// 读取文件2,下面的以此类推
return getFileByPath('./files/2.txt')
}, function (err) {
console.log('这是失败的结果:' + err);

// 读取文件2,下面的以此类推
return getFileByPath('./files/2.txt')
})
.then(function (data) {
console.log(data);
return getFileByPath('./files/3.txt')
})
.then(function (data) {
console.log(data);
});


如果后续的 Promise 执行,依赖于前面 Promise 执行的结果,如果前面的失败了,则后面的就没有执行下去的意义了,实现一旦有报错,则立即终止所有 Promise 的执行

getFileByPath('./files/1.txt')
.then(function (data) {
console.log(data);

// 读取文件2,下面的以此类推
return getFileByPath('./files/.txt')
})
.then(function (data) {
console.log(data);
return getFileByPath('./files/3.txt')
})
.then(function (data) {
console.log(data);
})
.catch(function (err) {
// catch 的作用:如果前面有任何的 Promise 执行失败,则立即终止所有
// 的 Promise 的执行,并立即进入 catch 去处理 Promise 中抛出的异常;
console.log('这是自己的处理方式:' + err.message);
});

jQuery 中的 promise 应用

$(function () {
$('#btn').on('click', function () {
$.ajax({
url: './data.json',
type: 'get',
dataType: 'json'
/*success: function (data) {
console.log(data);
}*/
})
// 不用 success 而是使用 promise 中的 .then
.then(function (data) {
console.log(data);
})
})
})
阅读更多
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: