Promise 类似 java 的 Callable
then 方法 类似 java 的 Future

# “异步” 引入

js 会把 主线程上某些任务放入任务队列

当主线程完成后,不断轮询任务队列

    function loadImag(src, resolve, reject) {
      let image = new Image() ;
      image.src = src ; 
      image.onload = resolve ;
      image.onerror = reject ;
    }
    loadImag('./images/0fcee7d8fb636a7e86ee034ac15cc46130d404c7.jpg',() => {
      console.log('图片加载完成')
    }, () => {
      console.log('加载失败')
    }) ;
    console.log('后盾热') ;

# 定时器轮询

div 向右移动,缩小

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style> div{ background-color: aqua; width: 300px; height: 300px; position: absolute; } </style>
</head>
<body>
  <div></div>
  <script> function interval(callback,delay=100) { let id = setInterval(() => callback(id), delay) ; } interval((id) => { const div = document.querySelector('div') ; let left = parseInt(window.getComputedStyle(div).left) div.style.left = left + 10 + 'px' ; if(left>=200) { clearInterval(id) interval((id) => { let width = parseInt(window.getComputedStyle(div).width) ; div.style.width = width - 10 + "px" ; if(width<=20) { clearInterval(id) } }) } }) </script>
</body>
</html>

# 通过文件依赖,了解任务排列

加载两个文件,hd.js 和 hd2.js

其中
hd2.js 对 hs.js 有依赖关系

但由于 加载和 加载完 两个事件是没有任务队列的。
因此会有概率出现,hd.js 加载完之前 加载了 hd2.js 。
而 hd2.js 缺少 hd.js 的依赖,从而hd2.js 报错
(如下)

    function load(src,resolve) {
      let script = document.createElement('script') ;
      script.src = src ; 
      script.onload = resolve ; 
      document.body.append(script) ;
    }
    load('./dist/hd.js', () => {
      show();
    }) ;
    load('./dist/hd2.js', () => {
      console.log('hd2')
    })
    console.log('主进程')

hd.js

function show() {
  console.log('hd show')
}

hd2.js

show() ;

所以,要让 加载和加载完 形成任务队列

需要把代码改一改

    function load(src,resolve) {
      let script = document.createElement('script') ;
      script.src = src ; 
      script.onload = resolve ; 
      document.body.append(script) ;
    }
    load('./dist/hd.js', () => {// hd.js 加载完
      show();
      load('./dist/hd2.js', () => { // hd2.js 开始加载
        console.log('hd2')
      })
    }) ;
    
    console.log('主进程')

# 禁止套娃(嵌套)

