与promise的第一次亲密接触

133 阅读5分钟

写这篇文章是为了更深入的了解promise,有不对的地方还希望小伙伴们能指出。

什么是promise?

从字面上理解,promise是承诺的意思,它承诺将来会给你一个答复。它是JavaScript中执行异步任务的新解决方案。(旧的是纯回调式的解决方案)promise是一个构造函数,它用来封装一个异步操作,并获取异步操作的结果。

promise能做什么?

1、指定回调函数的方式更加灵活,异步的回调如果提前不指定,一旦异步任务完成,就很容易错过需要获取的数据。promise可以在异步任务启动后指定一个时间去回调函数并获取数据。 2、支持链式调用,可以解决地狱回调问题(解决地狱回调的方案还有async/await)

promise的三种状态

promise内部有一个很重要的东西,就是状态。

1、 pending,等待状态,如正在进行网络请求,或者定时器没有到时间。

2、fulfill,满足状态,当我们主动回调resolved时,就处于满足状态,并且会回调.then()方法。

3、reject,拒绝状态,当我们主动回调reject时,就处于拒绝状态,并且会回调.catch()方法。

promise的状态改变

promise的状态改变只有两种,并且只能改变一次

1、pending—>resolved

2、pending—>rejected

无论状态的改变是成功还是失败,都会有一个结果,成功的结果是value,失败的结果是reason。

promise的执行流程

image.png

// 1、创建一个新的promise
    let test = new Promise((resolve,reject) => {
      // 2、异步操作
      setTimeout(() => {
        let time = Date.now() // 当前时间
        // 3、状态变更
        if(time%2 === 0) { // 如果当前时间是偶数,就调用resolve(value)
          resolve('当前时间是偶数'+time)
        } else { // 如果当前时间是奇数,就调用reject(season)
          reject('当前时间是奇数')
        }

      },1000) 
    }) 
    test.then(
      value => { // 接收成功的数据onResolved()
        console.log('成功',value)
    },
      reason => { // 接收失败的数据onRejected()
        console.log('失败',reason)
      }  
    )

image.png

image.png

手写一个promise

new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve('成功')
        // reject('失败')
      },1000)
    }).then(
      value => {
        console.log(value)
      }
    ).catch(
      reason => {
        console.log(reason)
      }
    )

解决地狱回调问题

什么是地狱回调?在弄懂地狱回调之前,我们首先需要明白两个概念:

1、什么是回调函数?

当一个函数(函数1)作为参数传递给另外一个函数(函数2)时,由另外一个函数(函数2)执行时来调用这个函数(函数1),这就是回调函数。主函数先执行,执行完成后将该函数作为参数传给下一个函数,

2、什么是异步任务?

当一个任务不进入主线程,被放到异步任务队列里,前一个任务的执行是否结束,不影响下一个任务的执行。这就是异步任务。 回调函数有两种类型

2.1同步调用回调函数

会立即执行,全部执行了以后才结束,不会放入回调队列中。

let array = [1,2,3,4,5]
array.forEach(item => {
    console.log(item)
})
console.log('执行顺序')

image.png

2.2异步调用回调函数

不会立即执行,会放入回调队列中将来执行。

setTimeout(() => {
   console.log('定时器内部')
 },0)
 console.log('定时器外部')

image.png

3、解决异步调用问题

// 成功的回调函数
      function successCallback(result) {
        console.log('成功了' + result)
      }
      // 失败的回调函数
      function failureCallback(error) {
        console.log('失败了' + error)
      }

先用纯回调的方法来解决一下这个问题

//  使用纯回调函数解决异步调用
  test(toDo, successCallback, failureCallback)

用promise解决

//  使用promise
      let promise = test(toDo)
      setTimeout(() => {
        promise.then(successCallback, failureCallback)
      },1000)

弄懂这些之后,我们来接着捋回调地狱,什么是回调地狱呢?写一段示例代码

// 地狱回调伪代码
      toDo1(function(result1) {
        toDo2(result1, function(result2) {
          toDo3(result2, function(result3) {
            console.log(result3)
          })
        })
      })

上段代码中,回调函数内部嵌套了回调函数,这种情况就叫做地狱回调。 现在,我们在上面学习的promise就可以出场来解决这个问题了。

// 使用promise的链式调用解决回调地狱
      toDo1()
      .then(function(result1) {
        return toDo2(result1)
      })
      .then(function(result2) {
        return toDo3(result2)
      })
      .then(function(result3) {
        console.log(result3)
      })
      .catch(failureCallback) // 失败的回调

当然promise不是地狱回调的唯一解决方法,还有一种解决方法是使用async/await来解决。

  // 使用async/await解决回调地狱
     async function request() {
       try {
         let result1 = await toDo1()
         let result2 = await toDo2(result1)
         let result3 = await toDo3(result2)
         console.log(result3) 
       } catch(error) {
        failureCallback(error)
       }
     } 

拓展知识

实例对象与函数对象

1、实例对象:

用new关键字创建出来的对象称为实例对象,简称对象。

let function = new Function() // Function是构造函数,function 是实例对象

2、函数对象:

当我们将一个函数当做对象使用时,就称为函数对象。函数本身就是一个对象。

let function = new Function()
console.log(Function.prototype) // Function是函数对象
Function.call({}) // 这行代码表示调用Function函数对象的call方法。

注:只有函数对象才有bind、call、apply等方法,实例对象上面没有这些方法。 小技巧:括号的左边是函数,点的左边是对象

ERROR的理解与处理

1、错误的类型

Error:所有错误的父类型 ReferenceError:引用错误,引用的变量不存在

console.log(a)

image.png

TypeError:类型错误,数据类型不正确

let a
console.log(a.xxx)

image.png

RangeError:范围错误,数据的值不在允许范围内

function demo() {
      demo()
    }
    demo()

image.png

SyntaxError:语法错误

let abc = " "" "

image.png

2、错误的处理

捕获错误:try…catch

try {
      let abc 
      console.log(abc.a)
    } catch(error) { // error对象里面有两个属性,message和stack
      console.log(error)
      console.log(error.message)
      console.log(error.stack)     
    }
    console.log('错误已被捕获')

image.png

抛出错误:throw error

function demo() {
      if(Date.now()%2===1) {
        console.log("当前时间为奇数")
      } else {
        throw new Error('当前时间为偶数')
      }
    }
    try{
      demo()
    } catch(error) {
      alert(error.message)
    }

image.png 抛出错误

image.png

3、错误对象

error是一个对象,它有两个属性

1、message属性:错误相关信息

2、stack属性:函数调用栈记录信息