第二章 Promise 基本使用
1 基本编码流程
// 1) 实例化 Promise 对象, 指定执行器函数
let p = new Promise((resolve, reject) => {
// 2) 在执行器函数中启动异步任务
setTimeout(() => {
let n = Math.floor(Math.random() * 10); //随机生成一个数字
// 3) 根据结果做不同处理
if (n % 2 === 0) {
// 3.1) 如果 n 是偶数认为是成功的,调用 resolve(),传入成功的 value, 状态变为 resolved
resolve(n);
} else {
// 3.2) 如果 n 是奇数认为是失败的,调用 reject(),传入失败的 reason, 状态变为 rejected
reject(n);
}
}, 2000);
});
// 4) 指定成功或失败的回调函数,状态改变回调函数会执行
p.then(value => { // 状态是 resolved,调用此回调函数
console.log('成功的 value:'+value)
}, reason => { // 状态是 rejected,调用此回调函数
console.log('失败的 reason:' + reason);
});
我们也可以把上述操作封装在一个函数中,让函数返回一个 Promsie 对象。
function doDelay(time) {
// 1) 创建 Promise 对象, 并把创建的对象返回
return new Promise((resolve, reject) => {
// 2) 在执行器函数中启动异步任务
setTimeout(() => {
const time = Math.floor(Math.random() * 10); //随机生成一个数字
// 3) 根据结果做不同的处理
if (time % 2 === 0) {
// 3.1) 成功了就调用 resolve 并传入 value, 状态改为 resolved
resolve(time);
} else {
// 3.2) 失败了就调用 reject 并传入 reason,状态改为 rejected
reject(time);
}
}, time);
});
}
// 调用函数返回一个 Promise 对象
const p = doDelay(2000);
// 指定成功或失败的回调函数,状态改变回调函数会执行
p.then(value => { // 状态是 resolved,调用此回调函数
console.log('成功的 value:'+value)
}, reason => { // 状态是 rejected,调用此回调函数
console.log('失败的 reason:' + reason);
});
2 案例:使用 Promise 封装 Ajax
/**
* 可复用的 Ajax 请求函数, 只实现 GET 请求
* @param url 请求地址
* @return Promsie 对象
*/
function promiseAjax(url, data) {
return new Promise((resolve, reject) => {
// 创建 XMLHttpRequest对象
const xhr = new XMLHttpRequest();
// 监听状态变化事件
xhr.onreadystatechange = () => {
// 如果响应结束
if (xhr.readyState === 4) {
// 响应状态码是2xx则表示成功(resolved),否则错误(rejected)
if (xhr.status >= 200 && xhr.status < 300) {
resolve(xhr.responseText);
} else {
reject(new Error('请求失败:status:' + xhr.status));
}
}
};
// 初始化请求
xhr.open('GET', url);
// 发送请求
xhr.send();
})
}
// 调用函数
promiseAjax('https://api.apiopen.top/getAllUrl').then(data => {
console.log(data);
}, error => {
console.log(error);
});
3 案例:使用 Promsie 封装文件读取(Node)
// 引入模块
const fs = require('fs');
// 创建 Promise 对象
let p = new Promise((resolve, reject) => {
// 在执行器函数中启动异步任务(异步读取文件)
fs.readFile('./content.txt', (err, data) => {
// 根据读取结果进行不同的处理
if (err) {
reject(err);
} else {
resolve(data)
}
});
});
// 调用 then 方法
p.then((data) => {
console.log('文件内容:\n' + data);
}, (error) => {
console.log('读取失败:\n' + error);
});
我们仍然可以定义一个可复用的函数,返回 Promise 对象
/**
* 读取文件
* @param {string} filename
* @param {Promise} 一个 Promise 对象
*/
function promiseReadFile(filename){
// 引入模块
const fs = require('fs');
// 创建 Promise 对象 并返回
return new Promise((resolve, reject) => {
// 在执行器函数中启动异步任务(异步读取文件)
fs.readFile(filename, (err, data) => {
// 根据读取结果进行不同的处理
if (err) {
reject(err);
} else {
resolve(data)
}
});
});
}
// 读取文件操作
promiseReadFile('./content.txt').then((data) => {
console.log('文件内容:\n' + data);
}, (error) => {
console.log('读取失败:\n' + error);
});
Node 中有一个核心模块 util,util 中有一个方法 promisify,该方法可以传入一个遵循常见的错误优先的回调风格的函数(即以 (err, value) => ...
回调作为最后一个参数),然后得到一个返回 Promise 对象的函数。
// 导入模块
const util = require('util');
const fs = require('fs');
// 使用 util.promisify 处理 fs.readFile, 得到的 readFile 就是一个返回 Promise 对象的函数
const readFile = util.promisify(fs.readFile);
// 调用 readFile 函数读取文件
readFile('./content.txt').then((data) => {
console.log('读取内容如下:\n' + data);
}, (error) => {
console.log('读取失败:' + error);
});