下面 先开启后台服务 (我这里用 mock 工具 jsonserver - 光速使用

开启服务:

json-server --watch db.json

db.json 数据:

{
  "users": [
    {"id":1, "name":"御坂美琴", "email":"jdbc@qq.com"},
    {"id":2, "name":"茵蒂克丝", "email":"c3p0@qq.com"}
  ],
  "lessons": [
    {"id":1 ,"js":60, "ts":89},
    {"id":2 ,"js":33, "ts":10}
  ]
}

ajax.js :

function ajax(url, callback) {
  let xhr = new XMLHttpRequest() ;
  xhr.open('GET', url) ;
  // xhr.readyState==4 ==> xhr.onload
  xhr.onload = function() {
    if(this.status == 200) {
      callback(JSON.parse(this.response)) ;
    }else {
      throw new Error('加载失败')
    }
  }
  xhr.send() ;
}

index.html:

  <script src="./dist/ajax.js"></script>
  <script> ajax(`http://localhost:3000/users?name=御坂美琴`,(result) => { let user = result[0] ; ajax(`http://localhost:3000/lessons?id=${user.id}`, (lessons) => { console.log(lessons) }); } ); console.log('main 线程') </script>

业务完成了,但是代码一层套一层,不美观

这种套娃也有中二叫法:回调地狱

怎么避免?

# Promise 微任务处理机制

Promise 许诺

白话:等通知模式

## 状态

  • panding 待定的(准备状态)

        let p = new Promise((resolve, reject)=>{
    
        })
        console.log(p) ;
    
  • resolved 成功状态

        let p = new Promise((resolve, reject)=>{
          resolve('成功状态');
        })
        console.log(p) ;
    
  • reject 拒绝状态

    	let p = new Promise((resolve, reject)=>{
          reject('拒绝状态');
        })
        console.log(p) ;
    

## then

then 里面做处理

  • value 成功参数
  • reason 失败参数
    let p = new Promise((resolve, reject)=>{
      reject('拒绝状态');
    }).then(value => {
		console.log('成功的处理')
    }, (reason)=> {
      console.log('拒绝的处理')
    })
    console.log(p) ;

    let p = new Promise((resolve, reject)=>{
      resolve('成功状态');
      //reject('拒绝状态');
    }).then(value => {
		console.log('成功的处理')
    }, (reason)=> {
      console.log('拒绝的处理')
    })
    console.log(p) ;

## 微任务、宏任务

<mark>同级情况下</mark>,微任务为主(优先级较高)

  <script src="./dist/ajax.js"></script>
  <script> let p = new Promise((resolve, reject)=>{ resolve('成功状态'); //reject('拒绝状态'); }).then(value => { console.log('微任务1:成功的处理--1') }, (reason)=> { console.log('微任务1:拒绝的处理--1') }).then(value => { console.log('微任务1:成功的处理--2') }, (reason)=> { console.log('微任务1:拒绝的处理--2') }) console.log(p) ; ajax(`http://localhost:3000/users`, (result) => { console.log('宏任务',result) }) </script>

## 宏任务、微任务执行顺序

<mark>同级下</mark>,微任务优先级高

    setTimeout(()=> {
      console.log('宏任务') // 宏任务等待微任务完成后执行
    }, 0) ;
    new Promise(resolve => {
      resolve();// 把then中成功的代码放入微任务区
      console.log('main promise') ;
    }).then(value => {
      console.log('微任务 成功') // 微任务等在同步线程完成后执行
    });
    console.log('main 线程完')

<mark>不同级下</mark>,顺序不变

    let  promise = new Promise(resolve => {
      console.log("setTimeout")
      resolve();
      console.log('promise')
    }).then(value => {
      console.log('成功');
    });
    console.log('houdunren.,com')

# 单一状态和状态中转

如果 上级 reject ,即便下级resolve也会去到 error 回调

    let p1 = new Promise((resolve, reject) => {
      reject('p1 失败')
    }) ;
    let p2 = new Promise((resolve, reject) => {
      resolve(p1) ;
    }).then((value)=> {
      console.log("p2 success ",value)
    }, (error) => {
      console.log("p2 error " , error)
    })
    console.log('main finish')

并且,状态确定之后,是不变的

    let p2 = new Promise((resolve, reject) => {
      reject("失败") ; // 确定了失败
      resolve("成功") ; // 后面的这段代码想改变状态,是无法做到的
    }).then((value)=> {
      console.log("p2 success ",value)
    }, (error) => {
      console.log("p2 error " , error)
    })
    console.log('main finish')

# Promise.then 也是 promise

且 失败 被成功处理了, 返回的也是成功

# return {then(resolve, reject):{…}}

then 中返回 reject 结果 可以这样写(下图)

new Promise((resolve, reject)=> {
      resolve("1 ok") ;
    }).then(value => {
      console.log(value) // 1 ok
      return {
        then(resolve, reject) {
          reject('2 reject')
        }
      }
    }).then(null, reason => {
      console.log(reason) // 2 reject ;
    })

或者

new Promise((resolve, reject)=> {
      resolve("1 ok") ;
    }).then(value => {
      console.log(value) // 1 ok
      return class {
        static then(resolve, reject) {
          reject('2 reject')
        }
      }
    }).then(null, reason => {
      console.log(reason) // 2 reject ;
    })


原理后面说

当然,也能 写成

....
then( value => {
		return new Promise((resolve, reject) => reject())
})
...

但是就很蠢

# 使用 Promise 封装 ajax 异步请求

  <script src="./dist/ajax.js"></script>
  <script> ajax(`http://localhost:3000/users?name=茵蒂克丝`) .then(value => { let user = value[0] ; return ajax(`http://localhost:3000/lessons?id=${user.id}`) ; }) .then(value => { console.log('ok',value); }, reason => { console.log('error', reason) ; }) </script>

js 返回 Promise 对象

function ajax(url) {
  return  new Promise((resolve, reject) => {
    let xhr = new XMLHttpRequest() ;
    xhr.open('GET', url) ;
    // xhr.readyState==4 ==> xhr.onload
    xhr.onload = function(result) {
      if(this.status == 200) {
        resolve(JSON.parse(this.response) ) ;
      }else {
        reject('加载失败')
      }
    }
    xhr.onerror = function() {
      reject(this)
    }
    xhr.send() ;
  })
}

# Promise 错误检查 与 catch

        // throw new Error('promise fail')
        // hd + 1 ; 
        resolve('rejected');
      }).then(value => 
        new Promise((resolve, reject)=> {
          reject('失败') ;
        }) , 
        // reason => {} 
      ).then(
        value => {},
        //reason => {} 
      ).catch((reason) => { // 语法上,也可以放中间, 但通常放最后
      console.log(reason)
      }) ;

# 自定义 错误

ajax.js

class ParamError extends Error{
  constructor(msg) {
    super(msg) ; 
    this.name = 'ParamError' ;
  }
}
class HttpError extends Error { 
  constructor(msg) {
    super(msg) ;
    this.name = 'HttpError' ;
  }
}
class WebAssert {
  static isURL(url) {
    if(!/^https?:\/\//i.test(url)) {
      throw new ParamError('请求地址格式错误')
    }
  }
}
function ajax(url) {
  return  new Promise((resolve, reject) => {
    WebAssert.isURL(url) ;
    let xhr = new XMLHttpRequest() ;
    xhr.open('GET', url) ;
    // xhr.readyState==4 ==> xhr.onload
    xhr.onload = function(result) {
      if(this.status == 200) {
        resolve(JSON.parse(this.response) ) ;
      }else if(this.status ==404) {
        // throw new HttpError('用户不存在'); 这样是不行的,因为在新线程里面
        reject(new HttpError('用户不存在'))
      }else{
        reject('加载失败')
      }
    }
    xhr.onerror = function() {
      reject(this)
    }
    xhr.send() ;
  })
}
  <script src="./dist/ajax.js"></script>
  <script> ajax('http://localhost:3000/users1') .then(value => { console.log(value) ; }) .catch((err) => { if(err instanceof ParamError) { console.log(err.message) ; }else if(err instanceof HttpError) { alert(err.message) }else { console.log(err) } }) </script>

这里故意不存在的 请求

# finally

最终执行

例子:资源加载后,隐藏 LOADING DOM
在·

  <div id='loading'>loading...</div>
  <script src="./dist/ajax.js"></script>
  <script> ajax(`http://localhost:3000/users?name='茵蒂克丝'`) .then(value=> { console.log(value); }) .finally(()=> { loading.style.display='none'; }) </script>
class ParamError extends Error{
  constructor(msg) {
    super(msg) ; 
    this.name = 'ParamError' ;
  }
}
class HttpError extends Error { 
  constructor(msg) {
    super(msg) ;
    this.name = 'HttpError' ;
  }
}
class WebAssert {
  static isURL(url) {
    if(!/^https?:\/\//i.test(url)) {
      throw new ParamError('请求地址格式错误')
    }
  }
}
function ajax(url) {
  return  new Promise((resolve, reject) => {
    loading.style.display='block'
    WebAssert.isURL(url) ;
    let xhr = new XMLHttpRequest() ;
    xhr.open('GET', url) ;
    // xhr.readyState==4 ==> xhr.onload
    xhr.onload = function(result) {
      if(this.status == 200) {
        resolve(JSON.parse(this.response) ) ;
      }else if(this.status ==404) {
        // throw new HttpError('用户不存在'); 这样是不行的,因为在新线程里面
        reject(new HttpError('用户不存在'))
      }else{
        reject('加载失败')
      }
    }
    xhr.onerror = function() {
      reject(this)
    }
    xhr.send() ;
  })
}

# 例子:异步加载图片

    function loadImage(src) {
      return new Promise((resolve, reject)=> {
        const image = new Image() ;
        image.src = src ;
        image.onload = () => {
          resolve(image)
        } ;
        image.onerror = reject;
        document.body.appendChild(image)
      })
    }
    loadImage('./images/0fcee7d8fb636a7e86ee034ac15cc46130d404c7.jpg')
    .then(image=> {
      image.style.border = 'solid 6px red'
    })

# 封装 setTimeOut

    function timeout(delay = 1000) {
      return new Promise(resolve => {
        setTimeout(resolve, delay);
      })
    }
    timeout(2000)
    .then((value) => {
      console.log('定时器 - 1',value)
      return timeout(2000) ;
    })
    .then((value) => {
      console.log('定时器 - 2', value)
    })

    function interval(delay=1000, callback) {
      return new Promise((resolve, reject) => {
        let id = setInterval(() => {
          callback(id, resolve);
        }, delay);
      })
    }
    interval(100, (id, resolve) =>{
      console.log(12) ;
      clearInterval(id) ;
      resolve('定时器关闭')
    }).then((value)=> {
      console.log(value)
    }) ;

# (优化)定时器轮询 - 解决套娃

好,现在可以处理前面 “回调地狱” 的问题了
同样的例子

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style> div{ background-color: aqua; width: 300px; height: 300px; position: absolute; } </style>
</head>
<body>
  <div></div>
  <script> function interval(callback,delay=100) { return new Promise((resolve, reject) => { let id = setInterval(() => callback(id, resolve, reject), delay) ; }) ; } const div = document.querySelector('div') ; interval((id, resolve) => { let left = parseInt(window.getComputedStyle(div).left) div.style.left = left + 10 + 'px' ; if(left>=200) { clearInterval(id) resolve('右移完毕!') } }, 100) .then(value=> { interval((id, resolve) => { let width = parseInt(window.getComputedStyle(div).width) ; div.style.width = width - 10 + "px" ; if(width<=20) { clearInterval(id) resolve('缩小完毕!') } }) }, 100) </script>
</body>
</html>

# 加载文件 - (Promise 形式)

    function loadScript(url) {
      return new Promise((resolve, reject) => {
        let script = document.createElement('script');
        script.src = url;
        script.onload = resolve(script);
        script.reject = reject;
        document.body.appendChild(script)
      })
    }
    // hd.js
    // -----------------
    // function show() {
    // console.log('hd show')
    // }
    //
    // hd2.js
    // -----------------
    // show() ;
    loadScript('./dist/hd.js')
      .then(script => {
        console.log(script);
        return loadScript('./dist/hd2.js')
      }).then(script => {
        console.log(script);
      });

# Promise.resolve 缓存后台数据

  <div id="loading">loading</div>
  <script src="./dist/ajax.js"></script>
  <script> function query(name) { const cache = query.cache || (query.cache = new Map()) let temp = cache.get(name) ; if(temp) return Promise.resolve(temp) ; let url = `http://localhost:3000/users?name=${name}` ; return ajax(url).then(user => { cache.set(name, user) ; return user ; }) } query('茵蒂克丝') .then(user => { console.log(user) }) setTimeout(() => { query('茵蒂克丝') .then(user => { console.log(user) }) }, 1000); </script>

# Promise.all 批量获取数据

全部成功,就成功 (下图)

    function timeout(msg,delay=1000) {
      return new Promise((resolve) => {
        setTimeout(() => {
          resolve(msg)
        }, delay);
      })
    }
    const t1 = timeout('第一个异步') ;
    const t2 = timeout('第二个异步') ;
    Promise.all([t1, t2]).then(result => {
      console.log(result)
    })

一个失败就失败 (下图)

    const t1 = new Promise((resolve, reject) => {
      setTimeout(() => {
        reject('第一个异步')
      }, 1000);
    })
    const t2 = new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve('第二个异步')
      }, 1000);
    })
    Promise.all([t1, t2])
    .then(result => {
      console.log('ok',result)
    })
    .catch(error => {
      console.log('error',error)
    })

