ES6新技术——promise

promise是ES6新提出得用于解决异步编程问题得方法。

1. 同步和异步

1) 同步任务:任务1执行完才能执行任务2,同步任务是直接放在主线程中的。
2)异步任务:异步任务是放在任务队列中的(event queue),只有当同步任务完成后才会执行异步任务。常见的异步任务:事件监听(click等)、回调函数(定时器,ajax请求、nodejs的某些回调),ES6中的promise、generator等,文件操作

2. 事件循环even loop

   步骤:

(1) 对所有的任务——判断是否为同步
(2) 如果是同步任务,放到主线程中,按照顺序执行
(3)如果是异步任务,先放到event table中,等该任务的执行条件满足(已经点击了,已经等待2s了),将改任为放到event queue中排队。
(4)当主线程的任务全部完成后,到event queue中检查是否有任务,如果有任务,将其拿到主线程中执行。

3. promise实现异步编程

3.1 promise是什么

抽象的理解:
1) promise是ES新提出的一门技术
2) promise是js中进行异步编程的新解决方案(旧操作:使用回调函数)
具体的表达
1) 从语法上说,promise是一个构造函数
2) 从功能上说,promise对象是用来封装一个异步操作并可以获取成功/失败结果的值。

3.2 为什么使用promise

使用promise的链式调用,可以解决回调地狱问题
1) 回调地狱:回调函数嵌套使用,外部回调函数异步执行的结果是嵌套的回调函数的条件。
2)回调地狱的缺点:不便于阅读、不便于异常处理
3) 解决回调地狱:promise的链式调用
指定回调函数的方式更加灵活
1)旧的:必须再启动任务之前指定回调函数
2)promise:启动异步任务=》返回promise对象=》给promise绑定回调函数(可以指定多个)

3.3 promise的状态——实例对象的属性

promise对象的三个状态
1) 初始化(等待中)的状态 pending
2) 请求成功的状态 fulfilled/resolved
3) 请求失败的状态 rejected
注意:promise的状态可以由等待中pending,变化为成功或者失败,但是改变为成功或者失败后是不能在改变的,也状态的改变是不可逆的。

3.4 promise对象的值——实例对象的属性(PromiseResult)

保存着异步任务成功/失败的值
resolve和reject可以改变该属性的值。err就是失败的值,data就是成功的值
const p = new Promise(function (resolve, reject) {
fs.readFile(“为学.md”, (err, data) => {
if (err) {//状态为失败,调用失败的回调函数
reject(err);
} else { //状态为成功,调用成功的回调函数
resolve(data.toString());
}

4 promise 的API

4.1Promise构造函数

4.1.1使用步骤

	1) 创建promise对象 new Promise(参数)   ,状态为等待 //该过程是同步调用的
	2) promise对象的参数是一个执行器函数,改函数具有两个参数(回调函数)即new Promise(function(resolve,reject)); reslove回调函数是执行成功时需要调用的回调函数,状态改变为成功,reject是执行失败时要调用的回调函数,状态改编为失败。
	3) 通过promise.then()和promise.catch()方法用于捕获promise成功或者失败的状态,并处理返回的结果。
读取文件的异步操作
// promise读取文件
// 1. 引入fs模块
const fs = require("fs");
// 2. 调用方法 err是返回错误,data为读取的数据
// 读取文件就是一个异步操作
const p = new Promise(function (resolve, reject) {
  fs.readFile("为学.md", (err, data) => {
    if (err) {//状态为失败,调用失败的回调函数
      reject(err); 
    } else { //状态为成功,调用成功的回调函数
      resolve(data.toString());
    }
  });
});
//调用promise对象的then方法
//第一个回调函数函数对应着resolve , 第二个回调函数对应着reject
p.then(
  function (value) {
    console.log(value);
  },
  function (reason) {
    console.log(reason);
  }
);

4.1.2 then()方法和catch()方法——指定回调

两者的区别
promise.then(function(p1){ }, function(p2){ })第一个函数捕获执行成功的状态,第二个函数捕获执行失败的状态。
promise.catch() 是对执行失败结果的处理,相当于,then的第二个函数操作

promise.then方法

  1. 只有状态改变,才会执行函数
  2. promise.then()的放回值类型仍是promise
/调用promise对象的then方法
//第一个回调函数函数对应着resolve , 第二个回调函数对应着reject
p.then(
  function (value) {
    console.log(value);
  },
  function (reason) {
    console.log(reason);
  }
);

promise.then() 可以只写一个回调函数

p.then(value=>{
     console.log(value);
})

3. 由于promise的返回值仍为promise,所以可以链式回调,避免回调地狱
p.then(value=>{
     console.log(value);
}).then(value=>{
     console.log(value);
})

promise.catch()方法
用于指定promise失败的回调,相当于的then()方法第二个函数

const fs = require("fs");
// 2. 调用方法 err是返回错误,data为读取的数据
// 读取文件就是一个异步操作
const p = new Promise(function (resolve, reject) {
  fs.readFile("为学.md", (err, data) => {
      reject(err);
  });
});
p.catch(function(value){
    log('error')//对应接收reject
})

5 Promise的对象方法

5.1 Promise.resolve方法(value)=>{}

   接收一个参数,返回一个成功或者失败的promise对象

1)传入的参数是非promise类型,返回结果均为成功的peomise
2)传入的结果是promise对象,则该参数的结果就决定了resolve的结果

//类型1  参数为非promsie类型
let p1 = Promise.resolve(123);
 console.log(p1);
 // 类型2 参数为promise类型
 let p2 = Promise.resolve(new Promise(function(reslove,reject){
            reject('error')  //状态为错误,结果值为error
        }))
console.log(p2);

类型1返回结果

类型2

5.2 Promise.reject()

