初步学习promise,从使用方法到常见题目

什么是promise

promise是JS的一种异步编程解决方案。setTimeout和Ajax都是常见的异步回调方案,但是他们都有一个问题,就是对于复杂的回调会产生层层嵌套的问题,代码会像一个横放的金字塔意一样一层套一层,编码体验极差。promise的多重链式回调可以很好的解决这个问题。

怎么用promise

首先promise对象代表的是现在未完成,但是将来会完成的操作。它一共有三个状态:

  • pending,代表初始状态
  • fulfilled,代表操作成功
  • rejected,代表操作失败
    promise的状态只会改变一次,改变了就会一直保持这个状态
构建一个promise对象
var promise = new promise(function (resolve,reject) {

}

promise的参数为函数,resolve是一部操作执行成功时执行的函数,reject是异步操作执行失败时执行的函数。

promise的基本api

1.then()
.then()方法可以指定resolve和reject状态下回调的函数

promise.then(function (data) {
//操作成功状态执行的内容
},function (error) {
//操作失败状态执行的内容
})

2.catch()
.catch()方法用于指定发生错误时的回调函数,可以看作是用来捕获错误的。虽然用.then()方法就可以指定reject状态下的回调函数,但是promise对象抛出的错误不会传递到外层代码,浏览器就不会抛错(除了chrome)。

promise.catch(function (error) {
})

3.all()
.all()方法的作用是将多个promise实例包装成一个新的promise实例,且只有所有promise实例状态都变成fulfilled,新的promise实例状态才会变成fulfilled。
只要有一个是rejected,新实例的状态就会变成rejected。

var p1 = new Promise(function (resolve, reject) {
    setTimeout(resolve, 3000, "first");
});
var p2 = new Promise(function (resolve, reject) {
    resolve('second');
});
var p3 = new Promise((resolve, reject) => {
  setTimeout(resolve, 1000, "third");
}); 

Promise.all([p1, p2, p3]).then(function(values) { 
  console.log(values); 
});

//约 3s 后
["first", "second", "third"] 

注意p1,p2,p3是同步执行的
4.race()
.race()的作用基本和.all()一样,不同之处在于p1,p2,p3中有一个状态变成fulfilled或者rejected,P的状态就会随之改变,并向回调函数中传递一个改变的状态。

5.resolve()
.resolve()方法可以立即让promise进入resolved状态,并将success结果传递给.then()。
.resolve()方法返回的是promise对象,可以用.then()处理返回值。

6.reject()
让promise立即进入rejected状态

promise常见题目5道

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
思路:.then()是异步的

setTimeout(function(){
  console.log(4)
},0); 
new Promise(function(resolve){
   console.log(1) 
   for( var i=0 ; i<10000 ; i++ ){
      i==9999 && resolve() 
    } 
    console.log(2) 
  }).then(function(){ 
      console.log(5) 
    });
       console.log(3);

答案:1 2 3 5 4
思路:涉及到js的执行队列,js是单线程多队列的
第一步:首先创建一个macrotask,里面放入整个scrpipt。执行过程中会创建一个新的macrotask,里面放入setTimeout()。
在创建执行第一个macrotask的同时还创建了一个microtask,里面放入了promise.nextTick和console。log(3),执行之后输出了1和2

第二步:根据microtask的特性它会连续执行直到队列清空,于是接下去执行console.log(3),然后执行promise.then(),输出3和5。

第三步:最后执行macrotask中的setTimeout(),输出4

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

结果:1
思路:promise.then()期望传入的参数是函数,传入非函数会发生值穿透。

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);
});

结果:开始,sucess 5002,success 5002
思路:promise.then()可以调用多次,但是里面的构造函数值执行一次,它执行一次之后值就被储存了,接下去每次调用都是直接拿值。

5.实现一个promise

//先创建一个promise类,搭好架子
class MyPromise {
//构造一个构造方法用来检测传入参数和初始化promise
 constructor(fn){
  if(typeof fn !== 'function') {
   throw new TypeError(`MyPromise fn ${fn} is not a function`)
  }	//如果传入的不是函数那就抛出错误
  this.state = 'pending';
  this.value = void 0;
  fn(this.resolve.bind(this),this.reject.bind(this)) //改变this的指向,使下面俩方法能修改state和value的值
 }
//用于改变state和value的值
 resolve(value){
  if(this.state !== 'pending') return;
  this.state = 'fulfilled';
  this.value = value
 }
 reject(reason){
  if(this.state !== 'pending') return;
  this.state = 'rejected';
  this.value = reason
 }
 //回调方法
 then(fulfilled,rejected){
 //判断传入的是不是函数,如果不是直接跳过,返回this进行下一步,这可以解释第三题为什么会返回1.
  if (typeof fulfilled !== 'function' && typeof rejected !== 'function' ) {
   return this;
  }
  //判断是不是多次.then()调用,如果时,不执行函数直接返回值,这可以解释第四题。
  if (typeof fulfilled !== 'function' && this.state === 'fulfilled' ||
   typeof rejected !== 'function' && this.state === 'rejected') {
   return this;
  }
  //then返回的是一个新的promise对象
  return new MyPromise((resolve,reject)=>{
   if(fulfilled && typeof fulfilled === 'function' && this.state === 'fulfilled'){
    let result = fulfilled(this.value); //调用.then()中传入的fulfilled方法
    //判断是否有链式调用,如果result存在且result.then是一个function则将返回值传入下一个promise
    if(result && typeof result.then === 'function'){
     return result.then(resolve,reject)
    }else{
    //如果是一个普通值就直接resolve()
     resolve(result)
    }
   }
   if(rejected && typeof rejected === 'function' && this.state === 'rejected'){
    let result = rejected(this.value); //调用.then()中传入的rejected方法
    if(result && typeof result.then === 'function'){
     return result.then(resolve,reject)
    }else{
     resolve(result)
    }
   }
  })
 }
 catch(rejected){
  return this.then(null,rejected)
 }
}

你可能感兴趣的:(学习笔记)