Promise笔记(一)

(参照尚硅谷教学视频,带了点自己的理解)

前期准备

一些概念

实例对象与函数对象

首先,我们要知道什么是函数,函数就是Function的一个实例,如

function Hello(){
    console.log('hello')
}

当我们用new的方式去调用该函数时,它就充当了构造函数的作用,返回一个实例对象,如

var h = new Hello();  //此时Hello为构造函数,它返回了一个实例对象

那么什么时候Hello为函数对象呢?当Hello调用.XXX的时候,它就作为一个函数对象了,如

Hello.bind({})

因为Hello其实它本身是由Function构造函数构造出来的,所以其也能调用Fuction.prototype里的一些方法,如bind,call,apply等。

同步回调与异步回调

同步回调就是回调函数会立即执行,由于高阶函数必须等待同步回调执行完成,所以同步回调也称为阻塞回调——回调的执行会阻塞调用者函数的执行。如:数组的forEach,map,filter等

异步回调就是回调函数不会立即执行,它会把回调函数放入到回调队列中等待处理,如:定时器回调,ajax回调等。高阶函数是派发回调任务的函数,而不是运行它的函数。

要检验一个回调函数是同步回调还是异步回调,只需要在回调函数内部和之后的地方打一个输出,然后观察输出的先后顺序即可。

常见的内置Error

ReferenceError:引用的变量不存在。如

console.log(a) //a没有声明

TypeError:数据类型不正确,有两种常见情景会引发这个错误。

第一个情景

var a = null
console.log(a.xxx)  //报错:cannot read property 'xxx' of null

第二个情景

var a = {}
a.xxx()  //报错:a.xxx is not a function

RangeError:其值超出了该类型允许的范围,如

function fn(){
    fn()
}

fn()
//报错:maximum call stack size exceeded
//递归次数超出了递归调用栈允许的调用次数

SyntaxError:语法错误,如

a=""""

错误处理

try..catch..捕获错误

我们可以把可能出错的代码段放入try语句块中,在catch语句块中做相应的错误处理,如

try{
    var a = null
    console.log(a.xxx)
}
catch(err){
    console.log(err)
}

另外,如果想看err对象里的详细内容,可以通过以下操作查看。

1. 在F12->source中点击对应的代码文件,在catch块中对代码打断点(直接点击行数就是打断点),如图所示:

 2. 重新刷新页面后,在souce界面中的右侧应该能看到具体的err信息,如图所示

 这里可以看到error主要有两个属性:message和stack,message描述了错误信息,stack是错误的调用堆栈信息。

通过throw new Error()主动抛出错误

这种情况更适合处理不是内置错误的情况,如:

    function divide(a, b) {
        if (b === 0) throw new Error("被除数为0,结果溢出");
        return a / b;
      }

      try {
        divide(100, 0);
      } catch (error) {
        console.log(error);
      }

promise的理解和使用

promise是什么

1. 抽象表达:promise是js中解决异步编程的新的解决方案(旧的是谁?什么是异步编程?)

2. 具象表达:从语法层面讲,promise就是一个构造函数,从功能层面讲,promise对象可以封装异步操作并获取其结果

补充:关于第一点中的,旧的是谁?什么是异步编程?

在没有出现promise之前,都是通过回调函数的方式来实现异步编程的。那么,什么是异步编程呢?

首先,要知道什么是异步和同步,同步是指按照代码的书写顺序一行行的去执行,上一段代码执行完毕才能执行下一段代码,平时我们编写的js代码都是同步代码,但在某些场景下如设置定时器,发送Ajax请求,事件绑定这些我们编写的才是异步代码。异步可以理解为一种并行的处理方式,被系统认为是异步的任务(代码块),系统会把这个任务丢到一个队列中,然后继续执行同步代码,这样做的好处是如果该任务耗时较长则不会阻塞主线程(同步代码)的执行。在第一次同步代码执行结束后,系统会开始从任务队列中取出之前的回调函数执行。

在编写异步代码时,我们有时会遇到这样的需求,比如先发起一个ajax请求,在这个请求返回数据后,再发起一个ajax请求并且要附带前面返回的数据,那么这里就涉及到一个同步等待结果的问题,也就是异步编程的问题了。在promise出现之前,传统的解决方式是,给请求的api传入一个回调函数,在结果返回时API会自动调用这个回调函数,通常这种回调的参数API都会设计好给我们。但这样也会存在一些瑕疵,后面会讲。

promise状态改变

promise有三种状态,分别是pending,resolved,rejected。

如果在new promise的过程中没有调用resolve或者reject,那么promise对象默认是pending状态;

如果调用了resolve,那么对象为resolved状态;

如果调用了reject,那么对象为rejected状态。

而且,一旦状态变为resolved或者rejected后,状态就不再改变。

 为什么要用promise

1. 指定回调函数的方式更加灵活

        对于旧方式,必须在启动异步任务前指定好回调函数。

        这就是我所说的那个瑕疵,回调函数什么时候给?只能在api传递回调参数的时候给,如果我想用这个返回结果的时机不是在结果马上返回后呢,这就有点麻烦了,目前我想到的解决办法就是用一个全局变量来接收结果,然后在想用的时机用上。

        对于新方式promise,在启动异步任务后会得到一个promise对象,我可以在我想要的时机调用then方法,并设置成功和失败的回调函数,而不需要考虑如何保存上一个异步任务返回的结果。

2. 支持链式调用,避免回调地狱。

        什么是回调地狱?举个例子,我发起一个请求A等待响应结果,然后再拿这个响应结果发起请求B等待响应结果,再拿这个响应结果发起请求C。

requestA(data,success(resp1){
    requestB(resp1,success(resp2){
        requestC(resp2,success(resp3){
            ...
        })
    })
})

        我们发现上面代码大量使用了回调函数(将一个函数作为参数传递给另个函数)并且有许多 })结尾的符号,使得代码看起来很混乱,这就叫回调地狱。

        在Promise中,因为Promise.then方法会返回一个promise对象,这个对象中有一个状态表示这个承诺是否被实现了,以及保存了对应的结果数据,比如如果状态是resolved,那么当你在then方法中设置成功的回调时,then就会调用你这个回调并且将成功的结果数据带进去,因此可以利用then方法进行链式调用,正好避免了回调地狱的问题。例子代码如下:

//假设request方法返回的是一个promise对象
requestA(data)
.then((resp)=>{
    return requestB(resp)
})
.then((resp)=>{
    return requestC(resp)
})
.catch(err=> console.error(err))

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值