失败处理了,也是成功 (下图)

    const t1 = new Promise((resolve, reject) => {
      setTimeout(() => {
        reject('第一个异步')
      }, 1000);
    }).catch(error => {
      console.log('第一个异步 失败')
      return '1 error'
    }).finally(value => {
      console.log('finally')
    })
    const t2 = new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve('第二个异步')
      }, 1000);
    })
    Promise.all([t1, t2])
    .then(result => {
      console.log('ok',result)
    })
    .catch(error => {
      console.log('error',error)
    })

## 批量 ajax 接收 (加缓存)

  <script src="./dist/ajax.js"></script>
  <script> function getUsers(names) { const cache = getUsers.cache ||( getUsers.cache = new Map() ) ; let promises = names.map(name => { let user = cache.get(name) ; if(user) return Promise.resolve(user) ; return ajax(`http://localhost:3000/users?name=${name}`).then(user => { cache.set(name, user) ; return Promise.resolve(user) ; }) }) return Promise.all(promises); } getUsers(['御坂美琴', '茵蒂克丝']) .then(value => { console.log(value) ; }) .catch(reason => { console.log("error", reason) }) setTimeout(() => { getUsers(['御坂美琴', '茵蒂克丝']) .then(value => { console.log(value) ; }) .catch(reason => { console.log("error", reason) }) }, 1000); </script>

