Promise
   
    1.异步行为是
    
     为了优化因计算量大而时间长的操作
    
    .
   
2.pedding 待定: 表示尚未开始或正在进行中
fulfilled 解决: 表示已经成功完成
rejected 拒绝: 表示没有完成
3.从pedding状态切换到fulfilled状态或rejected状态后,状态就不会再改变.而且也不能保证promise比如会脱离待定状态.
因此,无论promise是resolve还是reject,甚至永远处于待定状态,都应该具有恰当的行为
4.执行器函数的两项职责: 初始化promise的异步行为和控制状态的最终转换.
控制promise状态的转换是通过resolve()和reject()来实现的
    
     resolve()会把状态切换为兑现
    
   
    
     reject()会把状态切换为拒绝,reject()会抛出错误.
    
   
    5. 执行器函数是同步执行的, 因为
    
     执行器函数是promise的初始化程序
    
   
console.log(1);
new Promise((resolve,reject) => {
    console.log(3);
})
console.log(2);
//打印1, 3, 26.无论resolve()和reject()中的哪个被调用,状态转换后都不可撤销. 继续修改状态会默认失败
const p = new Promise((resolve,reject) => {
    resolve('666')
    reject('000') // 没有效果
})
console.log(p); // 666
    7.
    
     为了避免promise卡在待定状态,可以添加一个定时退出功能
    
    ,通过setTimeout设置一个10秒后无论如何都会拒绝promise的回调
   
如果执行器中的代码在超时之前已经解决或拒绝,那么再次调用reject也会默认失败
    8.Promise.resolve()
   
通过Promise.resolve()静态方法,可以实例化一个解决的Promise
使用这个静态方法实际上可以把任何值都转换为一个Promise
const p1 = new Promise((resolve,reject) => resolve())
const p2 = Promise.resolve() // undefined
const p3 = Promise.resolve(3) // 3
const p4 = Promise.resolve(4,5) // 4 多余参数会忽略, 可以使用对象
    
     9.Promise.reject()
    
   
    
     实例化一个拒绝的promise并抛出一个异步错误
    
    (这个错误不能通过try/catch捕获,只能通过拒绝处理程序捕获)
   
const p = Promise.reject(4) // promise <rejected> 410. Promise的实例方法
10.1.实现Thenable接口
    10.2
    
     .Promise.prototype.then()
    
   
Promise.prototype.then()是为Promise实例添加处理程序的主要方法.
    then()最多接收两个参数
    
     onResolved处理程序和onRejected处理程序,
    
    这两个参数都是可选的分别进入兑现和拒绝状态
   
let p1 = new Promise((resolve,reject) => setTimeout(resolve,2000))
let p2 = new Promise((resolve,reject) => setTimeout(reject,2000))
p1.then(() => onResolved('p1'),
        () => onRejected('p1'))
p2.then(() => onResolved('p2'),
        () => onRejected('p2'))
        
function onRejected(id){
    console.log(id,'rejected');
}
function onResolved(id){
    console.log(id,'onResolved');
}因为promise的只能转换最终状态一次,所以这两个操作一定的互斥的.
    
     传给then()的任何非函数类型的参数都会被静默忽略.如果只提供onRejected参数,要在onResolved位置上传入undefined
    
   
p1.then('glsdfosdfisdjif') // 会被忽略,不推荐
p1.then(null,() => onRejected('p2')) // 不传onResolved的规范写法
    
     Promise.prototype.then()返回一个新的Promise实例, 会通过Promise.resolve()隐式包装来生成新的Promise
    
   
const p3 = Promise.resolve('wei') // 默认返回undefined
    10.3.Promise.prototype.catch()
   
    Promise.prototype.catch()是为Promise实例
    
     添加拒绝处理程序.
    
   
实际上这个方法就是一个语法糖,相当于调用了 Promise.prototype.then(null,onRejected)
    返回一个新的Promise实例,会通过
    
     Promise.resolve()隐式包装来生成新的Promise
    
   
    10.4.Promise.prototype.finally()
   
    Promise.prototype.finally()用于给promise添加onFinally处理程序,在promise转换为解决或者拒绝都会执行, 主要是
    
     避免在resolve和rejected中出现冗余代码
    
    . 但是没办法知道promise的状态是解决还是拒绝.
   
