Javascript 学习笔记 10
这期没有用疑问句当作标题,因为我盯着屏幕看了两个小时才看懂这个东西,实在没心情疑问了。
Promisification 是把回调异步变为 Promise 链的函数,这个转换的过程叫做 Promisify 。
早期 JS 还没有 Promise 的时候,人们采用 回调 (Callback) 的方式来进行异步操作,来实现异步中同步、同步中异步,所以你可以看见很多老 API 仍然在使用,比如 Node.js 。
但是这样容易导致回调地狱,所以 ECMAScript 才发布了个 Promise ,但是你有没有想过把回调异步变为 Promise 链呢?虽然 Node.js 较新版本中有 Promisify 相关的函数,但是这里我们要自己实现。
这次我们转换的例子为 Node.js 中的 fs.readFile 函数,它便是采用了回调异步的 API 之一,它的语法如下:
/* 语法 */
fs.readFile(文件地址, callback(err, result));
/* 实例 */
fs.readFile('./test.txt', (err, result) => {
if (err) throw new Error(err)
console.log(result);
});
我们接下来要把它变成这样:
fs.readFile('./test.txt')
.then(console.log, console.error);
废话不多说,直接开整:
var fs = require('fs');
function promisify(func) { // (*)
return function (...args) { // (**)
return new Promise((resolve, reject) => {
function callback(err, result) { // (***)
if (err) {
reject(err);
} else {
resolve(result);
}
}
args.push(callback); // (+)
func(...args); // (-)
});
};
}
const read = promisify(fs.readFile);
read('./Async/catch.js') // 这个是我的环境下的一个文件,不用在意这个
.then(console.log, console.error);
看起来很费解对吧,我们慢慢讲解,我把 Label 都写在了上述代码的注释中 (* - + 标记),大家一一对应就可以了。
( * )
传入一个回调函数,实现类似装饰器的功能
( ** )
...args 包含了 readFile 的两个参数,至于为什么写成这样,后面会用到
( *** )
这个函数是对应 readFile 的第二个回调函数
( + )
把回调函数塞进 args 里,这样就自动传入了回调函数,你只需要写文件地址就可以了。这时你也许会奇怪, err 和 result 谁来传入呢?我当时也卡在了这里,实际上你把回调函数带入 readFile 就知道了,这俩参数不需要你传入,是 Node.js 自动给你传入的
( - )
传入文件地址和回调函数,也就是调用了 readFile
所以我换个写法没准你就懂了:
var fs = require('fs');
function promisify(func) {
return function (file) {
return new Promise((resolve, reject) => {
func(file, (err, result) => {
if (err) {
reject(err);
} else {
resolve(result);
}
});
});
};
}
const read = promisify(fs.readFile);
read('./Async/catch.js')
.then(console.log, console.error);
行了,我觉得我讲的够清楚了,大家应该都能看懂,看不懂再来找我。