# Promise.allSettled 状态收集

    const p1 = new Promise((resolve, reject) => {
      reject('p1 reject') ;
    })
    const p2 = new Promise((resolve, reject) => {
      resolve('p2 resolve') ;
    })
    Promise.allSettled([p1, p2]).then(result => {
      console.log(result)
    })

## 过滤ajax请求失败数据

  <script src="./dist/ajax.js"></script>
  <script> function getUsers(names) { return names.map(name => { return ajax(`http://localhost:3000/users?name=${name}`) .then(user => { return user.length>0?Promise.resolve(user) : Promise.reject('炮姐找不到,只有御坂美琴') ; }) }) } Promise.allSettled(getUsers(['茵蒂克丝', '炮姐'])) .then(result => { console.log(result); }) </script>

# Promise.race 只接收最快完成的一个

看下面一个 请求超时的例子

    function query(url, delay=1000) {
      let promises = [
        new Promise((resolve, reject)=> {
          setTimeout(() => {
            reject('请求超时')
          }, delay);
        }),
        ajax(url)
      ]
      return Promise.race(promises) ;
    }
    query(`http://localhost:3000/users`).then(result => {
      console.log(result)
    })


超时(下图)

# Promise 队列原理

## 1

    function queue(num) {
      let promise = Promise.resolve() ;
      num.forEach(v=>{
        promise=promise.then(_=>{
          return new Promise(resolve => {
            setTimeout(() => {
              console.log(v)
              resolve() ;
            }, 1000);
          })
        })
      })
    }
    queue([1,2,3,4,5])

