promsie进阶
废话不多说,直接上干货。
1. promise 相关问题
(1)使用方式问题
then 里传两个回调函数
const promise = new Promise((resolve, reject) => {
resolve(a);
});
promise.then(
(res) => {
console.log('resolve', res);
},
(err) => {
console.log('reject', err.message);
}
);
// reject a is not defined
then存在两个参数,第一个为成功的回调函数,第二个为错误的回调函数。
promise then的第二个回调函数等同于promise.catch()。
.then .catch 的方式
promise
.then(() => {})
.catch(() => {});
推荐使用 .then .catch 的方式。
(2)状态固化问题
promsie 使用 resolve 或 reject时,状态发生固化,意味着状态不再发生变化。
状态已经固化成成功状态时,catch并不能捕获到当前的异常。
let promise = new Promise((resolve, reject) => {
resolve('ok');
console.log(a);
});
promise
.then(res => {
console.log(res);
})
.catch(err => {
console.log(err);
});
// ok
(3)状态依赖问题
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
reject(new Error('fail'))
}, 3000);
});
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(p1);
}, 1000)
});
p2
.then(res => {
console.log(res);
})
.catch(err => {
console.log(err.message);
})
// fail
p1 作为参数传递给 p2 时,会导致 p2 状态无效。
p2 状态依赖 p1 状态,会等待p1状态完成后再固化状态,这是底层帮我们处理的事情。
(4)执行问题
const p1 = new Promise((resolve, reject) => {
resolve(1);
console.log('2');
});
p1.then(res => {
console.log(res);
});
// '2'
// 1
resolve、reject 不会终止函数执行,只是改变 promise 函数的状态。
2. promise 的方法
(1)Promise.all()、Promise.race()
promise 通过 Promise.all 和 Promise.race 方法,来管理异步回调之间的关系。
Promise.all()
异步操作全部成功的时候返回成功,返回所有成功的promise的值。
如果全部都失败,返回第一个触发失败的promsie的信息。
如果有一个异步函数失败就失败,返回错误的promise的信息。
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1);
}, 1000);
});
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(2);
}, 3000);
});
const p3 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(3);
}, 2000);
});
Promise.all([p1, p2, p3])
.then(arr => {
console.log(arr);
})
.catch(err => {
console.log(err);
});
// [1, 2, 3]
Promise.race()
异步操作只有一个成功就成功,返回第一个执行成功的promise的值。
异步操作失败,返回失败的promise的值。
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1);
}, 1000);
});
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(2);
}, 3000);
});
const p3 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(3);
}, 2000);
});
Promise.race([p1, p2, p3])
.then(res => {
console.log(res);
})
.catch(err => {
console.log(err);
});
// 1
(2)Promise.resolve()
直接返回一个promise对象。
let thenable = {
then: function (resolve) {
resolve(42);
}
};
let p1 = Promise.resolve(thenable);
p1.then(val => console.log(val)); // 42
thenable: 绑定了 then 的对象都可以叫做thenable。
let promise = Promise.resolve('hello');
promise
.then((val) => {
console.log(val);
});
// hello
(3)Promise.reject()
const promise = Promise.reject('123');
promise
.then(res => {
console.log('then', res);
})
.catch(err => {
console.log('catch', err);
});
3. promise 处理回调函数
根目录下存在 name.txt、number.txt、score.txt 文件,存放接下来需要读取的路径,如下图所示。
score.txt 文件中,存放需要打印的信息。
function readFile (path) {
return new Promise((resolve, reject) => {
fs.readFile(path, 'utf-8', (err, data) => {
if (data) {
resolve(data);
return;
}
console.log(err);
});
});
}
readFile('./name.txt')
.then(data => readFile(data))
.then(data => readFile(data))
.then(data => console.log(data)); // 90分
我们可以通过 promise 包装回调函数,将异步回调函数 promise 化。
4. 自定义实现 promisify
当存在很多异步的回调函数时,每次 promise 化都很麻烦,为此可以定义一个函数。
function promisify (func) {
return (...args) => {
return new Promise((resolve, reject) => {
func(...args, (err, data) => {
if (err) {
return reject(err);
}
resolve(data);
});
});
}
}
接下来,使用就很简单啦。
const readFile = 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)); // 90分
promisify 函数在 node 的8.0版本之后,已经被封装到 util 中,可以直接使用。
const fs = require('fs'),
util = require('util');
const 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));
还有一个问题,假如想把 fs 模块的所有方法都 promise 化,应该怎么做?
在这里提供一种解决思路,使用 Object.entries 获取模块的所有方法遍历处理。
const fs = require('fs');
function promisify (func) {
return (...args) => {
return new Promise((resolve, reject) => {
func(...args, (err, data) => {
if (err) {
return reject(err);
}
resolve(data);
});
});
}
}
function promisifyAll (obj) {
for (let [key, func] of Object.entries(obj)) {
if (typeof func === 'function') {
obj[key + 'Promise'] = promisify(func);
}
}
}
promisifyAll(fs);
fs.readFilePromise('./name.txt', 'utf-8')
.then(data => fs.readFilePromise(data, 'utf-8'))
.then(data => fs.readFilePromise(data, 'utf-8'))
.then(data => console.log(data));
5. 总结
本篇文章对 promise 进行了补充讲解,希望可以帮助到大家。