返回一个新的Promise实例,不同于then()和catch()方法返回的实例.在大多数情况下它将表现为父Promise的传递.
10.5.非重入Promise方法
    当Promise进入落定状态时,与该状态相关的处理程序仅仅会被排期,而非立即执行.(
    
     就是被放到一个微任务里去了
    
    )
   
// 例子
const p = Promise.resolve()
p.then(() => {
    console.log('p.then()');
})
console.log('同步执行');
// 实际输出 同步执行, p.then()// 例子
let sy;
let p = new Promise((resolve) => {
    sy = function() {
        console.log(1);
        resolve()
        console.log(2);
    }
})
p.then(() => {
    console.log(4);
})
sy()
console.log(3);
/* 
    实际输出: 1,2,3,4 即使Promise的状态发生在添加处理程序之后,
    处理程序也会等到运行的消息队列让出时,才会执行.
*/ 10.6.临近处理程序的执行顺序
10.7.传递解决值和拒绝理由
    解决的值和拒绝的理由分别通过
    
     resolve()和reject()的第一个参数往后传,直到报错
    
   
Promise.resolve() 和Promise.reject() 在被调用时就会接受解决值和拒绝理由.
10.8.拒绝Promise与拒绝错误处理
拒绝Promise类似于throw()表达式.它们都代表一种程序状态, 即需要中断或者特殊处理
let p1 = new Promise((resolve,reject) => reject( Error('1')))
let p2 = new Promise((resolve,reject) => { throw Error('2') })
let p3 = Promise.resolve().then(() => { throw Error('3') })
let p4 = Promise.reject(() => Error('4'))
console.log(p1);
console.log(p2);
console.log(p3);
console.log(p4);Promise.resolve().then()的错误最后才出现.
正常情况下,在通过throw()关键字抛出错误时,js运行时的错误处理机制会停止执行抛出错误之后的任何代码(抛出错误之后不解析了)
// 正常情况xxx不会执行
throw Error()
console.log('xxx');// promise抛出错误时,因为错误实际上是从消息队列中抛出来的,所有不会阻止运行时
Promise.reject(Error('x'))
console.log('xxx'); // 会输出// 例子:
        let p = new Promise((resolve,reject) => {
            console.log(1);
            reject(Error())
        }).then(() => {
            console.log(2);
        }).catch((e) => {
            console.log(3);
        }).catch(() => {
            console.log(4);
        }).then(() => {
            console.log(5);
        })
/*
    实际输出1,3,5 首先打印1, 没毛病, 接下来执行reject(),打印3, catch 函数会隐式的调用
    Promise.resolve()函数, 因此继续.then()打印5
*/
10.9.Promise连锁与合成
    多个Promise组合在一起可以
    
     构成强大的代码逻辑.
    
   
    通过两种方式实现:
    
     promise连锁和promise合成,前者是一个promise接一个promise的拼接,后者则是将多个promise组合成一个promise
    
   
        //要执行真正的异步任务,让每个执行器都返回一个promise实例
        let p1 = new Promise((resolve,reject) => {
            console.log(1);
            setTimeout(resolve,1000)
        })
        p1.then(() => new Promise((resolve,reject) => {
            console.log(2);
            setTimeout(resolve,1000)
        }))
        .then(() => new Promise((resolve,reject) => {
            console.log(3);
            setTimeout(resolve,1000)
        }))
        .then(() => new Promise((resolve,reject) => {
            console.log(4);
            setTimeout(resolve,1000)
        }))
        // 1 1秒后
        // 2 2秒后
        // 3 3秒后
        // 4 4秒后
    
     Promise的处理程序是按照它们添加的顺序执行
    
    的,由于Promise的处理程序是先添加到消息队列, 然后才逐个执行.
   
    
     将多个Promise实例组合成一个Promise的静态方法. Promise.all()和Promise.race()
    
   
Promise.all()方法创建的promise会将一组promise全部解决后,再返回结果.
Promise.all()接收一个可迭代对象,返回一个新Promise
let p1 = Promise.all([
    Promise.resolve(),
    Promise.resolve()
])// 可迭代对象中的元素会通过Promise.resolve()转换为Promise
let p2 = Promise.all([3,4])// 空的可迭代对象等价于Promise.resolve()
let p2 = Promise.all([])// 无效的语法
let p2 = Promise.all() // 报错有一个Promise待定,则合成的Promise也会待定, 有一个Promise拒绝,则合成的Promise也会拒绝.
// 一次拒绝导致最终Promise的拒绝
let p1 = Promise.all([
    Promise.resolve(),
    Promise.resolve(),
    Promise.reject()
])
    // 如果所有的promise都成功解决,则合成
    
     promise的解决值就是所有包含promise解决值的数组
    
    (按迭代器顺序)
   
