最近在搞秋招,发现自己的还有很多不足,特地的来复习一下之前所学的知识,坐下笔记巩固一下


代码实现

类似于发布订阅模式的状态存储-来实现异步的回调

  1. class Promise(){
  2. constructor(executor){ // executor 自执行函数
  3. this.state = 'pending' // 设置默认的状态 一共有 pending fulfilled rejected
  4. this.value = undefined // 设置成功时 存储返回的值
  5. this.reason = undefined // 设置失败时 存储失败的原因
  6. this.onFulfilledCallback = [] //存储成功时的回调函数
  7. this.onRejectedCallback = [];
  8. // 分别定义 resolve reject函数定义状态触发时的执行方法
  9. this.resolve = value=>{
  10. if(this.state === 'pending'){
  11. this.state = 'fulfilled'
  12. this.value = value
  13. this.onFulfilledCallback.forEach(fn=> f())
  14. }
  15. }
  16. this.reject = reason=>{
  17. if(this.tate === 'pending'){
  18. this.state = 'rejecteed'
  19. this.reason = reason
  20. this.onRejectedCallback.forEach(fn=> fn())
  21. }
  22. }
  23. try{
  24. executor(reslove,reject)
  25. }catch(e){
  26. reject(e)
  27. }
  28. }
  29. // 定义then方法
  30. then() .....
  31. }

实现then异步调用

  1. class Promis(){
  2. constructor(executor){ .....
  3. then(onFulfilled,onRejected){
  4. // 如果没有函数的设置适配器(默认函数)
  5. onFulfilled = typeOf onFulfilled === 'function' ? onFulfilled : value=> value;
  6. onRejected = typeOf onRejected === 'function' ? onRejected err = {throw err}
  7. let promise2 = new Promise((resolve,reject)=>{
  8. //三种状态
  9. // ————成功
  10. if(this.state === 'fulfilled'){
  11. setTimeout(()=>{
  12. var x = onFulfilleded(this.value) // 先执行当前then的回调函数, 并得到返回值
  13. reslovePromise(promise2,x,reslove,reject) // 如果有返回值执行自定义的函数
  14. },0)
  15. }
  16. // ———失败
  17. if(this.state === 'rejected'){
  18. setTimeout(()=>{
  19. var x = onRejected(this.value)
  20. reslovePromise(promise2,x,reslove,reject)
  21. },0)
  22. }
  23. // ———异步中(还在pending)
  24. if(this,state === 'pending'){ // 此时为异步调用分别将他们的函数推入定义的执行栈
  25. this.onFulfilledCallback.push(
  26. setTimeout(()=>{
  27. let x = oFulfilled(this.value)
  28. reslovePromise(promise2,x,reslove,reject)
  29. },0)
  30. )
  31. this.onRejectedCallback.push({
  32. setTimeout(()=>{
  33. let x = onRejected(this.reason)
  34. reslovePromise(promise2,x,reslove,reject)
  35. },0)
  36. })
  37. }
  38. })
  39. }
  40. }

问题1——为啥能实现异步的回调呢

我们来看看最初实现异步操作的—回调

  1. // f1 假设它为异步的操作
  2. function f1(){
  3. setTimeout(()=>{ja
  4. ... 执行f1后面的操作
  5. f2(); // 执行f2()
  6. },1000)
  7. }
  8. //这样就保证了f2的在f1后面执行-保障了执行的顺序

我们来看看promise是怎么定义的

  1. var p = new Promise(resolve=>{
  2. fs.readFile('input.txt', function (err, data) {
  3. if (err) {
  4. return console.error(err);
  5. }
  6. resolve(data)
  7. });
  8. })

她其实也是将后续操作(回调函数等)定义到后面,
1.所以当promise执行当then时发现异步函数还未执行完,于是将他推入执行栈内,
2.当异步函数执行完之后,执行resolve函数,这就像是自执行的订阅行为,(当异步函数还没执行完的时 候,发布其回调函数给promise,当执行完之后调用resolve订阅得到函数)

问题2——为啥要使用setTimout呢

如果在then方法注册回调之前,resolve函数就执行了,怎么办?比如promise内部的函数是同步函数

  1. function getUserId() {
  2. return new Promise(function (resolve) {
  3. resolve(9876);
  4. });
  5. }
  6. getUserId().then(function (id) {
  7. // 一些处理
  8. });

Promises/A+规范明确要求回调需要通过异步方式执行,用以保证一致可靠的执行顺序。因此我们要加入一些处理,保证在resolve执行之前

实现relovePromise函数

  1. function reslovePromise(promise2,x,reslove,reject){
  2. // 防止自身循环调用
  3. if(x === promise2){
  4. return reject(new TypeError('Chaining cycle detected for promise'))
  5. }
  6. let called = false // 检测他是否调用过
  7. if(x !== null && (typeof x === 'function' || typeof x === 'object')){
  8. // 返回的是一个promise对象
  9. try{
  10. const then = x.then;
  11. if(typeof then === 'fuction'){
  12. then.call(x,value=>{
  13. if(reject) return
  14. reject = true
  15. reslovePromise(promise2,value,resolve,reject)
  16. },reason=>{
  17. if(reject) return
  18. reject = true
  19. reject(reason)
  20. })
  21. }else{
  22. if(reject) return
  23. reject = true
  24. resolve(x)
  25. }
  26. }catch(e){
  27. if(reject) return
  28. reject = true
  29. reject(e)
  30. }
  31. }else{
  32. // 返回的是一个普通的值
  33. relove(x)
  34. }
  35. }

问题3——什么时候会发生循环调用

  1. let p = new Promise( resolve =>{
  2. resolve(x)
  3. })
  4. let p2 = p.then( ()=>{
  5. return p2
  6. })

问题4——为什么要使用try-catch语句

  1. var obj = {};
  2. Object.defineProperty(obj,'a',{
  3. get:function () {
  4. return new Error('hhhhh');
  5. }
  6. })

当对象定义了defineProperty的时候,如获取属性时抛出错误,就会发生错误

问题4——called是干啥的

peomise要保证内的状态的变化是单向的,当一次执行时内部的状态发生了改变,就不允许再次调用;