Promise 阅读笔记

发布于 2022-05-04 12:38:29 字数 5448 浏览 1047 评论 2

为什么会有 promise?

根据官方的说法,promise 的出现是为了解决 callback hell 回调地狱,将横向的嵌套回调改为可以纵向以 then 的方式加载执行。

简介 & 用法

// 通过new Promise 得到一个promise的实例,也就是一个普通对象。
// 构造函数需要传一个 callback 去定义何时执行 resolve,reject 这两个函数
var promise = new Promise(function(resolve, reject) {
  if('code') { // code 可能是异步操作成功判断条件
    resolve()
  } else {
    reject()
  }
})
// then的两个参数(resolve, reject)
promise.then(function(){
  console.log('success')
},function(){
  console.log('failure')
})

三种状态

[[PromiseValue]] //内部属性 -- 状态
//而且这个状态不可随意更改,只跟resolve ,reject函数执行有关

实例内部有三种状态标示

  • Pending 进行中 即构造函数执行开始
  • Resolved 已成功 resolve函数 执行
  • Rejected 已失败 reject函数 执行

而且只能由Pending --> Resolved,Pending-->Rejected ,即成功或失败

这个状态变化的条件是由我们控制的。一个请求返回成功状态码... 等等

方法

Promise.prototype.then()

两个参数 resolve, reject

function getPromise (status) {
   return new Promise(function(resolve, reject) {
    let time = Date.now()
    console.log('time')
    setTimeout(()=>{
       if(status) {
         resolve(time)
       } else {
         reject(new Error('status error'))
       }
    },1000)    
  })
}

getPromise(1).then((time)=>{
  console.log('1',Date.now()-time)
  return Date.now()-time
},(err)=>{
  console.log(err,'err')
  return err
}).then((time)=>{
  console.log('2',time)
  return time
},(err)=>{
  console.log(err,'err')
  return err
}).then((time)=>{
  console.log('3',time)
},(err)=>{
  console.log(err,'err')
})

//
"time"
"1" 1002
"2" 1002
"3" 1002
//
// status传0
getPromise(0).then((time)=>{
  console.log('1',Date.now()-time)
  return Date.now()-time
}, (err)=>{
  console.log(err,'err')
  return err
}).then((time)=>{
  console.log('2',time)
  return time
},(err)=>{
  console.log(err)
  return err
}).then((time)=>{
  console.log('3',time)
},(err)=>{
  console.log(err)
})
//
"time"
[object Error] { ... } "err"
"2" [object Error] { ... }
"3" [object Error] { ... }
// 很有意思的是第一次promise 异步代码失败
执行reject, 但是后面的都是执行resolve,而且resolve的参数都已经是error对象了
  1. 这里我们定义了一个函数来返回一个promise实例,然后实例可以执行then。只要构造函数执行,里面的代码就会执行,异步代码也会放到异步队列,当异步代码执行完(这里就是我们的setTimeout),根据我们提供的条件,成功执行resolve,失败就reject。当然条件都是我们自己规定的,比如异步请求的code...
  2. 只要异步代码成功,我们的条件成功,就可以无限then。因为then传的resolve,reject 执行完都后,都会返回一个promise实例。另外,如果我们在resolve里return一个新的promise实例,那么这个promise实例将作为新的then的调用者。如果return一个非promise实例,都会作为参数传递给下面的resolve..
  3. 无论是成功的结果还是error信息,都会被一级级传递下来。利用此,举个栗子我们有三个请求,每个请求的参数都依赖于上一个请求的结果,用promise就很简洁... 另外收集错误也是可以做到的。

举个栗子

var getJson = function (url) {
  return new Promise(function (resolve, reject) {
    var xhr = new XMLHttpRequest ()
    xhr.open('get',url)
    xhr.onreadystatechange = callback
    xhr.responseType = 'json'
    xhr.send(null)
    function callback () {
      if(this.readyState !== 4) return
      if(this.status === 200) {
        resolve(this.response)
      }else{
        reject(new Error(this.statusText))
      }
    }
  })
}

getJson('api/list').then((response)=>{
    console.log(response)
    return getJson(response.url)
},(err)=>{
  console.log(err)
  return err
}).then((response)=>{
    console.log(response)
},(err)=>{
  console.log(err)
})
//这个就是典型的第二个请求的参数依赖于第一个请求返回的结果。

业务中还有那种比如两三个请求都成功了,我们才处理,渲染的。用promise都比较好处理

Promise.prototype.catch()

Promise.prototype.catch方法是.then(null, rejection)的别名,用于指定发生错误时的回调函数。

getPromise(0).then((time)=>{
  console.log('1',Date.now()-time)
  return Date.now()-time
},(err)=>{
  console.log(err,'err')
  return err
}).then(null,(err)=>{
  console.log(err,'err')
  return err
}).then(null,(err)=>{
  console.log(err,'err')
})

类似于我们上面的例子把后面两个 then 的 resolve 去掉 改为 null,也就是说,当我们需要在第二个 then 里面有目的的收集错误的时候,我们可以直接用catch方法,省去then写法的麻烦。类似于这样

getPromise(0).then((time)=>{
  console.log('1',Date.now()-time)
  return Date.now()-time
},(err)=>{
  console.log(err,'err')
  return err
}).catch((err)=>{
  console.log(err,'err')
  return err
}).catch((err)=>{
  console.log(err,'err')
})

当然我们不会写两个 catch。这里只是改写一下 then。更多详细的直接看 es6 入门里面,讲的很详细,因为 catch 我用的也不是很多。

Promise.all()

all 的主要用途就是多个请求,同时成功了,再做某事,参数是一个数组,数组里面是 Promise 实例

注意这个方法是构造函数上的方法,用于将多个 Promise 实例,包装成一个新的 Promise 实例

两个Promise,请求 1.getExams  2.getQuestion
Promise.all([getExams(examId), getQuestion(questionId)]).then((exams,questions)=>{
    console.log(exams,questions)
})

应用场景就是我们多个请求都成功,才能做什么。

Promise.race()

跟 all 用法类似,都是传多个promise对象。根据 race 的意思,我们大概知道是干嘛的了。哪个先完成,就返回哪个的数据。应用场景大概是两个服务器,比较哪个快。但是现在服务器 都会通过nginx 做负载均衡,也不需要前端去关注这些东西。

Promise.race([getExams(examId), getQuestion(questionId)]).then((data)=>{
    console.log(data)
})

race 还要一个应用场景就是可以做超时处理。

const timeOut = 3000;
const delay = function delay(time) {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(JSON.stringify({
        code: 0,
        msg: '请求超时',
      }));
    }, time);
  });
};

const response = Promise.race([delay(timeOut), fetch('api/list')]);

当 fetch 超过 3 秒,delay 的 promise 对象 resolve(),结果就会赋值给 response,此时的 response 读取到的已经是超时的。但是还是无法 abort 请求,这算是 promise 的一个痛点,本次笔记记录先到此,其实 API 书中都比较清楚了。关键还是项目中的应用。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

夜夜流光相皎洁 2022-05-04 12:53:29

不错,我写过源代码分析:
http://www.cnblogs.com/pzhu1/p/8365963.html

作死小能手 2022-05-04 12:52:09

总结的很不错,感谢博主的分享。。

~没有更多了~

关于作者

蓝颜夕

暂无简介

0 文章
0 评论
702 人气
更多

推荐作者

烙印

文章 0 评论 0

singlesman

文章 0 评论 0

独孤求败

文章 0 评论 0

晨钟暮鼓

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文