Promise

一、什么叫回调函数?

回调函数:被作为参数传给另外一个函数;

二、常见的内置错误

  • ReferenceError:引用的变量不存在
  • TypeError:数据类型不正确
  • RangeError:数据值不在其允许的范围内
  • SyntaxError:语法错误

三、错误的处理

  • 捕获错误
try {
  let b = null
  console.log(b.null)
} catch (err) {
    // err是一个对象,该对象中有两个属性
    // message(错误相关信息)和stack(函数调用栈记录信息)
  console.log(err.message)
  // Cannot read property 'null' of null
}
  • 抛出错误
function something() {
  if (Date.now() % 2 === 1) {
    console.log("当前时间为奇数,可以执行任务")
  } else { // 抛出异常,由调用来处理
    throw new Error("当前时间为偶数,无法执行任务")
  }
}
// 捕获处理异常
try {
  something()
} catch (error) {
  console.log(error.message)
}

四、为什么要用promise?

语法角度:Promise是一个构造函数
功能角度:Promise对象用来封装一个异步操作并可以获取结果;

五、Promise状态改变

1)pending变为resolved
2)pending变为rejected

只有这两种状态改变,且promise对象只能改变一次状态;无论成功还是失败,都会有一个结果数据;
成功的结果数据称为value,失败的结果数据称为reason

resolve(1)  // promise由pending状态变为resolved成功状态
reject(2)  // promise由pending状态变为rejected失败状态
throw new Error("出错了") 
// 抛出异常,promise变为rejected状态,reason值为抛出的error
throw 3 
// 抛出异常,promise变为rejected失败状态,reason为抛出的3

六、Promise基本运行流程

  • 创建一个Promise对象
 new Promise()需要传递一个参数
 这个参数是回调函数(执行器函数)
  • new Promise执行异步操作:
    • 成功的话,执行resolve函数——promise对象状态变为resolved状态——回调onResolved()函数(使用.then())——返回新的promise对象
    • 失败的话,执行reject函数——promise对象状态变为rejected状态——回调onRejected()函数(使用.then()或者.catch())——返回新的promise对象
<script type="text/javascript">
// 1.创建一个promise对象
const p = new Promise((resolve, reject) => { 
// 执行器函数 同步回调
  console.log("执行excutor")
// 2.执行异步操作任务
  setTimeout(() => {
    const time = Date.now()
    // 3.1. 如果成功了,调用resolve(value)
    if (time % 2 == 0) {
      resolve("成功的数据,time=" + time)
    } else {
    // 3.2. 如果失败了,调用reject(reason)
      reject("失败的数据,time=" + time)
    }
  }, 1000)
})
console.log("new Promise()之后")

p.then(
  value => { // 接收得到成功的value数据  onResolved
    console.log("成功的回调", value)
  }, 
  reason => { // 接收得到失败的reason数据   onRejected
    console.log("失败的回调", reason)
  }
)
</script>

// 执行excutor
// new Promise()之后
// 成功的回调 成功的数据,time=1618713417808

七、为什么要用Promise函数?

// 成功的回调函数
function successCallback(result) {
  console.log("声音文件创建成功:" + result)
}
// 失败的回调函数
function failureCallback(error) {
  console.log("声音文件创建失败:" + error)
}

// 1.1 使用纯回调函数
createAudioFileAsync(audioSetting, successCallback, 
failureCallback)

// 1.2 使用Promise
const promise = createAudioFileAsync(audioSetting);
setTimeout(() => {
  promise.then(successCallback, failureCallback)
}, 1000)
  • 支持链式调用,解决回调地狱问题;回调地狱:回调函数的嵌套使用,不便于阅读(多个串联的异步操作,第一个执行完再执行第二个);
// 2.1 回调地狱
doSomething(function(result) {
  doSomethingElse(result, function(newResult) {
    doThirdThing(newResult, function(finalResult) {
      console.log("Got the final result" + finalResult)
    }, failureCallback)
  }, failureCallback)
}, failureCallback)

// 2.2 使用promise的链式调用解决回调函数
// 编码从上往下写,不需要嵌套
// 异常传透:当任何一个执行出了问题,都会去执行catch()
doSomething().then(function(result) {
  return doSomethingElse(result)
}).then(function(newResult) {
  return doThirdThing(newResult)
}).then(function(finalResult) {
  console.log("Got the final result" + finalResult)
}).catch(failureCallback)

// 2.3 async / await:回调地狱的终极解决方案
async function request() {
  try {
    const result = await doSomething()
    const newResult = await doSomethingElse(result)
    const finalResult = await doThirdThing(newResult)
    console.log("Got the final result" + finalResult)
  } catch (err) {
    failureCallback(error)
  }
}
  • 指定回调函数的方式更加灵活:可以先指定回调函数再改变状态,也可以先改变状态再指定回调函数;但是之前的方法只能先指定回调函数(一般情况下,先指定回调函数,再改变状态,使用setTimeout)