let p1 = Promise.all([
    Promise.resolve(1),
    Promise.resolve(2),
    Promise.resolve()
])
p1.then(res => {
    console.log(res); [1, 2, undefined]
})// 多个reject的情况
let p1 = Promise.all([
    Promise.reject(1),
    Promise.reject(2),
    Promise.resolve()
])
p1.then(res => {
    console.log(res); 
    /*
        1 会将第一个拒绝的理由作为合成promise的拒绝理由. 之后再拒绝的promise的不会
        影响最终promise的拒绝理由.
    */ 
})
    
     Promise.race()
    
    方法创建的任意一个 Promise 对象状态变为 fulfilled 或 rejected 时立即返回该 Promise 对象的值或原因。
   
语法同all()
    
     只要第一个落定的promise,Promise.race()就会包装其解决值或姐拒绝理由并返回新promise
    
   
    
     ES6不支持取消Promise和进度通知,一个主要原因就是这样会导致promise连锁和promise合成过渡复杂化.
    
   
    async await
   
    功能:
    
     让以同步方式写的代码能够异步执行.
    
   
async/await解决利用异步结构组织代码的问题.
    1.
    
     async 关键字用于声明异步函数
    
    可以用在函数声明,函数表达式,箭头函数和方法上
   
async function foo() {}
let bar = async function() {}
let baz = async () => {}
class Qux {
    async qux(){}
}
    
     使用async关键字可以让函数具有异步特征,但总体上代码仍然是同步求值的.
    
   
而在参数或闭包方面,异步函数仍然具有普通函数js函数的正常行为.
例子:
async function foo() {
    console.log('1');
}
foo()
console.log(2);
// 1,2异步函数如果使用return 关键字返回了值(没有return 返回undefined),这个值会被Promise.resolve()包装成一个Promise对象.
async function foo() {
    console.log('1');
    // return 666
    return Promise.resolve(666) // 效果同上
}
// 给返回的promise添加一个解决处理程序
foo().then(console.log)
// 1, 666在异步函数中抛出错误会返回拒绝的Promise
async function foo() {
    console.log('1');
    throw 3
    console.log('4'); // 不执行
}
// 给返回的promise添加一个解决处理程序
foo().catch(console.log)
console.log(2);
// 1, 2, 32. 异步函数主要针对不会马上完成的任务,需要一种暂停和恢复执行的能力.
使用await关键字可以暂停异步函数代码的执行,等待Promise的解决.它可以单独使用,也可以在表达式中使用
await命令后面是一个Promise对象. 如果不是,会被转成一个立即resolve的Promise对象.
// 对拒绝promise使用await会释放错误值(将拒绝promise返回)
async function foo() {
    console.log('1');
    await Promise.reject(3)
    // return await Promise.resolve(3) 
    // resolve需要return then才能接受, 而reject不需要return catch也可以接收
    console.log('4'); // 这行代码不会执行
}
// 给返回的promise添加一个解决处理程序
foo().then(console.log).catch(console.log)
console.log(2);
// await Promise.reject(3) 打印输出1,2,3只要一个await语句后面的Promise变成reject, 那么整个async函数都会中断执行.
// 下面await语句是不会执行的,因为第一个await已经变成了reject
async function foo() {
    await Promise.reject('出错了')
    await Promise.resolve('hello') // 不会打印
}如果希望前一个异步操作失败,也不要中断后面的异步操作.
这时可以将第一个await放在try…catch 这也不管这个异步是否成功,第二个await都会执行
 async function foo() {
     try {
         await Promise.reject('出错了') // 会打印
     } catch (e) {
         console.log(e);
     }
     return await Promise.resolve('hello') // 会打印
 }
 foo().then(v => console.log(v))另一种方式是在await后面的promise对象后添加一个catch方法,处理前面可能出现的错误
    async function foo() {
         await Promise.reject('出错了').catch (e => console.log(e))//会打印
         return await Promise.resolve('hello') // 会打印
    }
    foo().then(v => console.log(v))3.await 的限制
    
     
      await关键字必须在异步函数中使用.
     
    
   
