promise、async和await

promise

JavaScript是单线程

因为js语言的一大特点就是单线程,也就是说,同一个时间只能做一件事。

异步任务

但这样很容易造成阻塞,所以把任务分成了同步任务和异步任务两种,异步模式可以同时执行多个异步任务,当主线程遇到异步任务,就把异步任务放进’任务队列’里,执行完同步任务后,再循环的去检查任务队列里面有哪些异步任务要执行,

回调函数

在没有promise前,使用的是回调函数的方式来执行异步任务,就是当主线程开始执行这个异步任务时,就去执行这个异步任务对应的回调函数。

异步任务比如:ajax请求、定时器、事件函数等

回调地狱

但是不同的异步任务耗时不一,我们没有办法控制不同的异步任务的前后顺序,当一个异步任务需要依赖另一个异步任务的结果时,如果不控制这两个异步任务的先后顺序,就很容易会报错:

以向后端发送请求数据为例来说,一个请求b需要在拿到请求a中返回的参数后,才能正确发起请求,这种时候的解决方案是:在请求a的回调函数里去发起b请求,那如果这样的先后依赖多了的话,一层套一层,就会出现回调地狱的问题,代码不易读,耦合度过高,后期亦不好维护。

请求1(function(请求结果1){
    请求2(function(请求结果2){
        请求3(function(请求结果3){
            请求4(function(请求结果4){
                请求5(function(请求结果5){
                    请求6(function(请求结果6){
                        ...
                    })
                })
            })
        })
    })
})

promise

那为了解决回调地狱的问题,ES6就新增了Promise,是异步编程的一种解决方案,有了Promise对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数

promise的2个参数(resolve,reject) 和 3个状态(pending ,fulfilled/resolved,rejected)

Promise是一个构造函数,使用new Promise()得到一个实例,new Promise()需要传进去一个函数,这个函数有2个参数:

  • 一个是resolve回调函数,在异步操作成功时调用,把promise的状态从pending转变到fulfilled(又称resolved),并将异步操作的结果,作为参数传递出去

  • 一个是reject回调函数,在异步操作失败时调用,把Promise的状态从从 pending 变为 rejected,并将异步操作报出的错误,作为参数传递出去

// 创造一个Promise实例
const promise = new Promise((resolve, reject) => {
  // ... some code
  if (/* 异步操作成功 */){
    resolve(value);  // value是异步请求成功的结果,resolve把value传出去
  } else {
    reject(error);   // error是异步请求报的错误,reject把error传出去
  }
});

Promise.prototype.then()

Promise实例生成后,当promise状态一改变,不管是成功还是失败,就都会来到promise对象的then方法,.then()根据其最终状态,选择特定的状态响应函数执行

then方法可以接受两个回调函数作为参数:

  • 第一个回调函数是promise对象的状态变为resolved的时候调用,

  • 第二个回调函数是promise对象的状态变为rejected时调用。(其中第二个函数是可选的,不一定需要提供)

这两个函数都接受Promise对象传出的值【resolve(value) / reject(error) 】value或者error作为参数,

【then中的函数一定要return一个结果或者一个新的Promise对象(新的异步任务,才可以让之后的then回调接收】

// 创造一个Promise实例
const promise = new Promise((resolve, reject) => {
  // ... some code
  if (/* 异步操作成功 */){
    resolve(value);  // value是异步请求成功的结果
  } else {
    reject(error);   // error是异步请求报的错误
  }
});

promise.then(
  value => {  // value是异步请求成功的结果
    // 对请求来的结果进行处理,然后返回一个结果或者一个新的Promise对象,才可以让之后的then回调接收
    return value;
  },
  error => {  // error是异步请求报的错误
    // 对错误进行处理
    console.log(error);
  }
)

then方法返回的是一个新的Promise实例(注意,不是原来那个Promise实例)因此可以采用链式写法,即then方法后面再调用另一个then方法。

new Promise(请求1)
    .then(请求2(请求结果1))
    .then(请求3(请求结果2))
    .then(请求4(请求结果3))
    .then(请求5(请求结果4))
    .catch(处理异常(异常信息))

Promise.prototype.catch()

Promise.prototype.catch方法是.then(null, rejection)的别名,如果Promise的状态变为reject时,会被catch捕捉到。

Promise对象的错误具有“冒泡”性质,会一直向后传递,直到被捕获为止

一般来说,使用catch方法代替then()的第二个参数

所以就把成功的处理逻辑写在.then()里,把失败的处理逻辑写在.cache()里

const sayhello = (order) => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log(order);
      //在异步操作执行完后执行 resolve() 函数
      resolve();
    }, 1000);
  });
};
sayhello("first")
  .then(() => {
    // 仍然返回一个 Promise 对象
    return sayhello("second");
  })
  .then(() => {
    return sayhello("third");
  })
  .then(() => {
    console.log('end');
  })
  // 处理前面三个Promise产生的错误
  .catch((err) => {
    console.log(err);
  })