promise:启动异步任务——返回promise对象
——给promise对象绑定回调函数
new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve(1) // 后改变状态(同时指定数据),异步执行回调函数
  }, 1000)
}).then( // 先指定回调函数,先保存当前指定的回调函数
  value => {console.log(value)}, // 1
  reason => {console.log("reason", reason)}
)


new Promise((resolve, reject) => {
  resolve(1) // 先改变状态(同时指定数据)
}).then( // 后指定回调函数,异步执行回调函数
  value => {console.log(value)}, // 1
  reason => {console.log("reason", reason)}
)

八、Promise的API

Promise.all() all是函数对象的方法;

Promise.prototype.then() 所有的实例对象都可以调用then()方法,then是原型对象的方法;

1. Promise构造函数:Promise(excutor) {}
excutor函数:同步执行(resolve, reject) => {}
resolve函数:内部定义成功时,立刻调用函数 value => {}
reject函数:内部定义失败时,立刻调用函数 reason => {}
说明:excutor会在Promise内部立即同步回调,异步操作在执行器中执行

2.Promise.prototype.then方法:(onResolved, onRejected)
onResolved函数:成功的回调函数(value) => {}
onRejected函数:失败的回调函数(reason) => {}
说明:指定用于得到成功value的成功回调和用于得到失败reason的失败回调,
会返回一个新的promise对象

3.Promise.prototype.catch方法:(onRejected) => {}
onRejected函数:失败的回调函数 (reason) => {}
说明:then()的语法糖,相当于:then(undefined, onRejected)

4.Promise.resolve方法:(value) => {}
value:成功的数据或者promise对象
说明:返回一个成功/失败的promise对象

5.Promise.reject方法:(reason) => {}
reason:失败的原因
说明:返回一个失败的promise对象

6.Promise.all方法:(promises) => {}
promises:包含n个promise的数组
说明:返回一个新的promise,只有所有的promise都成功才成功,
只要有一个失败就直接失败

7.Promise.race方法:(promises) => {}
promises:包含n个promise的数组
说明:返回一个新的promise,第一个完成的promise的结果状态
就是最终的结果状态;

Promise.all()

let wake = (time) => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(`${time / 1000}秒后醒来`)
    }, time)
  })
}

let p1 = wake(3000)
let p2 = wake(2000)

Promise.all([p1, p2]).then((result) => {
  console.log(result)       // [ '3秒后醒来', '2秒后醒来' ]
}).catch((error) => {
  console.log(error)
})

九、promise.then()返回的新的promise对象的状态由什么决定

  • 简单表达:由then()指定的回调函数执行的结果决定;
  • 详细表达:
    • 如果抛出异常,新promise状态变为rejected,reason为抛出的异常;
    • 如果返回的是非promise的任意值,则新promise的状态变为resolved,value为返回的值(没有return的话,value为undefined,否则,为return 后面的值)
    • 如果返回一个新的promise对象,则此promise的状态由新promise对象的状态决定
new Promise((resolve, reject) => {
  resolve(1) 
}).then(
  value => {
  	console.log("onResolved1()", value);
  	return Promise.reject(3)
  },  
  reason => {console.log("onRejected1()", reason)} 
).then(
  value => {console.log("onResolved2()", value)},  
  reason => {console.log("onRejected2()", reason)} 
)

十、Promise串联多个操作任务

new Promise((resolve, reject) => {
  setTimeout(() => {
    console.log("执行任务1(异步)")
    resolve(1)
  }, 1000)
}).then(
  value => {
    console.log("任务1的结果:", value);
    console.log("执行任务2(同步)");
    return 2
  }
).then(
  value => {
    console.log("任务2的结果:", value)
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        console.log("执行任务3(异步)")
        resolve(3)
      }, 1000)
    })
  }
).then(value => {
  console.log("任务3的结果:", value)
})

// 执行任务1(异步)
// 任务1的结果: 1
// 执行任务2(同步)
// 任务2的结果: 2
// 执行任务3(异步)
// 任务3的结果: 3

十一、Promsie异常传透

  • 使用promise的then链式调用时,可以在最后指定失败的回调;

  • 前面任何操作出了异常,都会传到最后失败的回调中处理;(不是一下到了最后的失败回调函数,而是逐层传下的)

十二、中断Promise链

  • 当使用promise的then()链式调用时,在中间中断,不再调用后面的回调函数
  • 办法:在回调函数中返回一个pending状态的promise对象
    return new Promise(() => {})
new Promise((resolve, reject) => {
  resolve(1)
}).then(
  value => {
    console.log("onResolved1()", value);
    return 2
  }
).then(
  value => {
    console.log("onResolved2()", value)
    return new Promise(() => {})
     // 返回一个pending状态的Promise
  }
).then(value => {
  console.log("onResolved3()", value)
}).catch(reason => {
  console.log("onRejected()", reason)
})

十三、async / await

async确保函数返回一个promise,如果代码中return <非promise> ,则JS会自动把返回的value包装成promise中resolve的参数;

