强大的promise

这个玩意叫做普罗米修斯,希腊神话的盗火英雄
promise只用来包装异步函数,同步的会搞乱执行顺序,生产BUG

// 如何使用
function pro(){  
   return new Promise(function(resolve,reject){
      setTimeout(function(){
          var num = parInt(Math.random()*10);
          if(num>5){ 
             resolve(num) 
             // 这个可以写成
             // return  Promise.resolve(num)
          }else{ 
             reject(num) 
             // 这个可以写成
             // return  Promise.reject(num)
          } 
      },5000)
   })
}
// pro()这个返回的是一个pending的Promise对象
// Promise可以被then启动,参数有两个,跟new的时候对应也是两个
// new的时候第一个参数传递成功,then的时候第一个参数接受成功
// new的时候第二个参数传递失败,then的时候第二个参数接受失败
pro().then((res)=>{ ... },(error)=>{ ... })

这个api是有固定写法的,用来把回调的异步函数转成链式的异步函数
先看看传统的回调型异步函数

function ajax1(){
   ajax({
       sucess:function(res1){
           //回调ajax2,或者直接把第二个ajax写在这里面
           ajax2(res1)
       }
   })
}
function ajax2(res1){
   ajax({
       sucess:function(res2){
           ...
       }
   })
}
ajax1()

Promise写法