## 2 优化:抽离

把 Promise 抽出来

    function queue(num) {
      let promise = Promise.resolve() ;
      num.forEach(v=>{
        promise=promise.then((value)=>{
          return v(value) ;
        })
      })
    }
    
    function p1() {
      return new Promise(resolve => {
        setTimeout(() => {
          console.log('p1')
          resolve();
        }, 1000);
      })
    }
    function p2() {
      return new Promise(resolve => {
        setTimeout(() => {
          console.log('p2')
          resolve();
        }, 1000);
      })
    }
    queue([p1, p2])

## 优化 reduce

    function queue(num) {
      return num.reduce((promise, current) => {
        return promise.then(current)
      }, Promise.resolve());
    }
    function p1() {
      return new Promise(resolve => {
        setTimeout(() => {
          console.log('ok p1')
          resolve() 
        }, 1000);
      })
    }
    function p2() {
      return new Promise(resolve => {
        setTimeout(() => {
          console.log('ok p2')
          resolve() 
        }, 1000);
      })
    }
    queue([p1,p2])

# 案例:队列 ajax 、渲染

引入之前写好的 ajax.js

    class User{
      ajax(user) {
        let url = `http://localhost:3000/users?name=${user}` ;
        return ajax(url);
      }
      render(users) {
        users.reduce((promise, user) => {
          return promise.then(()=> {
            return this.ajax(user) ;
          }).then(user => {
            return this.view(user);
          })
        }, Promise.resolve())
      }
      view(user) {
        return new Promise(resolve => {
          resolve();
          let h2 = document.createElement('h2') ;
          h2.innerHTML = JSON.stringify(user, null, 2)
          document.body.appendChild(h2) ;
        })
      }
    }
    new User().render(['茵蒂克丝','御坂美琴']);

# 语法糖 : async 、 await

## async

在方法前 加 async
方法的返回值就 变为了 Promise

    async function hd() {
      return "www.houdunren.com" ;
    }
    let h = hd();
    console.log(h) ;// 是一个 Promise 状态 resolve
    h.then(v => {
      console.log(v)
    })

<mark>等于下面写法</mark>

    function hd() {
      return new Promise(resolve => {
     	resolve('www.houdunren.com')
      })
    }
    let h = hd();
    console.log(h) ;// 是一个 Promise 状态 resolve
    h.then(v => {
      console.log(v)
    })

## await

    async function hd() {
      let name = await new Promise(resolve => {
          //resolve('await') // 不放行,后面不执行
      });
      console.log(name);
    }
    hd();

其实就是 then 的简写

    function hd() {
      return new Promise((resolve) => {
        //resolve('await'); // 不放行,后面不执行
      }).then(name => {
        console.log(name)
      })
    }
    hd();

所以 可以这样写

    async function hd() {
      const value = 'value 0'
      let value1 = await new Promise(resolve=> {
        setTimeout(() => {
          console.log(value)
          resolve('value 1 ');
        }, 1000)
      }) 
      let value2 = await new Promise((resolve)=> {
        setTimeout(() => {
          console.log(value1)
          resolve('value 2');
        }, 1000);
      })
      return value2;
    }
    hd().then(value => {
      return new Promise(resolve => {
        setTimeout(() => {
          resolve();
          console.log(value)
        }, 1000);
      })
    })

