一、什么是Promise?我们用Promise来解决什么问题?
Promise是异步编程的一种解决方案,它相当于一个容器,里面保存着未来才会结束的事件,它也主要是用来解决回调地狱的问题。promise是一个对象,代表一个异步操作,有三种状态,进行中,成功,失败。只有异步操作的结果的可以决定当前是哪种状态,promise一旦新建执行,就没有办法中途停止。
Promise的状态
Promise 的构造器接受一个名称为 executor 的函数,而 executor 函数接受两个参数: resolve 和 reject,并且这两个参数也都是函数。
Promise 的 then 方法传入两个回调函数 onFulfilled 和 onRejected,分别用于处理 fulfilled 和 rejected 状态,并返回一个新的 Promise。
let p = new Promise((resolve, reject) => {
let a1 = '成功的参数';
let a2 = '失败的参数';
var time = setTimeout(() => {
console.log('start');
resolve(a1);
reject(a2);
console.log('end');
}, 1000);
});
p.then(value => {
console.log('这是resolve函数体,参数:' + value);
}, reason => {
console.log('这是reject函数体,参数:' + reason);
})
then 方法返回的是一个新的 Promise
then函数中,有两个参数。然后根据当前 promise 的不同状态执行不同的逻辑:
- pending状态:会将
then传递的两个处理函数变成一个节点插入到链表结构中,等待promise状态完成时再触发。 - fulfilled状态:会创建一个 微任务 来调用传入的 onFulfilled 处理函数,并将其插入 微任务 队列。
- rejected状态:与 fulfilled 状态类似,会将创建一个 微任务 来调用传入的
onRejected处理函数,然后将其插入 微任务 队列。
Promise 对象的原型方法
有三个方法在 Promise 的原型上,它们返回的都是 Promise 对象:
- Promise.prototype.catch(onRejected)
- Promise.prototype.then(onFulfilled, onRejected)
- Promise.prototype.finally(onFinally)
最开始 Promise 出于 pending 状态,当内部的耗时任务处理成功之后,就会调用 .then(onFulfillment) 回调;如果内部的耗时任务处理失败之后,其会对 .then(onFullfillment, onRejected) 的第二个参数 onRejected 函数进行回调,也会对 .catch(onRejection) 函数进行回调,用来让用户进行错误处理。
JS 层面 obj.catch(onRejected) 等价于 obj.then(undefined, onRejected)
Promise 耗时任务的成功调用链:
Promise 耗时任务的失败调用链:
如果在调用链上添加了 .finally 回调,那么无论调用成功还是失败,都会对 .finally 进行回调。
Promise 对象的静态方法
Promise 共有 4 个静态方法,它们返回的同样也都是 Promise 对象本身。我们先来看前两个方法:
-
Promise.reject(reason)
-
Promise.resolve(value) 这两个方法都是帮助方法,帮助开发者直接创建状态为 rejected 或 resolved 的 Promise,而剩下的这两个方法用来帮助开发者处理多个 Promise:
-
Promise.all(iterable)
-
Promise.race(iterable) Promise.all 可以将多个Promise实例包装成一个新的Promise实例。同时,成功和失败的返回值是不同的,成功的时候返回的是一个结果数组,而失败的时候则返回最先被reject失败状态的值。
const allFetch = ['amy','json','kebi'].map(
name => ajax('http:127.0.0.1/getUserDetail?name=${name}'))
Promise.all(allFetch).then((result) => {
console.log(result)
}).catch((error) => {
console.log(error) // 失败了
})
Promise.all获得的成功结果的数组里面的数据顺序和Promise.all接收到的数组顺序是一致的,即amy的结果在前,即便json的结果获取的比amy要晚。
Promise.race([p1, p2, p3])里面哪个结果获得的快,就返回那个结果,不管结果本身是成功状态还是失败状态。
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('success')
},1000)
})
let p2 = new Promise((resolve, reject) => {
setTimeout(() => {
reject('failed')
}, 500)
})
Promise.race([p1, p2]).then((result) => {
console.log(result)
}).catch((error) => {
console.log(error) // 打开的是 'failed'
})
promise是用来解决
- 回调地狱, 常常第一个的函数的输出是第二个函数的输入这种现象
- promise可以支持多个并发的请求,获取并发请求中的数据
- promise可以解决异步的问题,本身不能说promise是异步的
console.log('同步执行开始')
new Promise((resolve, reject) => {
resolve()
console.log('kankanwo')
})
console.log('同步执行结束')
// 本段代码的打印顺序是:
// 同步执行开始
// kankanwo
// 同步执行结束
二、 async 和 await
async
async 是一个修饰符,async 定义的函数会默认的返回一个Promise对象resolve的值,因此对async函数可以直接进行then操作,返回的值即为then方法的传入函数
async function funa() {
console.log('a')
return 'a'
}
funa().then( x => { console.log(x) }) // 输出结果a, a,
wait
await也是一个修饰符。只能放在 async 函数内部, await关键字的作用 就是获取 Promise中返回的内容, 获取的是Promise函数中resolve或者reject的值
如果await 后面并不是一个Promise的返回值,则会按照同步程序返回值处理\
很多人以为await会一直等待之后的表达式执行完之后才会继续执行后面的代码,实际上
await是一个让出线程的标志。await后面的函数会先执行一遍,然后就会跳出整个async函数来执行后面js栈(后面会详述)的代码。等本轮事件循环执行完了之后又会跳回到async函数中等待await后面表达式的返回值,如果返回值为非promise则继续执行async函数后面的代码,否则将返回的promise放入promise队列(Promise的Job Queue)
const testSometing = () => {
console.log("执行testSometing");
return "testSometing";
};
const testAsync = async () => {
console.log("执行testAsync");
return Promise.resolve("hello async");
};
const test = async () => {
console.log("test start...");
const v1 = await testSometing(); //关键点1
console.log(v1);
const v2 = await testAsync();
console.log(v2);
console.log(v1, v2);
};
test();
const promise = new Promise((resolve) => {
console.log("promise start..");
resolve("promise");
}); //关键点2
promise.then((val) => console.log(val));
console.log("test end...");
三、 # JS事件循环(Event Loop)
执行顺序:
1、先执行主线程
2、遇到宏队列(macrotask)放到宏队列(macrotask)
3、遇到微队列(microtask)放到微队列(microtask)
4、主线程执行完毕
5、执行微队列(microtask),微队列(microtask)执行完毕
6、执行一次宏队列(macrotask)中的一个任务,执行完毕
7、执行微队列(microtask),执行完毕
8、依次循环
setTimeout(()=>{
console.log('不知道')
},0)
console.log('想不到吧')
new Promise(resolve=>{
console.log('他')
resolve()
}).then(result=>{
console.log('我')
}).then(value=>{
console.log('才执行')
})
console.log('哈哈')
//会输出什么??