1. Promise的使用
如果
Promise函数执行时抛出错误,则会改变状态为reject,继而调用reject回调函数
let promise = new Promise((resolve, reject) => {
resolve(a); // 此时 a 未被声明,未被定义
})
promise.then(
(value) => {
console.log("resolve:" + value);
},
(reason) => {
console.log("reject:" + reason); // 此时错误被捕获
}
);
1.1 Promise.prototype.catch()
【 作用 】 用于指定发生错误时的回调函数,返回一个Promise对象
【 本质 】 .catch()是.then(null, reject) 或 .then(undefined, reject) 的另一种写法
promise.then(null, (reason) => { //不写回调函数的时候,填null
console.log('reject: ', reason)
});
// 等同于
promise.catch(function(reason) {
console.log('reject: ', reason)
});
捕获异常时推荐的写法
promise.then(() => {
}).catch(() => {
})
【 注意 】
.then()方法指定的回调函数,如果运行中抛出错误,也会被catch()方法捕获
1.2 固化
【 特点 】
- Promise 状态固化后不会改变,状态固化后,后续代码的错误不会被
catch捕获;但是代码会被执行,也就是说resolve和reject不会终止整个函数执行
let promise = new Promise((resolve, reject) => {
// 状态固化
resolve("ok");
// reject("no");
console.log(a); // 不论是 resolve 还是 reject ,后续的代码都会被执行,但是错误不会被catch捕获
});
promise
.then((value) => {
console.log(value);
})
.catch((error) => {
console.log(error);
});
【 注意 】
- 类似于冒泡的特性,异常会被一层一层的冒泡直到 catch 捕获
then()什么参数都不传,会被忽略掉
let promise = new Promise((resolve, reject) => {
console.log(a)
})
promise
.then((value) => {
console.log(value);
return "hello";
})
.then()
.then() // .then什么参数都不传,会被忽略掉,相当于没有添加这个.then
.then((value) => {
console.log("then: ", value);
})
.catch((error) => {
// 异常会被一层一层的冒泡直到 catch 捕获
console.log(error);
});
1.3 状态的依赖
状态失效
- 当一个
Promise的状态被另一个Promise状态引用时,被引用的Promise状态决定了第一个Promise的状态,在此之前该Promise状态都是无效的
const p1 = new Promise((resolve, reject) => {
setTimeout(function() {
reject(new Error('fail'));
// resolve('ok') // 打印 ok
}, 3000)
})
// p1 作为参数传递给 p2 的时候,此时 p2 的状态无效,取决于当前 p1 的状态,只有 p1 拿到结果之后才会执行 p2
const p2 = new Promise((resolve, reject) => {
setTimeout(function() {
resolve(p1);
}, 1000)
})
p2.then((result) => console.log(result))
.catch((error) => console.log(error))
2. 回调的管理
Tip
constructor上的方法
2.1 Pomise.all()
管理多个Promise实例,参数是具备iterator接口,一般来说是数组
【 用法 】
- 所有都成功,返回一个按
promise顺序执行的结果的数组 - 如果有失败,进行了
reject就会被catch捕获,返回第一个失败对象的错误信息,没有reject则会返回数组,对应失败的那个数组的值为undefined
const fs = require('fs');
// promise 包装异步操作
let promise1 = new Promise((resolve, reject) => {
fs.readFile('./name.txt', 'utf-8', (err, data) => {
if (err) {
reject(err);
}
resolve(data);
});
})
let promise2 = new Promise((resolve, reject) => {
fs.readFile('./number.txt', 'utf-8', (err, data) => {
if (err) {
reject(err);
}
resolve(data);
});
})
let promise3 = new Promise((resolve, reject) => {
fs.readFile('./score.txt', 'utf-8', (err, data) => {
if (err) {
reject(err);
}
resolve(data);
});
})
const p = Promise.all([promise1, promise2, promise3]);
p.then(res => console.log(res))
.catch(err => console.log(err));
【 证明 】 当有失败时被
catch捕获,返回第一个失败对象的错误信息
let promise1 = new Promise((resolve, reject) => {
setTimeout(function() {
reject('promise1: 1000ms');
// resolve('promise1: 1000ms');
}, 1000)
})
let promise2 = new Promise((resolve, reject) => {
setTimeout(function() {
reject('promise2: 2000ms');
// resolve('promise2: 2000ms');
}, 2000)
})
let promise3 = new Promise((resolve, reject) => {
setTimeout(function() {
reject('promise3: 3000ms');
// resolve('promise3: 3000ms');
}, 3000)
})
// 如果都成功,拿到所有成功的值组成一个数组返回
// 如果有失败并被 .catch,返回第一个触发失败的promise
let p = Promise.all([promise1, promise2, promise3]);
p.then(res => console.log(res))
.catch(err => console.log(err))
1.2 Promise.race()
【 用法 】 不论成功还是失败,都会返回一个promise对象,返回最先执行完成的结果
let promise1 = new Promise((resolve, reject) => {
setTimeout(function() {
// reject('promise1: 1000ms');
resolve('promise1: 1000ms');
}, 4000)
})
let promise2 = new Promise((resolve, reject) => {
setTimeout(function() {
// reject('promise2: 2000ms');
resolve('promise2: 2000ms');
}, 2000)
})
let promise3 = new Promise((resolve, reject) => {
setTimeout(function() {
// reject('promise3: 3000ms');
resolve('promise3: 3000ms');
}, 3000)
})
// 返回第一个执行完成的结果
let p = Promise.race([promise1, promise2, promise3]);
p.then(res => console.log(res))
.catch(err => console.log(err))
3. Promise.resolve()
Tip:
constructor上的方法
【 用法 】 可以把一个 thenable对象转为Promise 对象
- 如果有
then方法,可以直接通过Promise.resolve部署thenable,此时promise的状态是根据then中的状态决定的
3.1 部署 thenable
Tip: 具有
then属性的对象都可以叫thenable
let thenable = {
then(resolve, reject) {
resolve(2);
// reject(42)
},
};
// 通过 Promise.resolve(),把一个对象转成 Promise 对象
let promise = Promise.resolve(thenable);
promise
.then((value) => {
console.log(value);
})
.catch((error) => {
console.log(error);
});
4.回调地狱的优化
let fs = require('fs');
fs.readFile('./name.txt', 'utf-8', (err, data) => {
if (err) {
console.log(err)
}
if (data) {
fs.readFile(data, 'utf-8', (err, data) => {
console.log(data);
fs.readFile(data, 'utf-8', (err, data) => {
console.log(data);
})
})
}
console.log(data);
});
优化后:
function readFile(path) {
let fs = require("fs");
return new Promise((resolve, reject) => {
fs.readFile(path, "utf-8", (error, data) => {
if (error) {
console.log(`${error}`);
}
resolve(data);
});
});
readFile("./name.txt")
.then((value) => {
readFile(value);
})
.then((value) => {
readFile(value);
})
.then((value) => {
readFile(value);
})
.catch((error) => {
console.log(error);
});
}
5. 自定义promisify
5.1 实现promisify
【 用法 】 将函数 Promise 化
const fs = require('fs');
const util = require('util');
function promisify(fn) {
return function (...args) {
return new Promise((resolve, reject) => {
// 执行原本的函数 执行回调函数
fn(...args, (error, data) => {
if (error) {
return reject(error);
}
resolve(data);
})
})
}
}
// 传入一个函数作为参数
let readFile = promisify(fs.readFile);
// node 中提供了 promisify 方法
let readFile = util.promisify(fs.readFile);
readFile('./name.txt', 'utf-8')
.then(data => readFile(data, 'utf-8'))
.then(data => readFile(data, 'utf-8'))
.then(data => console.log(data))
实现promisifyAll
【 用法 】 将所有fs模块上的方法都变成Promise化的方法
const fs = require('fs');
function promisify(func) {
return function(...arg) {
return new Promise((resolve, reject) => {
// 执行原本的函数 执行回调函数
func(...arg, (err, data) => {
if (err) {
reject(err);
} else {
resolve(data);
}
})
})
}
}
// fs.writeFile 变成 fs.writeFileAsync
// fs.readFile 变成 fs.readFileAsync 以此类推
function promisifyAll(obj) {
for (let [key, fn] of Object.entries(obj)) {
if (typeof fn === 'function') {
obj[key + 'Async'] = promisify(fn);
}
}
return obj;
}
// 或者
function promisifyAll(fns) {
Object.keys(fns).map((fnName) => {
if (typeof fns[fnName] === 'function') {
fns[fnName + 'Async'] = this.promisify(fns[fnName]);
}
})
return fns;
}
promisifyAll(fs);
fs.readFileAsync('./name.txt', 'utf-8')
.then(data => fs.readFileAsync(data, 'utf-8'))
.then(data => fs.readFileAsync(data, 'utf-8'))
.then(data => console.log(data))