一文看懂JavaScript中的Promise

  1. 一、Promise 是什么
  2. 二、使用
    1. 2.1 创建 Promise
    2. 2.2 执行顺序
    3. 2.3 用函数封装 Promise
  3. 三、高级用法
    1. 3.1 同时支持Callback与Promise
    2. 3.2 链式调用
    3. 3.3 Promise.all
    4. Reference

一、Promise 是什么

PromiseES6 提供的原生对象,用来处理异步操作

它有三种状态

  • pending: 初始状态,不是成功或失败状态。
  • fulfilled: 意味着操作成功完成。
  • rejected: 意味着操作失败。

二、使用

2.1 创建 Promise

通过 new Promise 来实例化,支持链式调用

new Promise((resolve, reject)=>{
  // 逻辑
}).then(()=>{
  //当上面"逻辑"中调用 resolve() 时触发此方法
}).catch(()=>{
  //当上面"逻辑"中调用 reject() 时触发此方法
})

2.2 执行顺序

Promise一旦创建就立即执行,并且无法中途取消,执行逻辑和顺序可以从下面的示例中获得

如下,可修改 if 条件来改变异步结果,下面打印开始的数字是执行顺序

在线调试此示例 - jsbin

console.log('1.开始创建并执行 Promise')
new Promise(function(resolve, reject) {
  console.log('2.由于创建会立即执行,所以会立即执行到本行')
  setTimeout(()=>{ // 模拟异步请求
    console.log('4. 1s之期已到,开始执行异步操作')
    if (true) {
        // 一般我们符合预期的结果时调用 resolve(),会在 .then 中继续执行
        resolve('成功')
    } else {
        // 不符合预期时调用 reject(),会在 .catch 中继续执行
        reject('不符合预期')
    }
  }, 1000)
}).then((res)=>{
  console.log('5.调用了then,接收数据:' + res)
}).catch((error)=>{
  console.log('5.调用了catch,错误信息:' + error)
})
console.log('3.本行为同步操作,所以先于 Promise 内的异步操作(setTimeout)')

执行结果如下

"1.开始创建并执行 Promise"
"2.由于创建会立即执行,所以会立即执行到本行"
"3.本行为同步操作,所以先于 Promise 内的异步操作(setTimeout)"
"4. 1s之期已到,开始执行异步操作"
"5.调用了then,接收数据:成功"

2.3 用函数封装 Promise

这是比较常用的方法,如下用 setTimeout 模拟异步请求,封装通用请求函数

在线调试此示例 - jsbin

// 这是一个异步方法
function ajax(url){
  return new Promise(resolve=>{
    console.log('异步方法开始执行')
    setTimeout(()=>{
      console.log('异步方法执行完成')
      resolve(url+'的结果集')
    }, 1000)
  })
}
// 调用请求函数,并接受处理返回结果
ajax('/user/list').then((res)=>{
  console.log(res)
})

执行结果

"异步方法开始执行"
"异步方法执行完成"
"/user/list的结果集"

三、高级用法

3.1 同时支持Callback与Promise

在线调试此示例 - jsbin

function ajax(url, success, fail) {

  if (typeof success === 'function') {
    setTimeout(() => {
      if (true) {
        success({user: '羊'})
      } else if (typeof fail === 'function') {
        console.log(typeof fail)
        fail('用户不存在')
      }
    }, 1000)
  } else {
    return new Promise((resolve, reject) => {
      this.ajax(url, resolve, reject)
    })
  }

}

// callback 调用方式
ajax('/user/get', (res)=>{
  console.log('Callback请求成功!返回结果:', res)
}, (error)=>{
  console.log('Callback请求失败!错误信息:', error)
})

// Promise 调用方式
ajax('/user/get').then((res)=>{
  console.log('Pormise请求成功!返回结果:', res)
}).catch((error)=>{
  console.log('Promise请求失败!返回结果:', error)
})

执行结果

Callback请求成功!返回结果: {user: "羊"}
Pormise请求成功!返回结果: {user: "羊"}

3.2 链式调用

.then 支持返回 Promise 对象进行链式调用

ajax('/user/info').then((res)=>{
  // 用户信息查询成功后,可以根据返回结果查询后续信息
  console.log('用户信息:', res)
  return ajax('/user/score')
}).then((res)=>{
  console.log('用户成绩:', res)
  return ajax('/user/friends')
}).then((res)=>{
  console.log('用户朋友:', res)
})

3.3 Promise.all

Promise.all 方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。
在线调试此示例 - jsbin

// 生成一个Promise对象的数组
var promises = [2, 3, 5, 7, 11, 13].map(function(id){
  return new Promise((resolve, reject)=>{
    if (id % 3 === 0) {
      resolve(id)
    } else {
      reject(id)
    }
  });
});
Promise.all(promises).then(function(post) {
  console.log('全部通过')
}).catch(function(reason){
  console.log('未全部通过,有问题id:'+reason)
});

执行结果

未全部通过,有问题id:2

Reference

mozilla web docs


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 jaytp@qq.com

×

喜欢就点赞,疼爱就打赏