接收一个参数,返回的都是失败的Promise对象,即使传入的是一个成功的promise对象,返回的也是失败的promise对象,失败的结果是传入的值。

5.3 Promise.all()方法 (promise)=>{}

(1)传入的参数是包含n个promise的数组
(2) 返回的是一个新的promise,只有所有的promise的状态都成功才返回状态成功,结果值为所有成功的promise成功结果值组成的数组,只要有一个状态失败就直接失败了,失败的结果值是失败的那个promise的结果值。

5.4 promise.race方法 (promises)=>{}

(1)接收的参数promise数组
(2)返回结果,一个新的promise,第一个完成promise的状态就是最终的结果状态(谁先改变状态,就输出谁的结果)

6. promise中的几个关键问题

6.1. 如何改变promise的状态

(1) resolve(value)将pending状态改为resolved
(2)reject(reason) 将pending改为rejected
(3)抛出异常,将pending改为rejected

const p = new Promise(function (resolve, reject) {
   // reslove('ok') ; //将pending-》resolved
   // reject('error'); //将pending改为rejected
    //抛出异常将pending改为rejected
    throw '出错了'
  });

6.2 一个promise指定多个成功/失败的回调函数,都会调用吗

指定回调函数用then()方法
答案:当promise改变为对应状态时,都会调用

let p =new Promise(function(resolve,reject){
            resolve('ok');//将状态改变为成功
        });
p.then(function(res){
            console.log(res);
        })
        //再次指定回调
p.then(res=>{
            console.log('再次调用');
        })

6.3 改变promise的状态和指定调用函数谁先谁后?

也就是resolve()/reject先执行;还是then()
(1)都有可能
正常情况下时先指定回调再改变状态:当执行器中是一个异步任务(居多)
但是也可能先改变状态再指定回调
(2) 如何先改变状态再指定回调
在执行器中直接调用resolve()/reject() //同步任务
延长更长的事件再调用then()
(3)什么时候才得到数据
如果先指定回调,当状态发生改变时,回调函数就会调用,就会得到数据
如果先改变状态,当指定回调时,回调函数就会调用,就会得到数据

6.4 promise.then()返回新promise的结果状态是由什么决定的

由then指定的回调函数执行的结果决定
(1)如果抛出异常,新promise的状态时rejected,返回值reason为抛出异常
(2)如果返回值为非promise的任意值,新promise为resolved, value为返回的值
(3)如果返回的是另一个新的promise,此promise的状态和返回值就变成了新promise的返回结果

6.5 promise如何串联多个操作任务

(1)promise的返回值仍是一个promise对象,可以使用then()的链式调用
(2)通过then的链式调用串联多个同步/异步任务

  let p = new Promise((reslove, reject) => {
            setTimeout(() => { //异步任务
                reslove('ok')
            }, 1000);
        });
  p.then(value => {
            console.log(value);  //ok
            return new Promise((reslove, reject) => {
                reslove('success');
            })
        }).then(value => {
            console.log(value); //success
        }).then(value => {
            console.log(value); //undefined
        })
       // 最后一个undefine的由来,then的返回值是一个promise对象,
       // 但是第二个then没有返回,默认为undefine,即第三个then的输入为undefined
       //,undefined不属于promise类型,所以最后返回的状态是成功,值为undefined 

6.6 promise的异常渗透

(1)当使用promise的then链式调用时,可以在最后指定失败的回调
(2)前面任何操作出现了异常,都会传到最后的回调中处理

 p.then(value => {
            console.log(value);  //ok
            return new Promise((reslove, reject) => {
                //reslove('success');
                reject('erroe')
            })
        }).then(value => {
            console.log(value); //success
        }).then(value => {
            console.log(value); //undefined
        }).catch(reason=>{
            console.log(reason)
           //只在最后指定错误的回调函数
           //中间的then有错误,也会执行这个回调函数
        })

6.7 终端promise链 p.then().then()

(1)当使用promise的then链式调用时,在中间中断,不再调用后边的回调函数
(2)办法: 再回调函数中返回一个pending状态的promise对象

 p.then(value => {
            console.log(value);  //ok
            return new Promise((reslove, reject) => {
                //reslove('success');
                reject('erroe')
            })
        }).then(value => {
            console.log(value); //success
            // 中段promise链,一个pending状态的promise对象
            reruturn new Promise(()=>{})
        }).then(value => {
            console.log(value); //undefined
        }).catch(reason=>{
            console.log(reason)
           //只在最后指定错误的回调函数
           //中间的then有错误,也会执行这个回调函数
        })

7. async函数

(1) 函数的返回值是promise对象
如果返回值是一个非promise类型,结果就是一个成功的promise
如果返回值是一个promise对象,该对象决定了async函数的返回结果
如果抛出异常,返回结果的状态为失败,值为抛出的值

async function main(){
    //retrun '521'   //第一种类型
    return new Promise((resolve,reject)=>{
        resolve('ok)  //第二种类型
    })
    //return throw 'error'  //第三种类型
}

(2) promise对象的结果由async函数执行的返回值决定

8. await表达式

(1) await的右侧一般为promise对象,也可以是其他的值
(2) 如果表达式时promise对象,await的返回值是promise成功的值
(3)如果表达式是其他值,直接将其值作为await的返回值
(4) await 必须写再async函数中,但async函数中可以没有它
(5) 如果await的promise是失败的,就会抛出异常,try。。catch异常处理

    async function main() {
            let p = new Promise((resolve, reject)=>{
                // resolve('ok');
                reject('error');
            });
            // let res = await p;
            // console.log(res);
            try {
                let res2 = await p;
            } catch (e) {
                console.log(e);
            }
        }

笔记来源:

https://www.bilibili.com/video/BV1GA411x7z1?p=45&spm_id_from=pageDriver

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值