Promise

promise

Promise是一种异步编程的解决方案, 异步抽象处理对象

  • 三种状态,pending(进行中)、resolved(已完成)、rejected(已失败)

  • 一旦状态改变,就不会再变,任何时候都可以得到这个结果

  • 可传入函数作为参数,函数的参数:resolve, reject

  • 回调函数: .then, .catch, .finally

    • .then:异步执行的

    • .catch:在链式写法中可以捕获前面then中发送的异常

      • 都会返回一个新的Promis
      • 返回的值不能是 promise 本身,否则会造成死循环
      • 参数期望是函数,传入非函数则会发生值穿透
    • .finally: 返回一个Promise,他在Promise结束的时候,无论结果为resolved还是rejected,都会执行里面的回调函数

缺点:

1. 无法取消 Promise,一旦新建它就会立即执行,无法中途取消
2. 内部抛出的错误,不会反应到外部
3. 当处于 Pending 状态时,无法得知目前进展到哪一个阶段

解决:

1. 回调地狱
2. 支持多个并发的请求,获取并发请求中的数据

方法

  • promise.all[{}]: 等待一个结果返回才会执行下一个(根据看谁跑的慢的原则)
    • 如果有一个函数执行为reject,那么全部状态都为rejected
    • 会等全部函数执行完毕,同时返回
  • promise.race[{}]:哪个结果获得的快,就返回那个结果(根据看谁跑的快的原则)

注意

Promise.resolve(1)
   .then(2)
   .then(Promise.resolve(3))
   .then(console.log)

  输出结果:1
  解题思路:Promise的then方法的参数期望是函数,传入非函数则会发生值穿透。

all

    // then方法不会被执行, catch方法将会被执行,输出结果为:2
    var   p1 = Promise.resolve(1),
          p2 = Promise.reject(2),
          p3 = Promise.resolve(3);
    Promise.all([p1, p2, p3]).then((res)=>{
        console.log(results);
    }).catch((err)=>{
        console.log(err);
    });
    
    // 10s之后输出[1,10,5]
    let p1 = new Promise((resolve)=>{
      setTimeout(()=>{
        console.log('1s') //1s后输出
        resolve(1)
      },1000)
    })
    let p10 = new Promise((resolve)=>{
      setTimeout(()=>{
        console.log('10s') //10s后输出
        resolve(10)
      },10000)
    })
    let p5 = new Promise((resolve)=>{
      setTimeout(()=>{
        console.log('5s') //5s后输出
        resolve(5)
      },5000)
    })
    Promise.all([p1, p10, p5]).then((res)=>{
        console.log(res); // 最后输出
    })

race

  • 数组中的元素实例那个率先改变状态,就向下传递谁的状态和异步结果。但是,其余的还是会继续进行的
    // 结果: 1s, 1, 5s, 10s
    let p1 = new Promise((resolve)=>{
      setTimeout(()=>{
        console.log('1s') //1s后输出
        resolve(1)
      },1000)
    })
    let p10 = new Promise((resolve)=>{
      setTimeout(()=>{
        console.log('10s') //10s后输出
        resolve(10) //不传递
      },10000)
    })
    let p5 = new Promise((resolve)=>{
      setTimeout(()=>{
        console.log('5s') //5s后输出
        resolve(5) //不传递
      },5000)
    })
    Promise.race([p1, p10, p5]).then((res)=>{
        console.log(res); // 最后输出
    })

race: 请求某个图片资源(超时的操作)

//请求某个图片资源
let requestImg = new Promise(function(resolve, reject){
        var img = new Image();
        img.onload = function(){
            resolve(img);
        }
    });
//延时函数,用于给请求计时
let timeOut = new Promise(function(resolve, reject){
        setTimeout(function(){
            reject('图片请求超时');
        }, 5000);
    });

Promise.race([requestImg, timeout]).then((res)=>{
    console.log(res);
}).catch((err)=>{
    console.log(err);
});

异步回调Async/Await与Promise区别

async/await
- 基于Promise实现的,它不能用于普通的回调函数,是非阻塞的
- 使得异步代码看起来像同步代码
- 函数前添加了async关键字,+await关键字只能用在aync定义的函数内
- 返回值必定是 promise 对象
- await等的是右侧表达式的结果

优点:
- 节约了代码量
- 不需要写.then,替代then
- 不需要写匿名函数处理Promise的resolve值
- 不需要定义多余的data变量,还避免了嵌套代码
        
promise:
const makeRequest = () => {
  try {
    getJSON().then(result => {
      const data = JSON.parse(result)
      console.log(data)
    })
  } catch (err) {
  	console.log(err)
  }
}

aync/await:
const makeRequest = async () => {
	try {
    const data = JSON.parse(await getJSON())
    console.log(data)
  } catch (err) {
    console.log(err)
  }
}

Promise相关的面试题

demo_1

const promise = new Promise((resolve, reject) => {
  console.log(1);
  resolve();
  console.log(2);
});
promise.then(() => {
	console.log(3);
});
console.log(4);
输出结果为:1,2,4,3

demo_2

