Promise

94 阅读5分钟

一、什么是Promise?我们用Promise来解决什么问题?

  • Promise是异步编程的一种解决方案,它相当于一个容器,里面保存着未来才会结束的事件,它也主要是用来解决回调地狱的问题。
  • promise是一个对象,代表一个异步操作,有三种状态,进行中,成功,失败。只有异步操作的结果的可以决定当前是哪种状态,promise一旦新建执行,就没有办法中途停止。

1645867796.png

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 耗时任务的成功调用链:​

image.png

​Promise 耗时任务的失败调用链:​

image.png

​如果在调用链上添加了 .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('哈哈')
  
  //会输出什么??