Promise

46 阅读5分钟

是什么

1.1理解

  • 是js发展到ES6之后出现的一种异步编程的解决方案(避免旧版的回调地狱)

  • 常见异步操作:文件读取 数据库操作 ajax 定时器

  • 语法上看,主要通过Promise构造函数的resolve reject all race allSettled 方法

  • 功能上看,主要在Promise构造函数封装一个异步操作,并获取成功/失败的返回值

1.2 状态改变

  • 每一个promise实例,都有三种状态 pending fullfilled rejected,通过实例的PromiseState存储。
  • 其状态的改变遵循一定规律。
    1. 只要在构造函数的参数function中,判断异步操作成功,那么通过resolve方法,传参value,此时状态从pending->fullfilled.
    2. 只要在构造函数的参数function中,判断异步操作失败,那么通过reject方法,传参resaon,此时状态从pending->rejected.
    3. 最终promise的状态只有这两种,不会有其他。
    4. 1和2操作之后状态从进行中变成成功过/失败,每个promise对象只改变一次
    5. 无论promise成功还是失败状态,都会有一个最终的数据结果。成功结果通过resolve参数传递,失败结果通过reject参数传递resaon

1.3Promise基本流程

image.png

1.4基本使用

new Promise(function(resolve, reject){
    // 执行异步操作
    if(){
        resolve(value)
    } else {
        reject(reason)
    }
})
  • new之后会生成实例对象promise,他的状态由PromiseState存储,值为fulfilled/rejected;结果由value存储,为resolve()和reject()的参数。
  • 构造函数接受函数作为参数,该函数在实例化的时候会立即执行。该函数有两个参数resolve函数 和 reject函数,这两个函数由js引擎提供,用户自己不用声明。
  • resolve函数的作用是,将Promise对象的状态从进行中变成成功,在异步操作成功时调用,并将异步返回的结果value,通过参数传递出去。
  • reject函数的作用是,将Promise对象的状态从进行中变成失败,在异步操作失败时调用,并将异步操锁失败的原因reason,通过参数传递出去。
  • promise实例生成后,可以通过.then()分别指定状态为fulfilled和rejected的回调函数,并且调用promise实例调用.then之后会生成新的Promise实例对象
promise.then(function(value){
    },function(reason){
    }
 )

then方法可以接受两个回调函数作为参数。

第一个回调函数onResolved()是Promise对象的状态变为resolved时调用

第二个回调函数onRejected()是Promise对象的状态变为rejected时调用

这两个函数都是可选的,不一定要提供。它们都接受Promise对象传出的值作为参数

为什么要用Promise

指定回调函数方法更加灵活

旧版本 启动异步操作前,就要制定好回调函数

// 1. 纯回调的形式
// 成功的回调函数
function successCallback(result) {
  console.log("声音文件创建成功:" + result);
}
// 失败的回调函数
function failureCallback(error) {
  console.log("声音文件创建失败:" + error);
}
// 必须先指定回调函数,再执行异步任务
createAudioFileAsync(audioSettings, successCallback, failureCallback) // 回调函数在执行异步任务(函数)前就要指定

Promise 执行异步操作->改变promise状态->绑定不同状态的回调函数

// 2. 使用Promise
const promise = createAudioFileAsync(audioSettings);  // 执行2秒
setTimeout(() => {
  promise.then(successCallback, failureCallback) // 也可以获取
}, 3000);

支持链式调用,解决回调地狱

回调地狱是什么?

回调函数嵌套调用,外层回调函数的执行结果是内层回调函数的参数,或依赖条件

doSomething(function(result) {
  doSomethingElse(result, function(newResult) {
    doThirdThing(newResult, function(finalResult) {
      console.log('Got the final result:' + finalResult)
    }, failureCallback)
  }, failureCallback)
}, failureCallback)

可见,外层函数执行完,通过执行结果,才能调用内层函数,并且每层回调函数的异常处理函数都要作为回调函数的第二个参数传递,也很冗余

缺点

  • 不便于阅读
  • 不便于异常处理

解决方案

promise链式调用

doSomething()
  .then(result => doSomethingElse(result))
  .then(newResult => doThirdThing(newResult))
  .then(finalResult => {console.log('Got the final result:' + finalResult)})
  .catch(failureCallback)

如何使用Promise

3.1 Promise 构造函数:Promise(executor) {}

  • executor 函数:同步执行 (resolve, reject) => {}
  • resolve 函数:内部定义成功时调用的函数 resove(value)
  • reject 函数:内部定义失败时调用的函数 reject(reason)

executor 是执行器,会在 Promise 内部立即同步执行,异步操作 resolve/reject 就在 executor 中执行

3.2 Promise.prototype.then 方法:p.then(onResolved, onRejected)

指定两个回调(成功+失败)

  • onResolved 函数:成功的回调函数 (value) => {}
  • onRejected 函数:失败的回调函数 (reason) => {}

指定用于得到成功 value 的成功回调和用于得到失败 reason 的失败回调,返回一个新的 promise 对象

3.3 Promise.prototype.catch 方法:p.catch(onRejected)

指定失败的回调

  • onRejected 函数:失败的回调函数 (reason) => {}

说明:这是then() 的语法糖,相当于 then(undefined, onRejected)

3.4 Promise.resolve 方法:Promise.resolve(value)

**作用:**返回一个带着给定值解析过的 Promise 对象

value:将被 Promise 对象解析的参数,也可以是一个成功或失败的 Promise 对象

如果参数本身就是一个 Promise 对象,则直接返回这个 Promise 对象

1、如果传递的参数时非promise类型,那么返回值为value,状态为成功的promise实例

let p1 = Promise.resolve(521);
console.log(p1); // Promise {<fulfilled>: 521}

2、如果传递的是promise类型,那么promise参数的结果决定了resolve结果

let p2 = Promise.resolve(new Promise((resolve, reject) => {
    // resolve('OK'); // 成功的Promise
    reject('Error');
}));
console.log(p2); // Promise {<rejected>: Error}
p2.catch(reason => {
    console.log(reason);
})

3.5 Promise.reject 方法:Promise.rejec(value)

作用:返回一个失败结果的promise对象

reason: 失败的原因

let p = Promise.reject(521);
let p2 = Promise.reject('iloveyou');
let p3 = Promise.reject(new Promise((resolve, reject) => {
    resolve('OK');
}));

console.log(p);
console.log(p2);
console.log(p3);   //reject 就算返回的promise调用的是resolve,结果仍然是rejected

Promise.resole()和Promise.reject()都是快速得到promise对象的语法糖