function ajax1(){  
   return new Promise((resolve,reject)=>{
      ajax({
         sucess:function(res1){
           //回调ajax2,或者直接把第二个ajax写在这里面
           resolve(res1)
         }
      })
   }
}
function ajax2(){  
   return new Promise((resolve,reject)=>{
      ajax({
         sucess:function(res2){
           //回调ajax2,或者直接把第二个ajax写在这里面
           resolve(res2)
         }
      })
   }
}
ajax1().then((res1)=>{
   return ajax2(res1)
}).then((res2)=>{
   ...
})

promise.resolve

let res = Promise.resolve("123")
res.then(res=>{ console.log(res) })

promise.reject

let res = Promise.reject("123")
res.then(res=>{ console.log(res) })

Promise.all
这个使用在几个异步函数需要同时请求但是相互不关联的情况
常用来作为初始化加载使用

Promise.all([promise1, promise2, promise3]).then((values) => {
  console.log(values);
},(error)=> {
  console.log(error)
});
// 如果上面几个promise函数没有全部返回成功,就会指向error

看了上面的写法觉得也不过如此是吧,有没有改变,代码还变多了,我也是这么觉得的,直到看到Promise配合async使用

async
这个是Generator函数的语法糖
什么是语法糖,就是更简易的使用,二次封装
什么是Generator函数,这个是es6的api,还没被人知道就被他的语法糖async给抢了头条,所以不管,知道语法糖async怎么用就行

任何函数都可以在前面加上单词async把函数升级成异步管理函数
async只能在该函数的作用域里使用,如果是函数里的函数就得再写一次async了
async要跟await配合使用,否则没有存在意义
await要连接一个promise函数,primise要是一个异步函数
这几个点不遵守肯定会有一些执行顺序等等的BUG

function ajax1(){  
   return new Promise((resolve,reject)=>{
      ajax({
         sucess:function(res1){
           //回调ajax2,或者直接把第二个ajax写在这里面
           resolve(res1)
         }
      })
   }
}
function ajax2(opt){  
   return new Promise((resolve,reject)=>{
      ajax({
         sucess:function(res2){
           //回调ajax2,或者直接把第二个ajax写在这里面
           resolve(res2)
         }
      })
   }
}
async function init(){
   var res1 = await ajax1()
   var opt = res1 + 1; //模拟正常的方法什么的
   var res2 = await ajax2(opt)
}
init()

上面的代码如果是同步代码我们是很好理解的,但是因为是异步的,就不好理解了,正常来说因为ajax1和ajax2是异步的,res1和res2只会拿到undefined,这种运行顺序根本巅峰了对异步的理解,你确定这样的代码执行下来没问题?
有没有问题可以自己试试

async错误处理

// 统一处理
async function init(){
   try{
      var aa = await A()
      var bb = await B()
   }catch(err) {
      console.log(err)  
   }
}

// 单独处理
async function init(){
   const [err, data] = await A().then(data => [null, data]).catch(err => [err, null])
   const [err, data] = await B().then(data => [null, data]).catch(err => [err, null])
}

// 上面的优化写法
// 抽离成公共方法
const awaitWrap = (promise) => {
  return promise
   .then(data => [null, data])
   .catch(err => [err, null])
}
async function init(){
   const [err, data] = await awaitWrap(A())
   const [err, data] = await awaitWrap(B())
}

如何理解async呢
我们可以认为await阻塞了线程,如果有了解过java,在java里有个yeild的方法,这个方法就是await的语法糖,这个API让异步变成了同步,让代码更加的好理解

做一个网络测速
网络测速的前提是服务器超大的带宽
原理是让前端递归去获取服务器的图片获得下载的网速,再把图片转base64递归上传获得上传的网速,我做了五个实验

第一个

var index = 10;
function yi() {
    var start = new Date().getTime()
    var img = document.createElement("img");
    var num = Math.random()
    img.src = './img/xxx.png?num=' + num;
    img.onload = function (res){
        var end = new Date().getTime()
        console.log("递归----"+(end-start))
        index--;
        if(index!=0){
            yi()
        }
    }
}
yi()

第二个

var index = 10;
var promiseArr = [];
function getImg() {
return new Promise(function (resolve, reject) {
    var start = new Date().getTime()
    var img = document.createElement("img");
    var num = Math.random()
    img.src = './img/girs.png?num=' + num;
    img.onload = function (res){
    var end = new Date().getTime()
    console.log("Promise.all----"+(end-start))
    resolve(end-start);
    }
})
}
function er() {
   for(var i=0;i<10;i++){
     promiseArr.push(getImg())
   }
   Promise.all(promiseArr).then()
}
er()

第三个

function getImg() {
   return new Promise(function (resolve, reject) {
    var start = new Date().getTime()
    var img = document.createElement("img");
    var num = Math.random()
    img.src = './img/girs.png?num=' + num;
    img.onload = function (res){
        var end = new Date().getTime()
        console.log("10次await-----"+(end-start))
        resolve(end-start);
    }
   })
}
async function san() {
   var allTime = 0;
   allTime += await getImg();
   allTime += await getImg();
   allTime += await getImg();
   allTime += await getImg();
   allTime += await getImg();
   allTime += await getImg();
   allTime += await getImg();
   allTime += await getImg();
   allTime += await getImg();
   allTime += await getImg();
}
san()

第四个

function getImg() {
   return new Promise(function (resolve, reject) {
    var start = new Date().getTime()
    var img = document.createElement("img");
    var num = Math.random()
    img.src = './img/girs.png?num=' + num;
    img.onload = function (res){
        var end = new Date().getTime()
        console.log("for(x){await x}-----"+(end-start))
        resolve(end-start);
    }
   })
}
async function si() {
   var arr = []
   for(var i=0;i<10;i++){
    arr.push(getImg())
   }   
   for (const x of arr){
    await x;
   }
}
si()

第五个

function getImg() {
   return new Promise(function (resolve, reject) {
    var start = new Date().getTime()
    var img = document.createElement("img");
    var num = Math.random()
    img.src = './img/girs.png?num=' + num;
    img.onload = function (res){
        var end = new Date().getTime()
        console.log("for await(x){x}+-----"+(end-start))
        resolve(end-start);
    }
   })
}
async function wu() {
   var arr = []
   for (var i=0;i<10;i++){
    arr.push(getImg())
   }
   for await(const x of arr){
    x;
   }
}
wu()

这五个代码的执行时间都不一样,为什么还得研究

封装一个promise版本的ajax

function ajax(url, method = 'get', param = {}) {
    return new Promise((resolve, reject) => {
        const xhr = new XMLHttpRequest();
        const paramString = getStringParam(param);
        if (method === 'get' && paramString) {
            url.indexOf('?') > -1 ? url += paramString : url += `?${paramString}`
        }
        xhr.open(method, url);
        xhr.onload = function () {
            const result = {
                status: xhr.status,
                statusText: xhr.statusText,
                headers: xhr.getAllResponseHeaders(),
                data: xhr.response || xhr.responseText
            }
            if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
                resolve(result);
            } else {
                reject(result);
            }
        }
        // 设置请求头
        xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
        // 跨域携带cookie
        xhr.withCredentials = true;
        // 错误处理
        xhr.onerror = function () {
            reject(new TypeError('请求出错'));
        }
        xhr.timeout = function () {
            reject(new TypeError('请求超时'));
        }
        xhr.onabort = function () {
            reject(new TypeError('请求被终止'));
        }
        if (method === 'post') {
            xhr.send(paramString);
        } else {
            xhr.send();
        }
    })
}

function getStringParam(param) {
    let dataString = '';
    for (const key in param) {
        dataString += `${key}=${param[key]}&`
    }
    return dataString;
}

相关推荐