Promise.prototype.finally()

finally方法,不管Promise对象最后状态如何,都会执行操作。

Pomise.all()

接受一个数组(迭代对象)作为参数,数组成员都应为Promise实例

多个 Promise 任务同时执行,如果全部成功执行,则以数组的方式返回所有 Promise 任务的执行结果。

如果有一个 Promise 任务 rejected,则只返回 rejected 任务的结果。

const sayhello = (order) => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log(order);
      resolve('请求成功');
      // reject('失败了');
    }, 1000);
  });
};

const p1 = sayhello('first');
const p2 = sayhello('second');
const p3 = sayhello('third');

Promise.all([p1, p2, p3])
  .then((value) => {
    console.log(value);  // ['请求成功', '请求成功', '请求成功']
  })
  .catch((err) => {
    console.log(err); // 如果注释掉resolve('请求成功'),打开reject('失败了'),则打印:失败了
  })

promise.race()

race是赛跑的意思,就是说,Promise.race([p1, p2, p3])里面哪个结果获得的快,就返回那个结果,不管结果本身是成功状态还是失败状态。

const f1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('成功了');
  }, 1000);
});

const f2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject('失败了');
  }, 500);
});

Promise.race([f1, f2])
  .then((value) => {
    console.log(value);
  })
  .catch((error) => {
    console.log(error);  // 打印: '失败了'  因为f2耗时短
  })

通过race可以设置图片请求超时

//请求某个图片资源
function requestImg(){
    var p = new Promise(function(resolve, reject){
        var img = new Image();
        img.onload = function(){
           resolve(img);
        }
        //img.src = "https://b-gold-cdn.xitu.io/v3/static/img/logo.a7995ad.svg"; 正确的
        img.src = "https://b-gold-cdn.xitu.io/v3/static/img/logo.a7995ad.svg1";
    });
    return p;
}

//延时函数,用于给请求计时
function timeout(){
    var p = new Promise(function(resolve, reject){
        setTimeout(function(){
            reject('图片请求超时');
        }, 5000);
    });
    return p;
}

Promise
.race([requestImg(), timeout()])
.then(function(results){
    console.log(results);
})
.catch(function(reason){
    console.log(reason);
});

async、await

async 作为一个关键字放在函数的前面,表示该函数是一个异步函数,async修饰的函数的返回值是一个promise对象

const fun = async () => {
  return 'hello';
};

const a = fun();

console.log(a);  // Promise { 'hello' }

a.then(result => console.log(result))  // hello

await即等待,用于等待一个Promise对象。它只能在异步函数 async function中使用,否则会报错

它的返回值不是Promise对象,而是Promise对象处理之后的结果

await表达式会暂停当前 async函数的执行,等待Promise 处理完成,

  • 如果 Promise 正常处理(fulfilled),await会拿到resolve传递出来的异步数据,然后再继续执行 async函数;
  • 如果 Promise 处理异常(rejected)await 表达式会把 Promise 的异常原因抛出。

通过Promise封装Ajax

// 通过Promise封装Ajax
function http(options) {
  // 解构参数
  let { method, url, data, headers } = options
  // 默认的请求方式
  method = method || "GET"
  // 默认请求头
  headers = headers || {
    'Content-type': 'application/json'
  };
  return new Promise((resolve, reject) => {
    let xhr = null;
    if (window.XMLHttpRequest) {
      xhr = new XMLHttpRequest();
    } else {
      xhr = new ActiveXObject("Microsoft.XMLHTTP");
    }
    xhr.onreadystatechange = () => {
      if (xhr.readyState == 4) {
        resolve(JSON.parse(xhr.responseText))
      }
      if (xhr.readyState == 4 && xhr.status == 400) {
        reject(JSON.parse(xhr.responseText))
      }
    }
    // 开启
    xhr.open(method, url)
    // 设置请求头
    for (const key in headers) {
      // 设置请求参数的类型
      xhr.setRequestHeader(key, headers[key]);
    }
    // 发送请求
    xhr.send(JSON.stringify(data));
  })
}
// 使用上面封装好的http发送请求
  const queryGoods = async () => {
    try {
      const res = await http({
        url: 'http://119.91.125.14:3000/home/goods',
        data: {
          type: 'pop',  // 商品的类型 type pop|new|sell
          page: 1   // 页码数
        }
      })
      console.log(res);
      return res;
    } catch (error) {
      console.log(error);
    }
  }
  const res = queryGoods()
  console.log(res);  // Promise对象
  • 5
    点赞
  • 45
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值