const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('success')
    reject('error')
  }, 1000)
})
promise.then((res)=>{
	console.log(res)
},(err)=>{
	console.log(err)
})
输出结果:success   
解题思路:Promise状态一旦改变,无法在发生变更

demo_3

Promise.resolve(1)
.then(2)
.then(Promise.resolve(3))
.then(console.log)
输出结果:1 , Promise {<fulfilled>: undefined}  
解题思路:Promise的.then()的参数期望是函数,传入非函数则会发生值穿透

demo_4

setTimeout(()=>{
	console.log('setTimeout')
})
let p1 = new Promise((resolve)=>{
  console.log('Promise1')
  resolve('Promise2')
})
p1.then((res)=>{
	console.log(res)
})
console.log(1)
输出结果:Promise1, 1, Promise2, setTimeout

demo_5

Promise.resolve(1)
.then((res) => {
  console.log('res', res);
  return 2;
})
.catch((err) => {
	return 3;
})
.then((res) => {
	console.log('res2', res);
});
输出结果:res  1, res2 2 
解题思路:
Promise首先resolve(1),接着就会执行then函数,因此会输出1
因为是resolve函数,因此后面的catch函数不会执行,直接执行第二个then函数,
return 2会被包装成resolve(2), 因此会输出2

Promise.reject(1)
.then(res => {
  console.log('res', res);
  return 2;
})
.catch(err => {
  console.log('err', err);
  return 3
})
.then(res => {
	console.log('res2', res);
});
// err 1, res2 3

demo_6

const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    console.log('开始');
    resolve('success');
  }, 5000);
});

const start = Date.now();
promise.then((res) => {
	console.log(res, Date.now() - start);
});

promise.then((res) => {
	console.log(res, Date.now() - start);
});
输出结果:开始, success 5002, success 5002
解题思路:
promise 的.then或者.catch可以被调用多次,但这里 Promise 构造函数只执行一次。
或者说 promise 内部状态一经改变,并且有了一个值,那么后续每次调用.then 或者.catch都会直接拿到该值

demo_7

let p1 = new Promise((resolve,reject)=>{
  let num = 6
  if(num<5){
    console.log('resolve1')
    resolve(num)
  }else{
    console.log('reject1')
    reject(num)
	}
})

p1.then((res)=>{
	// p1 执行reject(num), 所以不会执行此段代码
  console.log('resolve2')
  console.log(res)
},(rej)=>{
  console.log('reject2')
  let p2 = new Promise((resolve,reject)=>{
    if(rej*2>10){
      console.log('resolve3')
      resolve(rej*2)
    }else{
      console.log('reject3')
      reject(rej*2)
    }
	})
	return p2
}).then((res)=>{
  console.log('resolve4')
  console.log(res)
},(rej)=>{
  console.log('reject4')
  console.log(rej)
})

输出结果:reject1,  reject2,  resolve3,  resolve4,  12
解题思路:我们上面说了Promise的先进之处在于可以在then方法中继续写Promise对象并返回。

demo_8

const promise = new Promise((resolve, reject) => {
  reject("error");
  resolve("success2");
});
promise.then(res => {
    console.log("then1: ", res);
  }).then(res => {
    console.log("then2: ", res);
  }).catch(err => {
    console.log("catch: ", err);
  }).then(res => {
    console.log("then3: ", res);
  })

// catch:  error, then3:  undefined

demo_9

Promise.resolve().then(() => {
  returnnewError('error!!!')
}).then(res => {
  console.log("then: ", res)
}).catch(err => {
  console.log("catch: ", err)
})
// "then: " "Error: error!!!"
const promise = Promise.resolve().then(() => {
  return promise;
})
promise.catch(console.err)

.then 或 .catch 返回的值不能是 promise 本身,否则会造成死循环。
// err: Uncaught (in promise) TypeError: Chaining cycle detected for promise #<Promise>
- 实现一个简单的Promise
function Promise(fn){
  var status = 'pending'
  function successNotify(){
      status = 'fulfilled'//状态变为fulfilled
      toDoThen.apply(undefined, arguments)//执行回调
  }
  function failNotify(){
      status = 'rejected'//状态变为rejected
      toDoThen.apply(undefined, arguments)//执行回调
  }
  function toDoThen(){
      setTimeout(()=>{ // 保证回调是异步执行的
          if(status === 'fulfilled'){
              for(let i =0; i< successArray.length;i ++)    {
                  successArray[i].apply(undefined, arguments)//执行then里面的回掉函数
              }
          }else if(status === 'rejected'){
              for(let i =0; i< failArray.length;i ++)    {
                  failArray[i].apply(undefined, arguments)//执行then里面的回掉函数
              }
          }
      })
  }
  var successArray = []
  var failArray = []
  fn.call(undefined, successNotify, failNotify)
  return {
      then: function(successFn, failFn){
          successArray.push(successFn)
          failArray.push(failFn)
          return undefined // 此处应该返回一个Promise
      }
  }
}

解题思路:Promise中的resolve和reject用于改变Promise的状态和传参,then中的参数必须是作为回调执行的函数。因此,当Promise改变状态之后会调用回调函数,根据状态的不同选择需要执行的回调函数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值