async function f() {
  return 2
}
f().then(value => {
  console.log(value) // 2
})


// await等待当前promise执行完,才能往下执行其他的JS代码
async function f() {
  return await new Promise((resolve, reject) => {
    resolve(3)
    reject(5)
  })
}
f().then(value => {
  console.log(value) // 3
})

使用async / await

let fs = require("fs")
async function f(filePath) {
  return await new Promise((resolve, reject) => {
    fs.readFile(filePath, "utf-8", (err, data) => {
      if (err) {
        reject(err)
      }
      resolve(data)
    })
  })
}

f("C:/Users/Jayson柴/Desktop/11.txt").then(res => {
  console.log(res)
  return f("C:/Users/Jayson柴/Desktop/22.txt")
}).then(res => {
  console.log(res)
  return f("C:/Users/Jayson柴/Desktop/33.txt")
}).then(res => {
  console.log(res)
})
// 11 22 33

使用promise

let fs = require("fs")
function f(filePath) {
  return new Promise((resolve, reject) => {
    fs.readFile(filePath, "utf-8", (err, data) => {
      if (err) {
        reject(err)
      }
      resolve(data)
    })
  })
}

f("C:/Users/Jayson柴/Desktop/11.txt").then(res => {
  console.log(res)
  return f("C:/Users/Jayson柴/Desktop/22.txt")
}).then(res => {
  console.log(res)
  return f("C:/Users/Jayson柴/Desktop/33.txt")
}).then(res => {
  console.log(res)
})
// 11 22 33

十四、自定义Promise

// 自定义Promsie函数模块
(function(window) {
  // Promise构造函数
  // excutor:执行器函数(同步执行)
  function Promise(excutor) {
    // 把当前promise对象存起来
    const self = this
    self.status = "pending"
    self.data = undefined
    self.callbacks = [] // 元素的结构:{onResolved() {}, onRejected() {}}
    
    
    function resolve(value) {
      // 如果当前状态不是pending,直接结束
      // 意思就是如果前面执行过resolve或者reject,就不再执行
      if (self.status !== "pending") {
        return
      }
      // 将状态改为resolved
      self.status = "resolved"
      // 保存value数据
      self.data = value
      // 如果有待执行的callback函数,立即异步执行回调onResolved
      if (self.callbacks.length > 0) {
        setTimeout(() => { 
          self.callbacks.forEach(callbacksObj => {
            callbacksObj.onResolved(value)
          })
        })

      }
    }
    function reject(reason) {
      // 如果当前状态不是pending,直接结束
      // 意思就是如果前面执行过resolve或者reject,就不再执行
      if (self.status !== "pending") {
        return
      }
      // 将状态改为rejected
      self.status = "rejected"
      // 保存value数据
      self.data = reason
      // 如果有待执行的callback函数,立即异步执行回调onRejected
      if (self.callbacks.length > 0) {
        setTimeout(() => { 
          self.callbacks.forEach(callbacksObj => {
            callbacksObj.onRejected(reason)
          })
        })

      }      
    }
    // 立即同步执行excutor
    try {
      excutor(resolve, reject)
    } catch (error) { // 如果执行器抛出异常,promise对象变为rejected状态
      reject(error)
    }
  }
  // Promise原型对象的then()
  // 指定成功和失败的回调函数,返回一个新的promise对象
  Promise.prototype.then = function (onResolved, onRejected) {
    //假设当前状态是pending状态,将回调函数保存起来
    this.callbacks.push({onResolved, onRejected})
  }

  // Promise原型对象的catch()
  // 指定失败的回调函数,返回一个新的promise对象
  Promise.prototype.catch = function (onRejected) {

  }

  //Promsie函数对象resolve方法
  // 返回一个指定结果的成功的promise
  Promise.resolve = function(value) {

  }

  //Promsie函数对象reject方法
  // 返回一个指定reason的失败的promise
  Promise.reject= function(reason) {

  }

  //Promsie函数对象all方法
  // 返回一个promise,只有当所有promise都成功才成功
  // 只要有一个失败的就失败
  Promise.all= function(promises) {

  }

  //Promsie函数对象race方法
  // 返回一个promise,其结果由第一个完成的promise决定
  Promise.race= function(promises) {

  }

  // 向外暴露Promise函数
  window.Promise = Promise

})(window)

十四、自定义Promise.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>自定义promise</title>
  <style type="text/css">

  </style>

</head>

<body>
<script src="./promise.js" type="text/javascript"></script>
<script type="text/javascript">
  const p = new Promise((resolve, reject) => {
    setTimeout(() => {
      // resolve(1) // value
      reject(2) // reason     
    }, 100)
  })

  p.then(value => {
    console.log("onResolved1()", value)
  }, reason => {
    console.log("onRejected1()", reason)
  }) 

  p.then(value => {
    console.log("onResolved2()", value)
  }, reason => {
    console.log("onRejected2()", reason)
  })
</script>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值