# 语法糖简化 ajax 请求

  <script src="./dist/ajax.js"></script>
  <script>
    async function get(name) {
      let url = 'http://localhost:3000'
      let user = await ajax(`${url}/users?name=${name}`)
      return await ajax(`${url}/lessons?id=${user[0].id}`)
    }
    get('茵蒂克丝').then(value => {
      console.log(value)
    })

# 案例:进度条

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style> div { height: 30px; background: #8e44ad; width:0px ; display: flex; justify-content: center; align-items: center; font-size: 30px; color: #fff; } </style>
</head>

<body>
  <div id="loading">0%</div>
</body>
<script src="./dist/ajax.js"></script>
<script> function query(name) { let url = `http://localhost:3000` ; return ajax(`${url}/users?name=${name}`) ; } (async ()=>{ let users = ['茵蒂克丝','御坂美琴','白井黑子','佐天泪子','初春饰利']; let len = users.length; for(let i=0;i<len;i++) { let user = await query(users[i]) ; let progress = ((i+1)/len)*100; loading.style.width = progress+'%'; loading.innerHTML = Math.round(progress)+'%' ; console.log( user.length>0?user : '没有数据' ) } })() </script>
</html>

ajax.js
<mark>这里加了延时哦,为了看出效果</mark>

class ParamError extends Error{
  constructor(msg) {
    super(msg) ; 
    this.name = 'ParamError' ;
  }
}
class HttpError extends Error { 
  constructor(msg) {
    super(msg) ;
    this.name = 'HttpError' ;
  }
}
class WebAssert {
  static isURL(url) {
    if(!/^https?:\/\//i.test(url)) {
      throw new ParamError('请求地址格式错误')
    }
  }
}
function ajax(url) {
  return  new Promise((resolve, reject) => {
    WebAssert.isURL(url) ;
    let xhr = new XMLHttpRequest() ;
    xhr.open('GET', url) ;
    // xhr.readyState==4 ==> xhr.onload
    xhr.onload = function(result) {
      if(this.status == 200) {
        resolve(JSON.parse(this.response) ) ;
      }else if(this.status ==404) {
        // throw new HttpError('用户不存在'); 这样是不行的,因为在新线程里面
        reject(new HttpError('用户不存在'))
      }else{
        reject('加载失败')
      }
    }
    xhr.onerror = function() {
      reject(this)
    }
    setTimeout(() => {
      xhr.send() ;
    }, 1000);
  })
}

db.json

{
  "users": [
    {"id":1, "name":"御坂美琴", "email":"jdbc@qq.com"},
    {"id":2, "name":"茵蒂克丝", "email":"c3p0@qq.com"}
  ],
  "lessons": [
    {"id":1 ,"js":60, "ts":89},
    {"id":2 ,"js":33, "ts":10}
  ]
}

# class + async 、 await

<mark>一个类,内部如果有 then 方法,那么,他会被包装成 Promise</mark>

不会是个坑,会了真香

例如下面(简洁啊)

## 初尝禁果

<script src="./dist/ajax.js"></script>
<script> class User { constructor(name) { this.name = name; } then(resolve, reject) { const url = `http://localhost:3000`; let user = ajax(`${url}/users?name=${this.name}`); resolve(user); } } async function get() { let user = await new User('茵蒂克丝'); console.log(user); } get(); </script>

## 异步封装在类内部

  class User {
    async get(name) {
      const url = `http://localhost:3000`;
      let list = await ajax(`${url}/users?name=${name}`);
      let user = list[0];
      user.name += '真平'
      return user;
    }
  }
  new User().get('茵蒂克丝').then(user => {
    console.log(user)
  })

# await 并行执行技巧

怎么让 await 并行?

## 方法一

await 在 接收参数时候才加上

  function p1() {
    return new Promise(resolve => {
      setTimeout(() => {
        resolve('houdunren');
      }, 2000);
    })
  }

  function p2() {
    return new Promise(resolve => {
      setTimeout(() => {
        resolve('hdcms')
      }, 2000)
    })
  }
  async function hd() {
    let h1 = p1();
    let h2 = p2();
    let h1value = await h1;
    let h2value = await h2;
    console.log(h1value, h2value)
  }
  hd();

  async function hd() {
    let res = await Promise.all([p1(), p2()]);
    console.log(res)
  }