不允许:await出现在箭头函数中
不允许:await出现在同步函数声明中
不允许:await出现在同步函数表达式中
不允许:IIFE使用同步函数表达式或箭头函数
停止和恢复执行
使用await关键字之后的区别其实看上去还要微妙一些.
async function foo() {
    console.log(await Promise.resolve('foo'));
}
async function bar() {
    console.log(await 'bar');
}
async function baz() {
    console.log('baz');
}
foo()
bar()
baz()
// 打印 baz, bar, foo
    async/await中
    
     
      真正起作用的是await. async只是一个标识符,毕竟异步函数如果不包含await关键字,基本和普通函数没什么区别
     
    
   
async function foo() {
    console.log(2);
}
console.log(1);
foo()
console.log(3);
// 打印 1, 2, 3要完全理解await关键字,必须知道它并非只是等待一个值可用那么简单.
    
     
      js运行时在碰到await关键字时, 会记录在哪里暂停执行. 等到await后面的值可用了,js运行时会向消息队列中推送一个任务,这个任务会恢复异步函数的执行
     
    
   
    因此,
    
     即使await后面跟着一个立即可用的值,函数的其余部分也会被异步求值
    
    .下面例子:
   
async function foo() {
    console.log(2);
    await null
    console.log(4);
}
console.log(1);
foo()
console.log(3);
// 打印 1, 2, 3, 4
/*
运行时的工作过程:
(1) 打印1;
(2) 调用异步函数foo();
(3) (在foo中)打印2;
(4) (在foo中)await关键字暂停执行,为立即可用的值null向消息队列中添加一个任务;
(5) foo()退出;
(6) 打印3;
(7) 同步线程执行完毕;
(8) js运行时从消息队列中取出任务,恢复异步函数执行;
(9) (在foo中)恢复执行,await取得null值(这里并没有用)
(10) (在foo中)打印4;
(11) foo()返回
*/
    // TC39对await后面是promise的情况如何处理做过一次修改.
    
     修改后await Promise.resolve(8)只会生成一个异步任务
    
   
async function foo() {
    console.log(2);
    console.log(await Promise.resolve(8));
    console.log(9);
}
async function bar() {
    console.log(4);
    console.log(await 6);
    console.log(7);
}
console.log(1);
foo()
console.log(3);
bar()
console.log(5);
// 打印 1, 2, 3, 4, 5, 8, 9, 6, 7使用注意点:
1.await命令后面的promise对象的运行结果可能是rejected,最好把await放在try…catch代码块中
2.多个await命令后面的异步操作如果不存在继发关系,最好让他们同时触发
// getFoo和getBar是两个独立的异步操作,被写成激发关系,这样比较耗时.可以让它们同时触发
   let foo = await getFoo()
   let bar = await getBar()
   let [foo, bar] = await Promise.all([getFoo,getBar])async函数的实现原理:
    
     async函数的实现原理就是将Generator函数和自动执行器包装在一个函数里.
    
   
面试官: 来说一下你对Promise的理解?
    个人对Promise的理解是, promise是一种
    
     异步编程的解决方案,
    
    它比传统的回调函数加事件更加合理合强大,
   
    目前除了使用promise的异步操作外,还使用promise在项目中
    
     解决回调地狱
    
    等问题.
   
promise是一个对象可以获取异步操作的信息
promise的特点:
    对象不受外界影响,promise一共有三个状态, 分别是
    
     进行中,成功和失败,
    
    只有
    
     异步操作的结果,可以决定是哪一种状态,任何其他的操作都无法改变这个状态
    
    .
   
    
     一旦状态改变就不会在变
    
    ,任何时候都可以得到这个结果,promise的状态改变只有两种可能要么成功要么失败
   
如果要使用promise必须对promise进行实例化, 实例化之后promise内有一个回调函数,这个函数有两个参数,分别是resolve和reject,
    当我们的状态发生变化的时候,如果是成功则会通过
    
     resolve将成功的结果返回,
    
    如果失败通过
    
     reject将错误的信息返回
    
    出去.
   
    通过
    
     .then方法接收成功
    
    的结果,通过.
    
     catch方法接收失败
    
    的结果
   
    promise常用的方法还用
    
     promise.all(),race()方法. 主要是将多个实例包装成一个新的实例.
    
   
Promise.all()方法创建的promise会将一组promise全部解决后,再返回结果.
Promise.race()方法哪个接口跑的快,先返回哪个
    在项目中一般使用promise来
    
     对接口进行封装
    
    ,以及一些
    
     异步的操作
    
    都会用到promise.
    
     校验
    
   
 
