当前位置:网站首页>Promise入门到精通(1.5w字详解)
Promise入门到精通(1.5w字详解)
2022-07-30 17:00:00 【[email protected]】
Promise详解
Promise的出现
我们在此之前,要知道什么是同步,异步,在这里我就不过多篇幅地去整理了
我们知道,我们异步编程的场景,⼤部分情况都是通过回调函数来进⾏
那么,什么是回调?
回调的定义
把函数 A 传给另一个函数 B 调用,那么函数 A 就是回调函数。
例如在浏览器中发送 ajax 请求,就是常⻅的⼀个异步场景,发送请求后,需要等待一段时间,等服务端响应之后我们才能拿到结果。如果我们希望在异步结束之后执⾏某个操作,就只能通过回调函数这样的⽅式进⾏操作。
let dynamicFunc = function (callback) {
setTimeout(function () {
callback();
}, 1000);
};
dynamicFunc(function () {
console.log('shaka');
});
例如上⾯这个例⼦,dynamicFunc 就是⼀个异步函数,⾥⾯ setTimeout 会在 1s 之后调⽤传⼊的 callback 函数。按照上⾯的调⽤⽅式,最终 1s 之后,会打印 shaka 这个结果。
回调的缺点
回调的写法比较直观,不需要 return,层层嵌套即可。但也存在两个问题:
- 如果嵌套过深,则会出现回调地狱的问题。
- 不同的函数,回调的参数,在写法上可能不一致,导致不规范、且需要单独记忆。
我们来具体看看这两个问题。
如果多个异步函数存在依赖关系(比如,需要等第一个异步函数执行完成后,才能执行第二个异步函数;等第二个异步函数执行完毕后,才能执行第三个异步函数),就需要多个异步函数进⾏层层嵌套,⾮常不利于后续的维护,而且会导致回调地狱的问题。
关于回调地狱,我们来举一个形象的例子:
假设买菜、做饭、洗碗、倒厨余垃圾都是异步的。
但真实的场景中,实际的操作流程是:买菜成功之后,才能开始做饭。做饭成功后,才能开始洗碗。洗碗完成后, 再倒厨余垃圾。这里的一系列动作就涉及到了多层嵌套调用,也就是回调地狱。
关于回调地狱,我们来看看几段代码举例。
1.1、定时器的代码举例:(回调地狱)
setTimeout(() => {
//第一层回调
console.log('延迟1s后输出')
setTimeout(() => {
//第二层回调
console.log('延迟2s后输出')
setTimeout(() => {
//第三层回调
console.log('延迟3s后输出');
}, 3000)
}, 2000)
}), 1000
1.2、Node.js 读取文件的代码举例:(回调地狱)
fs.readFile(A, 'utf-8', function (err, data) {
fs.readFile(B, 'utf-8', function (err, data) {
fs.readFile(C, 'utf-8', function (err, data) {
fs.readFile(D, 'utf-8', function (err, data) {
console.log('shaka:' + data);
});
});
});
});
上面代码的逻辑为:先读取 A 文本内容,再根据 A 文本内容读取 B,然后再根据 B 的内容读取 C。为了实现这个业务逻辑,上面的代码就很容易形成回调地狱。
1.3、ajax 请求的代码举例:(回调地狱)
// 伪代码
ajax('a.json', (res1) => {
console.log(res1);
ajax('b.json', (res2) => {
console.log(res2);
ajax('c.json', (res3) => {
console.log(res3);
});
});
});
2、回调的写法不一致问题:
// Node.js 读取文件时,成功回调和失败回调,是通过 error参数来区分
readFile('d:\\readme.text', function (err, data) {
if (error) {
console.log('文件读取失败');
} else {
console.log('文件读取成功');
}
});
// jQuery的 ajax 写法中,成功回调和失败回调,是通过两个回调函数来区分
$.ajax({
url: '/ajax.json',
success: function (response) {
console.log('文件读取成功');
},
error: function (err) {
console.log('文件读取失败');
},
});
我们可以看到,上面的代码中,成功回调和失败回调,写法不统一,需要单独记忆,容易出错。
小结:
- 代码耦合性太强,牵一发而动全身,难以维护
- 大量冗余的代码相互嵌套,代码的可读性变差
在 ES5 中,当进行多层嵌套回调时,会导致代码层次过多,很难进行后续维护和二次开发;而且会导致回调地狱的问题。ES6 中的 Promise 就可以解决这些问题。
Promise的介绍
- Promise 是一个构造函数
- 我们可以创建 Promise 的实例 const p = new Promise()
- new 出来的 Promise 实例对象,代表一个异步操作
- Promise.prototype 上包含一个 .then() 方法
- 每一次 new Promise() 构造函数得到的实例对象
- 都可以通过原型链的方式访问到 .then() 方法,例如 p.then()
- .then() 方法用来预先指定成功和失败的回调函数
- p.then(成功的回调函数,失败的回调函数)
- p.then(result => { }, error => { })
- 调用 .then() 方法时,成功的回调函数是必选的、失败的回调函数是可选的
Promise 对象, 可以用同步的表现形式来书写异步代码(也就是说,代码看起来是同步的,但本质上的运行过程是异步的)。使用 Promise 主要有以下好处:
- 1、可以很好地解决回调地狱的问题(避免了层层嵌套的回调函数)。
- 2、语法简洁、可读性强,便于后期维护。
- 3、Promise 对象提供了简洁的 API,使得管理异步操作更加容易。比如多任务等待合并。
// 伪代码1
myPromise()
.then(
function () {
},
function () {
}
)
.then(
function () {
},
function () {
}
)
.then(
function () {
},
function () {
}
);
// 伪代码2
是时候展现真正的厨艺了().然后(买菜).然后(做饭).然后(洗碗);
上面的伪代码可以看出,即便在业务逻辑上是层层嵌套,但是代码写法上,却十分优雅,也没有过多的嵌套。
以上也说了Promise的步骤
(1)通过 new Promise()
构造出一个 Promise 实例。Promise 的构造函数中传入一个参数,这个参数是一个函数,该函数用于处理异步任务。
(2)函数中传入两个参数:resolve 和 reject,分别表示异步执行成功后的回调函数和异步执行失败后的回调函数。代表着我们需要改变当前实例的状态到已完成或是已拒绝。
(3)通过 promise.then() 和 promise.catch() 处理返回结果(这里的 promise
指的是 Promise 实例)。
promise 的 3 个状态
初始化(等待中):pending
成功:fulfilled
失败:rejected
当 new Promise()执行之后,promise 对象的状态会被初始化为pending
,这个状态是初始化状态。new Promise()
这行代码,括号里的内容是同步执行的。括号里可以再定义一个 异步任务的 function,function 有两个参数:resolve 和 reject。如下:
如果请求成功了,则执行 resolve(),此时,promise 的状态会被自动修改为 fulfilled。
如果请求失败了,则执行 reject(),此时,promise 的状态会被自动修改为 rejected
(2)promise.then()方法:只有 promise 的状态被改变之后,才会走到 then 或者 catch。也就是说,在 new Promise()的时候,如果没有写 resolve(),则 promise.then() 不执行;如果没有写 reject(),则 promise.catch() 不执行。
then()
括号里面有两个参数,分别代表两个函数 function1 和 function2:
如果 promise 的状态为 fulfilled(意思是:如果请求成功),则执行 function1 里的内容
如果 promise 的状态为 rejected(意思是,如果请求失败),则执行 function2 里的内容
另外,resolve()和 reject()这两个方法,是可以给 promise.then()传递参数的。
关于 promise 的状态改变,以及如何处理状态改变,伪代码及注释如下:
// 创建 promise 实例
let promise = new Promise((resolve, reject) => {
//进来之后,状态为pending
console.log('同步代码'); //这行代码是同步的
//开始执行异步操作(这里开始,写异步的代码,比如ajax请求 or 开启定时器)
if (异步的ajax请求成功) {
console.log('333');
resolve('请求成功,并传参'); //如果请求成功了,请写resolve(),此时,promise的状态会被自动修改为fulfilled(成功状态)
} else {
reject('请求失败,并传参'); //如果请求失败了,请写reject(),此时,promise的状态会被自动修改为rejected(失败状态)
}
});
console.log('222');
//调用promise的then():开始处理成功和失败
promise.then(
(successMsg) => {
// 处理 promise 的成功状态:如果promise的状态为fulfilled,则执行这里的代码
console.log(successMsg, '成功了'); // 这里的 successMsg 是前面的 resolve('请求成功,并传参') 传过来的参数
},
(errorMsg) => {
//处理 promise 的失败状态:如果promise的状态为rejected,则执行这里的代码
console.log(errorMsg, '失败了'); // 这里的 errorMsg 是前面的 reject('请求失败,并传参') 传过来的参数
}
);
Promise 的状态一旦改变,就不能再变
代码举例:
const p = new Promise((resolve, reject) => {
resolve(1); // 代码执行到这里时, promise状态是 fulfilled
reject(2); // 尝试修改状态为 rejected,是不行的。因为状态执行到上一行时,已经被改变了。
});
p.then((res) => {
console.log(res);
}).catch((err) => {
console.log(err);
});
上方代码的打印结果是 1,而不是 2,详见注释。
Promise 的状态改变,是不可逆的
小结
1、promise 有三种状态:等待中、成功、失败。等待中状态可以更改为成功或失败,已经更改过状态后⽆法继续更改(例如从失败改为成功)。
2、promise 实例中需要传⼊⼀个函数,这个函数接收两个参数,执⾏第⼀个参数之后就会改变当前 promise 为「成功」状态,执⾏第⼆个参数之后就会变为「失败」状态。
3、通过 .then ⽅法,即可在上⼀个 promise 达到成功时继续执⾏下⼀个函数或 promise。同时通过 resolve 或 reject 时传⼊参数,即可给下⼀个函数或 promise 传⼊初始值。
4、失败的 promise,后续可以通过 promise 自带的 .catch ⽅法或是 .then ⽅法的第⼆个参数进⾏捕获。
封装定时器
传统写法
写法 1:
// 定义一个异步的延迟函数:异步函数结束1秒之后,再执行cb回调函数
function fun1(cb) {
setTimeout(function () {
console.log('即将执行cb回调函数');
cb();
}, 1000);
}
// 先执行异步函数 fun1,再执行回调函数 myCallback
fun1(myCallback);
// 定义回调函数
function myCallback() {
console.log('我是延迟执行的cb回调函数');
}
写法 2:(精简版,更常见)
// 定义一个异步的延迟函数:异步函数结束1秒之后,再执行cb回调函数
function fun1(cb) {
setTimeout(cb, 1000);
}
// 先执行异步函数fun1,再执行回调函数
fun1(function () {
console.log('我是延迟执行的cb回调函数');
});
上⾯的例⼦就是最传统的写法,在异步结束后通过传入回调函数的方式执⾏函数。
学习 Promise 之后,我们可以将这个异步函数封装为 Promise,如下。
Promise 写法
function myPromise() {
return new Promise((resolve) => {
setTimeout(resolve, 1000);
});
}
/* 【重要】上面的 myPromise 也可以写成: function myPromise() { return new Promise((resolve) => { setTimeout(() => { resolve(); }, 1000); }); } */
// 先执行异步函数 myPromise,再执行回调函数
myPromise().then(() => {
console.log('我是延迟执行的回调函数');
});
读取文件
传统写法
//读取文件 1.txt
fs.readFile('./files/1.txt', 'utf8', (err1, r1) => {
if (err1) return console.log(err.message);//读取文件1失败
console.log(r1);//读取文件1成功
//读取文件 2.txt
fs.readFile('./files/2.txt', 'utf8', (err2, r2) => {
if (err2) return console.log(err.message);//读取文件2失败
console.log(r2);//读取文件2成功
//读取文件 3.txt
fs.readFile('./files/3.txt', 'utf8', (err3, r3) => {
if (err3) return console.log(err.message);//读取文件3失败
console.log(r3);//读取文件3成功
})
})
})
基于 then-fs 读取文件内容
由于 node.js 官方提供的 fs 模块仅支持以回调函数的方式读取文件,不支持 Promise 的调用方式。因此,需要先运行如下的命令,安装 then-fs 这个第三方包,从而支持我们基于 Promise 的方式读取文件的内容:
首先先安装一下
调用 then-fs 提供的 readFile() 方法,可以异步地读取文件的内容,它的返回值是 Promise 的实例对象。因此可以调用 .then() 方法为每个 Promise 异步操作指定成功和失败之后的回调函数。示例代码如下:
import thenFs from 'then-fs'
thenFs.readFile('./files/1.txt', 'utf8').then((r1) => {
console.log(r1)})
thenFs.readFile('./files/2.txt', 'utf8').then((r2) => {
console.log(r2)})
thenFs.readFile('./files/3.txt', 'utf8').then((r3) => {
console.log(r3)})
上述的代码无法保证文件的读取顺序,需要做进一步的改进!
Promise进行改进
import thenFs from 'then-fs'
thenFs
.readFile('./files/11.txt', 'utf8')
.then((r1) => {
console.log(r1)
return thenFs.readFile('./files/2.txt', 'utf8')
})
.then((r2) => {
console.log(r2)
return thenFs.readFile('./files/3.txt', 'utf8')
})
.then((r3) => {
console.log(r3)
})
在 Promise 的链式操作中如果发生了错误,可以使Promise.prototype.catch 方法进行捕获和处理
import thenFs from 'then-fs'
thenFs
.readFile('./files/11.txt', 'utf8')
.then((r1) => {
console.log(r1)
return thenFs.readFile('./files/2.txt', 'utf8')
})
.then((r2) => {
console.log(r2)
return thenFs.readFile('./files/3.txt', 'utf8')
})
.then((r3) => {
console.log(r3)
})
.catch(err => {
//捕获第一行发生的错误,并输出
console.log(err.message);
})
如果不希望前面的错误导致后续的 .then 无法正常执行,则可以将 .catch 的调用提前,示例代码如下:
import thenFs from 'then-fs'
thenFs
.readFile('./files/11.txt', 'utf8')
.catch((err) => {
console.log(err.message)
})
.then((r1) => {
console.log(r1)
return thenFs.readFile('./files/2.txt', 'utf8')
})
.then((r2) => {
console.log(r2)
return thenFs.readFile('./files/3.txt', 'utf8')
})
.then((r3) => {
console.log(r3)
})
Promise 的常用 API 分类
Promise 的实例方法
实例方法:我们需要先 new 一个 promise 实例对象,然后通过 promise 对象去调用 then
、catch
、finally
方法。这几个方法就是 Promise 的实例方法。
Promise 的自带 API 提供了如下实例方法:
promise.then():获取异步任务的正常结果。
promise.catch():获取异步任务的异常结果。
promise.finaly():异步任务无论成功与否,都会执行。
Promise 的静态方法
之前讲的都是 Promise 的实例方法;现在,我们来详细讲一下 Promise 的静态方法。
静态方法:可以直接通过大写的Promise.xxx
调用的方法。这里的xxx
就称之为静态方法。
Promise 的自带 API 提供了如下静态方法:
Promise.resolve()
Promise.reject()
Promsie.all()
:并发处理多个异步任务,所有任务都执行成功,才算成功(走到 resolve);只要有一个失败,就会马上走到 reject,整体都算失败。Promise.race()
:并发处理多个异步任务,返回的是第一个执行完成的 promise,且状态和第一个完成的任务状态保持一致。Promise.allSettled()
:并发处理多个异步任务,返回所有任务的执行结果(包括成功、失败)。当你有多个彼此不依赖的异步任务执行完成时,或者你想知道每个 promise 的结果时,通常使用它。Promise.all()
Promise.any()
Promise.all()
Promsie.all([p1, p2, p3])
:并发处理多个异步任务,所有任务都执行成功,才算成功(才会走到 then);只要有一个任务失败,就会马上走到 catch,整体都算失败。参数里传的是 多个 promise 实例组成的数组。
简单理解:Promise.all() 方法会发起并行的 Promise 异步操作,等所有的异步操作全部结束后才会执行下一步的 .then
操作(等待机制)
语法举例
1、异步任务都执行成功时:
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('执行 promise1');
resolve('promise 1 成功');
}, 1000);
});
const promise2 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('执行 promise2');
resolve('promise 2 成功');
}, 2000);
});
const promise3 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('执行 promise3');
resolve('promise 3 成功');
}, 3000);
});
Promise.all([promise1, promise2, promise3])
.then((res) => {
// 三个异步任务都执行成功,才会走到这里
// 这里拿到的 res,是三个成功的返回结果组成的数组
console.log(JSON.stringify(res));
})
.catch((err) => {
// 只要有一个异步任务执行失败,就会马上走到这里
console.log(err);
});
打印结果:
// 1秒后
执行 promise1
// 2秒后
执行 promise2
// 3秒后
执行 promise3
["promise 1 成功","promise 2 成功","promise 3 成功"]
2、异步任务有至少一个执行失败时:
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('执行 promise1');
resolve('promise 1 成功');
}, 1000);
});
const promise2 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('执行 promise2');
// 这里通过 reject() 的方式,表示任务执行失败
reject('promise 2 失败');
}, 2000);
});
const promise3 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('执行 promise3');
resolve('promise 3 成功');
}, 3000);
});
Promise.all([promise1, promise2, promise3])
.then((res) => {
// 三个异步任务都执行成功,才会走到这里
console.log('走到 then:' + JSON.stringify(res));
})
.catch((err) => {
// 只要有一个异步任务执行失败,就会马上走到这里
console.log('走到 catch:' + err);
});
打印结果:
// 1秒后
执行 promise1
// 2秒后
执行 promise2
走到 catch:promise 2 失败
// 3秒后
执行 promise3
可以看到,当 promise2 执行失败之后,马上就走到了 catch,而且 promise3 里的 resolve 并没有执行。
读文件例子
import thenFs = require("then-fs");
//1. 定义一个数组,存放3个读文件的异步操作
const promiseArr = [
thenFs.readFile('./files/1.txt', 'utf8'),
thenFs.readFile('./files/2.txt', 'utf8'),
thenFs.readFile('./files/3.txt', 'utf8'),
]
//2. 将Promise的数组,作为Promise.all()的参数
Promise.all(promiseArr)
.then(([r1, r2, r3]) => {
//2.1 所有文件读取成功
console.log(r1, r2, r3);
})
.catch(err => {
console.log(err.message); //2.2 捕获Promise异步操作中的错误
})
Promise.race()
Promise.race([p1, p2, p3])
:并发处理多个异步任务,返回的是第一个执行完成的 promise,且状态和第一个完成的任务状态保持一致。参数里传的是多个 promise 实例组成的数组。
上面这句话,第一次读时,可能很绕口。我说的再通俗一点:在多个同时执行的异步任务中,先找出哪个异步任务最先执行完成(无论是走到 resolve,还是走到 reject,都算执行完成),整体的状态就跟这个任务保持一致。如果这个任务执行成功,那整体就算成功(走到 then);如果这个任务执行失败,那整体就算失败(走到 catch)。
race
的中文翻译,可以理解为“竞赛”。意思是,谁先抢到名额,就认定谁了。无论这个人最终的结局是成功或者失败,整体的结局,都以这个人的结局为准。
我刚开始学 Promise.race()的时候,误以为它的含义是“只要有一个异步执行成功,整体就算成功(走到 then);所有任务都执行失败,整体才算失败(走到 catch)”。现在想来,真是大错特错,过于懵懂。
现在我顿悟了,准确来说,Promise.race()强调的是:只要有一个异步任务执行完成,整体就是完成的。
Promise.race()的应用场景:在众多 Promise 实例中,最终结果只取一个 Promise,谁返回得最快就用谁的 Promise。
简单理解:Promise.race() 方法会发起并行的 Promise 异步操作,只要任何一个异步操作完成,就立即执行下一步的.then操作(赛跑机制)。
示例代码如下:
语法举例
场景 1、所有任务都执行成功时:
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('执行 promise1');
resolve('promise 1 成功');
}, 1000);
});
const promise2 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('执行 promise2');
resolve('promise 2 成功');
}, 2000);
});
const promise3 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('执行 promise3');
resolve('promise 3 成功');
}, 3000);
});
Promise.race([promise1, promise2, promise3])
.then((res) => {
// 第一个完成的任务,如果执行成功,就会走到这里
// 这里拿到的 res,是第一个成功的 promise 返回的结果,不是数组
console.log(JSON.stringify(res));
})
.catch((err) => {
// 第一个完成的任务,如果执行失败,就会走到这里
console.log(err);
});
打印结果:
// 1秒后
执行 promise1
"promise 1 成功"
// 2秒后
执行 promise2
// 3秒后
执行 promise3
场景 2、第一个任务成功、第二个任务失败时:
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('执行 promise1');
resolve('promise 1 成功');
}, 1000);
});
const promise2 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('执行 promise2');
// 第二个任务执行失败时
reject('promise 2 失败');
}, 2000);
});
const promise3 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('执行 promise3');
resolve('promise 3 成功');
}, 3000);
});
Promise.race([promise1, promise2, promise3])
.then((res) => {
// 第一个完成的任务,如果执行成功,就会走到这里
console.log('走到then:' + res);
})
.catch((err) => {
// 第一个完成的任务,如果执行失败,就会走到这里
console.log('走到catch:' + err);
});
打印结果:
// 1秒后
执行 promise1
走到then:promise 1 成功
// 2秒后
执行 promise2
// 3秒后
执行 promise3
可以看出,场景 2 的打印结果和场景 1 的打印结果,是一样的。因为最新执行完成的任务,是成功的,所以整体会马上走到 then,且整体就算成功。
场景 3、第一个任务失败、第二个任务成功时:
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('执行 promise1');
// 第一个任务执行失败时
reject('promise 1 失败');
}, 1000);
});
const promise2 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('执行 promise2');
resolve('promise 2 成功');
}, 2000);
});
const promise3 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('执行 promise3');
resolve('promise 3 成功');
}, 3000);
});
Promise.race([promise1, promise2, promise3])
.then((res) => {
// 第一个完成的任务,如果执行成功,就会走到这里
console.log('走到then:' + res);
})
.catch((err) => {
// 第一个完成的任务,如果执行失败,就会走到这里
console.log('走到catch:' + err);
});
打印结果:
// 1秒后
执行 promise1
走到catch:promise 1 失败
// 2秒后
执行 promise2
// 3秒后
执行 promise3
读取文件例子
import thenFs from 'then-fs'
// 1.定义一个数组,存放3个读文件的异步操作
const promiseArr = [
thenFs.readFile('./files/3.txt', 'utf8'),
thenFs.readFile('./files/2.txt', 'utf8'),
thenFs.readFile('./files/1.txt', 'utf8'),
]
// 2.将Promise的数组,作为Promise.race()的参数
Promise.race(promiseArr)
.then(result => {
//2.1 只要任何一个异步操作完成,就立即执行成功的回调函数(赛跑机制)
console.log(result)
})
.catch(err => {
//2.2 捕获promise异步操作的错误
console.log(err.message);
})
基于 Promise 封装读文件的方法
方法的封装要求:
- 方法的名称要定义为 getFile
- 方法接收一个形参 fpath,表示要读取的文件的路径
- 方法的返回值为 Promise 实例对象
1. getFile 方法的基本定义
//1. 方法的名字为getFile
//2.方法接收一个形参fpath,表示要读取的文件的路径
function getFile(fpath) {
//3. 返回一个Promise实例对象
return new Promise()
}
第 5 行代码中的 new Promise() 只是创建了一个形式上的异步操作
2. 创建具体的异步操作
如果想要创建具体的异步操作,则需要在 new Promise() 构造函数期间,传递一个 function 函数,将具体的异步操作定义到 function 函数内部。示例代码如下:
//1. 方法的名字为getFile
//2.方法接收一个形参fpath,表示要读取的文件的路径
function getFile(fpath) {
//3. 返回一个Promise实例对象
return new Promise(function(){
//4。这行表示一个具体的、读文件的异步操作
fs.readFile(fpath,'utf8',(err,dataStr) => {
} )
})
}
3.获取 .then 的两个实参
通过 .then() 指定的成功和失败的回调函数,可以在 function 的形参中进行接收,示例代码如下:
4. 调用 resolve 和 reject 回调函数
Promise 异步操作的结果,可以调用 resolve 或 reject 回调函数进行处理。示例代码如下:
import fs from 'fs'
function getFile(fpath) {
return new Promise(function (resolve, reject) {
fs.readFile(fpath, 'utf8', (err, dataStr) => {
if (err) return reject(err)
resolve(dataStr)
})
})
}
getFile('./files/11.txt')
.then((r1) => {
console.log(r1)
})
.catch((err) => console.log(err.message))
Promise.resolve() 和 Promise.reject()
当我们在定义一个 promise 的过程中,如果涉及到异步操作,那就需要通过new Promise
的方式创建一个 Promise 实例。
但有些场景下,我们并没有异步操作,但仍然想调用 promise.then,此时,我们可以用 Promise.resolve()
将其包装成成功的状态。同理,Promise.reject()
可以包装成失败的状态。
比如说,有的时候,promise 里面并不涉及异步操作,我只是单纯地想通过 promise 对象返回一个字符串(有的业务就是有这样的需求),那就可以通过 Promise.reslove('字符串')
Promise.reject('字符串')
、这种简写的方式返回。
这两种情况,我们来对比看看。
例 1:
function foo(flag) {
if (flag) {
return new Promise((resolve) => {
// 这里可以做异步操作
resolve('success');
});
// return Promise.resolve('success2');
} else {
return new Promise((reslove, reject) => {
// 这里可以做异步操作
reject('fail');
});
}
}
// 执行 reslove 的逻辑
foo(true).then((res) => {
console.log(res);
});
// 执行 reject 的逻辑
foo(false).catch((err) => {
console.log(err);
});
例 2:(见证奇迹的时刻)
function foo(flag) {
if (flag) {
// Promise的静态方法:直接返回字符串
return Promise.resolve('success');
} else {
// Promise的静态方法:直接返回字符串
return Promise.reject('fail');
}
}
// 执行 reslove 的逻辑
foo(true).then((res) => {
console.log(res);
});
// 执行 reject 的逻辑
foo(false).catch((err) => {
console.log(err);
});
例 1 和例 2 的打印结果是一样的。这两段代码的区别在于:例 1 里面可以封装异步任务;例 2 只能单纯的返回一个字符串等变量,不能封装异步任务。
版权声明
本文为[[email protected]]所创,转载请带上原文链接,感谢
https://blog.csdn.net/weixin_59816940/article/details/126008054
边栏推荐
- Public Key Retrieval is not allowed error solution
- Summary of String Copy, Concatenation, Comparison and Split Functions (1)
- 数据预处理:离散特征编码方法
- Mongoose module
- 大厂面试官眼中的好简历到底长啥样
- KDD 2020 | 深入浅出优势特征蒸馏在淘宝推荐中的应用
- 对话框 QDialog ( 详解 )
- 基于STM32F407使用ADC采集电压实验
- LeetCode318:单词长度的最大乘积
- Lotus 1.16.0 minimum snapshot export import
猜你喜欢
Paper reading (63): Get To The Point: Summarization with Pointer-Generator Networks
LeetCode318:单词长度的最大乘积
向量检索基础方法总结
FP6606CMP5 CPC-16L USB类型-C和PD充电控制器 百盛电子代理商
DTSE Tech Talk丨第2期:1小时深度解读SaaS应用系统设计
Public Key Retrieval is not allowed error solution
PHP留言反馈管理系统源码
LeetCode167: Sum of two numbers in sorted array
Mysql进阶优化篇01——四万字详解数据库性能分析工具(深入、全面、详细,收藏备用)
万华化学精细化工创新产品大会
随机推荐
Dive deep on Netflix‘s recommender system(Netflix推荐系统是如何实现的?)
【综合类型第 34 篇】喜讯!喜讯!!喜讯!!!,我在 CSDN 的第一个实体铭牌
Lotus 1.16.0 minimum snapshot export import
如何注册域名、备案以及解析
Weka 3.8.6安装与Weka 3.8.6功能介绍
HUAWEI CLOUD data governance production line DataArts, let "data 'wisdom' speak"
PHP留言反馈管理系统源码
You are a first-class loser, you become a first-class winner
简易的命令行入门教程
将 APACHE 日志解析到 SQL 数据库中
Visual Studio编辑器 2019:scanf函数返回值被忽略(C4996)报错及解决办法
Various meanings of SQL's PARTITION BY syntax (with examples)
Leetcode 118. Yanghui Triangle
FP6606ACAW4 TQFN-20L (3mmx3mm) USB双端口充电控制器 百盛电子代理
lotus 爆块失败
每日练习------生成13位条形, Ean-13码规则:第十三位数字是前十二位数字经过计算得到的校验码。
DTSE Tech Talk丨第2期:1小时深度解读SaaS应用系统设计
JVM学习----垃圾回收
Nervegrowold d2l (7) kaggle housing forecast model, numerical stability and the initialization and activation function
数组和指针(2)