Skip to content

promise

1. axios封装参数提取

javascript
function myAxios(config){
      return new Promise((resolve, reject) => {
        	// 解构 ==> 可以设置默认值
          const {url, method = 'get'} = config
          // 原生ajax 五步走
          // 1. 实例化xhr
          const xhr = new XMLHttpRequest()
          // 2. 设置方法和接口
          xhr.open(method, url)
          // 3. 请求头
          // xhr.setRequestHeader(key, val)
          // 4. 注册回调函数
          xhr.addEventListener('load', () => {
              if(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304){
                  console.log()
                  resolve(JSON.parse(xhr.response))
              } else {
                  reject('请求失败')
              }
          })
          // 5. 发送请求
          xhr.send()
      })
  }


  const api = 'http://ajax-api.itheima.net/api/news'

  myAxios({
      url:api,
      // method:'get'
  }).then(res => {
      console.log(res)
  })

ajax-添加post

javascript
<h2>post传递JSON数据给后端</h2>
<div class="wrap">
    <button class="get">获取图书</button>
    <button class="add">新增图书</button>
    <button class="edit">修改图书</button>
    <button class="delete">删除图书</button>
</div>

<script>
    /* 
        参数是一个对象config
        url
        method
        data:{} 通过请求体传递的数据写在data属性里面
    
    */

    function myAxios(config){
        return new Promise((resolve, reject) => {
            const {url, method = 'get', data} = config
            // 原生ajax 五步走
            // 1. 实例化xhr
            const xhr = new XMLHttpRequest()
            // 2. 设置方法和接口
            xhr.open(method, url)
            // 3. 请求头
            xhr.setRequestHeader('content-type', 'application/json')
            // 4. 注册回调函数
            xhr.addEventListener('load', () => {
                if(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304){
                    console.log()
                    resolve(JSON.parse(xhr.response))
                } else {
                    reject('请求失败')
                }
            })
            // 5. 发送请求
            xhr.send(JSON.stringify(data))
        })
    }


    // apifox:
    // https://apifox.com/apidoc/shared-fa9274ac-362e-4905-806b-6135df6aa90e/api-25018003
    // GET 
    const api_get = 'http://ajax-api.itheima.net/api/books'
    // POST JSON格式 bookname/author/publisher
    const api_add = 'http://ajax-api.itheima.net/api/books' 
    // 修改图书  PUT  JSON格式 id
    const api_edit = 'http://ajax-api.itheima.net/api/books/{id}'
    // 删除图书  DELETE  id 
    const api_del = 'http://ajax-api.itheima.net/api/books/{id}'

    // const btn_get = document.querySelector('.get')
    // const btn_add = document.querySelector('.add')
    // const btn_edit = document.querySelector('.edit')
    // const btn_del = document.querySelector('.delete')

    // 事件委托绑定事件
    const box = document.querySelector('.wrap')
    box.addEventListener('click', (e) => {
        if(e.target.className === 'get'){
            // console.log(111)
            myAxios({
                url:api_get,
            }).then(res => {
                console.log(res)
            })
        }
    })

</script>

完整代码

javascript

function myAxios(config){
    return new Promise((resolve, reject) => {
        const {url, method = 'get', data} = config
        // 原生ajax 五步走
        // 1. 实例化xhr
        const xhr = new XMLHttpRequest()
        // 2. 设置方法和接口
        xhr.open(method, url)
        // 3. 请求头
        xhr.setRequestHeader('content-type', 'application/json')
        // 4. 注册回调函数
        xhr.addEventListener('load', () => {
            if(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304){
                console.log(1111)
                resolve(JSON.parse(xhr.response))
            } else {
                reject('请求失败')
            }
        })
        // 5. 发送请求
        xhr.send(JSON.stringify(data))
    })
}


// apifox:
// https://apifox.com/apidoc/shared-fa9274ac-362e-4905-806b-6135df6aa90e/api-25018003
// GET 获取图书
const api_get = 'http://ajax-api.itheima.net/api/books'
// 新增图书
// POST JSON格式 bookname/author/publisher
const api_add = 'http://ajax-api.itheima.net/api/books' 
// 修改图书  PUT  JSON格式 id
const api_edit = 'http://ajax-api.itheima.net/api/books'
// 删除图书  DELETE  id 
const api_del = 'http://ajax-api.itheima.net/api/books'

// const btn_get = document.querySelector('.get')
// const btn_add = document.querySelector('.add')
// const btn_edit = document.querySelector('.edit')
// const btn_del = document.querySelector('.delete')

// 事件委托绑定事件
const box = document.querySelector('.wrap')
box.addEventListener('click', (e) => {
    if(e.target.className === 'get'){
        // console.log(111)
        myAxios({
            url:api_get,
        }).then(res => {
            console.log(res)
        })
    }

    if(e.target.className === 'add'){
        myAxios({
            url:api_add,
            method:'post',
            data:{
                bookname:'新增的',
                author:'xx',
                publisher:'hh'
            }
        }).then(res => {
            console.log(res)
        })
    }

    if (e.target.className === 'edit'){
        myAxios({
            url:`${api_edit}/325`,
            method:'put',
            data:{
                bookname:'新增的修改',
                author:'xx',
                publisher:'hh'
            }
        }).then(res => {
            console.log(res)
        })
    }

    if (e.target.className === 'delete'){
        myAxios({
            url:`${api_del}/318`,
            method:'delete',
        }).then(res => {
            console.log(res)
            // alert('删除成功')
        }).catch(err => {
            console.log(err)
        })
    }
})

2. promise.then() 的返回值

javascript
const p = new Promise((resolve, reject) => {
    // 一些异步代码
    resolve('success')
})
// console.log(p)

// 1. promise.then() 返回一个promise对象
const res1 = p.then(res => {
    console.log(res)
})

res1.then(res => {
    console.log(res)
})
// console.log(res)


// 2. 如果p.then中回调函数,返回了一个非promise的值,
// 则新的promise的将使用这个值作为成功的结果
const res2 = p.then(res => {
    console.log(res)
    return 'second success'
})
// console.log(res)

// 3. 如果回调函数本身返回了一个promise对象,则then方法调用后返回的新promise
// 与该promise对象采用相同的成功结果或失败原因
const res3 = p.then(res => {
    console.log(res)
    return new Promise((resolve,reject) => {reject(1)})
})
// console.log(res)


===> 一句话总结 p.then() 返回的是一个promise对象,
// 1. then的回调中没有return ,那么promise成功的结果为undefined
// 2. then中return了一个非promise对象,新promise以该值作为成功的结果
// 3. then中return了一个promise对象,新promise 成功或失败与它相同

3. promsie.then() 第二个参数

javascript
const p = new Promise((resolve,reject) => {
    setTimeout(()=>{
        if(Math.random() > 0.5){
            resolve('success')
        } else {
            reject('failed')
        }
    }, 1000)
})

// catch的方式用的更多一些推荐使用
p.then(res => {
    console.log(res)
}).catch(err => {
    console.log(err)
})

// promise.then() 可以接收两个函数作为参数,
// 第一个函数是promise状态为fulfilled时调用
// 第二个回调函数是promise对象为reject时调用
p.then((res)=>{
    console.log(res)
}, (err)=>{
    console.log(err)
})

4. Promise.resolve()

javascript
// Promsie.resolve() promise的静态方法

// ==> 调用这个方法,返回的就是一个promsie对象
// const p = Promise.resolve(1)
// const p = Promise.resolve('123')

// 1. 如果不传参数 => 返回的就是一个成功态的promise对象,结果为undefined
const p = Promise.resolve()
console.log(p)

// 2. 如果传入的value是一个普通的值或者对象,返回一个新的promise对象,
// 并且它的状态是已完成/成功的, 值就是传入的这个值
const p = Promise.resolve({name:'果果'})
console.log(p)
p.then(res => {
    console.log(res)
})


Promise.resolve(1)  
// ==> 等价于
new Promise(resolve => resolve(1))


// 3. 如果传入的value就是一个promise对象
// Promise.resolve将原封不动的,返回这个promise
const p2 = new Promise((resolve, reject) => {
    reject('失败了')
}) 

const p3 = Promise.resolve(p2)
console.log(p3)

5. Promise.reject()

javascript

// Promise.reject() 返回一个新的promise对象,并且状态是失败,结果就是传入的参数
const p = Promise.reject('出错了')
console.log(p)

// 等同于
// const p = new Promise((resolve, reject) => reject('出错了'))

p.then(null, err => {
    console.log(err)
})

Promise.reject('出错了').catch(err => {
    console.log(err)
})

6. Promise.all()

javascript
// Promsie.all() 静态方法

// 1. Promise.all接收一个promise数组作为参数,返回一个新的promise对象。
// const p = Promise.all([p1, p2, p3])
// 最后p的状态,由p1,p2,p3决定

// 分两种情况
// 2.1 当p1,p2,p3都为fulfilled状态时,p的状态才会变成fulfilled(成功态、完成态)
//  p1,p2,p3的返回值,会挨个(按顺序)的组成一个新的数组,作为p的结果

// 2.2 
//  只要p1, p2, p3 有一个被rejected了,失败了,p的状态就会变成rejected,
//  第一个被rejected的promise的值(失败的原因),会作为p的结果
// ==> p.catch(err => console.log(err))

const p1 = Promise.resolve(111)
const p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve(222)
  }, 2000);
})
const p3 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve(333)
  }, 3000);
})

const p4 = Promise.reject('失败了4')
const p5 = Promise.reject('失败了5')

// 1. 所有的promise都成功了
const p = Promise.all([p1, p2, p3])

p.then(res => {
  console.log(res)
})
console.log(p)

// 2. 有一个promise失败了
const p21 = Promise.all([p1, p2, p4])
console.log(p11)
p11.then(res => {
  console.log(res)
}).catch(err => {
  console.log(err)
})

// 3. 有两个promise失败了, 第一个失败的值会作为promise.all的结果
const p22 = Promise.all([p1, p4, p5])
console.log(p22)
p22.then(res => {
  console.log(res)
}).catch(err => {
  console.log(err)
})

07 Promise.race()

javascript
// Promise.race() 接收一个promise数组
// 只要p1, p2, p3之中 有一个实例率先改变状态,p的状态就跟着改变
// race返回一个promise,它可以是完成态(成功态fulfilled),也可以是失败(rejected)

// race 竞赛,只认第一名

// const sleep = (ms) => {
//     return new Promise((resolve) =>{
//         setTimeout(() => {
//             resolve(ms)
//         }, ms);
//     })
// }
const sleep1 = s => new Promise(resolve => setTimeout(resolve, s * 1000))
// 上面这个返回值是undefined,1s后 => 成功态

const sleep2 = s => new Promise(resolve => setTimeout(resolve(s), s * 1000))
// 上面这个resolve(s) 立即执行了 , 立即得到1000结果

const sleep = s => new Promise(resolve => setTimeout(() => { resolve(s) }, s * 1000))
// sleep(1000).then(res => {
//     console.log(res)
//     console.log(222)
// })
// sleep(1000).then(res => {
//     console.log(res)
// })

const p1 = sleep(1)
const p2 = sleep(6)
const p3 = sleep(5)
const p4 = Promise.reject('error')

const p = Promise.race([p1, p2, p3, p4])
console.log(p)
p.then(res => {
    console.log(res)
}).catch(err => {
    console.log(err)
})

08 Promise.all和Promise.race

javascript
const api_books = 'http://ajax-api.itheima.net/api/books'
const api_news = 'http://ajax-api.itheima.net/api/news'
const api_robot = 'http://ajax-api.itheima.net/api/robot?spoken=你不好'

// Promise.all()
const fetch_book = fetch(api_books).then(res => res.json())
// console.log(fetch_book)
const fetch_news = fetch(api_news).then(res => res.json())
// console.log(fetch_news)
const fetch_robot = fetch(api_robot).then(res => res.json())
// console.log(fetch_robot)

// 所有的请求都成功了,返回给P
const p = Promise.all([fetch_book,fetch_news,fetch_robot])

console.log(p)


// Promise.race()
// 谁最快,最快的那个拿过来
const p2 = Promise.race([fetch_book,fetch_news,fetch_robot])
console.log(p2)

// all获取所有,race获取第一个

09 Promise.allSettled

想知道每一个promise的结果时,可以使用promise.allSettled

javascript
// 接收一个Promise数组,在所有promise对象都已经fulfilled或rejected后
// 返回一个返回每个promise结果的对象数组. 
// 每个对象有三个属性 
// status => promsie的状态: fulfilled / rejected
// value  =>成功的结果,如果rejected,undfined  
// reason =>失败的原因,如果fulfilled,undefined

const sleep = s => new Promise(resolve => setTimeout(() => { resolve(s) }, s * 1000))

const promises = [
    Promise.resolve(1),
    Promise.reject('error'),
    Promise.resolve(3),
    sleep(5)
]

Promise.allSettled(promises).then(res => {
   // 等结果--> 有了结果,才执行.then的回调
    console.log(res)
})

10 Promise.any()

等待第一个promise是成功的状态, Promise.any()不会因为某个 Promise 变成rejected状态而结束,必须等到所有参数 Promise 变成rejected状态才会结束。

javascript
// 等待第一个成功的状态,如果都失败了, 返回一个失败状态的promise的对象,值是所有的都失败
const sleep = s => new Promise((resolve,reject) => setTimeout(() => { reject('error') }, s * 1000))

const promises = [
    Promise.reject('error'),
    // sleep(5),
    Promise.reject('666'),
    // sleep(3)
    // Promise.reject('333')
    sleep(3)
]

const res = Promise.any(promises)
console.log(res)
res.then(res => {
    console.log(res)
}).catch(err => {
    console.log(err)
})
// Promise.any(promises).then(res => {
//     // 等结果--> 有了结果,才执行.then的回调
//     console.log(res)
// })

javascript
Promise.all()  ==> 等待所有的成功状态
Promise.race()  ==> 等待第一个promise的状态确定
Promise.allSettled()   ==> 等带每一个promise的状态
Promise.any()   ==>  等待第一个成功的状态确定

JS是一门单线程语言

javascript
// 1. JS 是一门单线程的语言   
// 也就是说,同一段时间只能做一件事,前一件事情做完了,才做下一件事情。

// 为什么JS是一门单线程的语言呢?
// JS设计之初为了操作DOM元素的, 我们不能同时去添加或者删除同一个DOM.
// 代码是从上到下运行

// 2. 线程 和 进程 
// ===> 简单理解
// 进程 process ==> 可以理解为正在运行着的程序 
// 线程 thread ==> 程序中的一个执行单元或执行路径。
// 在一个程序中,可能会有多个线程同时执行不同的任务


// 如果把 进程 ==> 火车  , 线程 ==> 一节一节的车厢 。
// 线程进程的特点:
// 1. 一个进程可以有多个线程
// 2. 线程必须依附进程才能运行
// 3. 线程之间共享进程中的数据。

// 一个正在生产着运行着的工厂 。。 ==> 进程。
// 可以将进程比喻成一个正在生产着运行着的工厂,而线程则是工厂里的工人。
// 在工厂中,不同的工人可以同时处理不同的任务,而且工人之间可以相互协作,共同完成整个生产过程。


// 3. 同步和异步
// 同步:同一时间只有一个任务再执行,前一个任务执行完,才能执行后一个任务。 串联
// 异步:可以同时执行多个任务,可以提高程序的性能。 并联

浏览器架构

javascript
// 目前:Chrome采用多进程架构

打开一个页面,会至少有四个进程
1. 浏览器(Browser)主进程
2. GPU 进程
3. 网络(NetWork)进程
4. 渲染进程 (Renderer Process)
5. 如果有插件在运行,还会有插件进程

----
1. 1 个浏览器(Browser)主进程
	   ===>  主要负责界面显示、用户交互、子进程管理,同时提供存储等功能。
2. 1 个GPU 进程
		 ===> 用于加速渲染和处理网页中的图形和动画效果, 
		 ---> 一开始是为了3D CSS绘制,之后网页,Chrome UI界面都采用GPU绘制
3. 1 个网络(NetWork)进程:           
		 ===>  负责处理网络请求,如HTTP请求、WebSocket连接等。       
4. 多个渲染进程 (Renderer Process):    
		 ===>   负责处理一个选项卡Tab的所有页面渲染任务。
5. 多个插件进程。(可能无)
		 ===> 主要是负责插件的运行,因插件易崩溃,所以需要通过插件进程来隔离,以保 
证插件进程崩溃不会对浏览器和页面造成影响。  

// JavaScriptV8 引擎和JS代码都运行在 渲染进程中!
// Chrome 会为每个 Tab 标签创建一个渲染进程

事件循环

image.png

javascript
console.log(1)

document.addEventListener('click', function () {
    console.log(4)
})

console.log(2)

setTimeout(function () {
    console.log(3)
}, 3000)

// 思考

// 异步任务一般由回调函数组成。
// 1. dom事件  click、load , resize
// 2. ajax/fetch 网络请求
// 3. setTimeout / setInterval

/* ==================== 事件循环低配版理解 ===================== */
// 1. 首先判断JS任务是同步的还是异步的,同步任务会在主线程的执行栈上依次执行。(顺序执行)
// 2. 异步任务会提交给异步进程处理(click/fetch),当满足触发条件后,异步进程会将异步任务(回调)
//    推到消息队列(任务队列)中
// 3. 当主线程上的所有的所有的,所有的同步任务执行完之后,就会去消息队列(任务队列中)看有没有
//    可以执行的异步任务,如果有,拿到主线程上执行.
//    执行完之后再去消息队列中查看,如果没有,等,依次不断的循环

// EventLoop
javascript
console.log(0);  

setTimeout(function () {
    console.log(1);    
});

new Promise(function(resolve,reject){
    console.log(2)
    resolve(3) 
    console.log(6)
}).then(function(val){
    console.log(val);  
})

console.log(4);

事件循环 => 宏微任务

javascript
console.log(0);  

// 下一个宏任务的开始 
setTimeout(function () {
    console.log(1);    
});

new Promise(function(resolve,reject){
    // 同步执行的!
    console.log(2)
    resolve(3) 
    console.log(6)
}).then(function(val){
    console.log(val);  
})

console.log(4)

// 我们的任务还分为 宏任务 macroTask 和 微任务 microTask


// 宏任务
// 1. script代码块
// 2. setTimeout / setInterval
// 3. setImmediate 

// 微任务
// 1. promise.then() / promise.catch()
// 2.  async / await 
// 3. MutationObeserver ==> 监听dom的改变的(Vue源码中有)
// 4. process.nextTick (node)


// 在当前事件循环中,微任务的优先级高,比下一个宏任务的优先级高
// 微任务是属于(包含于)宏任务里面的嘛? 是
// 1. 一个宏任务中,可以包含多个微任务
// 2. 每执行完一个宏任务,就会清空当前的微任务队列中的所有微任务。

// 执行宏任务,清空当前宏任务中产生的所有微任务,然后再执行下一个宏任务,再清空所有的微任务。


/* ==================== 事件循环 宏微任务 ===================== */
// 1. 首先,我们的script代码块,可以看做是一个宏任务,开始第一个Tick事件循环。
// 2. 先执行当前任务中的所有同步代码,
// 3. 如果遇到宏任务,就放到宏任务队列中等待执行,如果遇到微任务,就放到微任务队列中。
// 4. 当主线程执行完所有的同步代码,首先,去微任务队列中清空当前事件循环的所有微任务
//   (表示这一轮Tick事件循环结束)
// 5. 再去执行下一个宏任务  (下一个宏任务的开始)

我们经常说微任务的优先级比宏任务高?怎么理解?
==> 在本轮事件循环中的微任务比下一次事件循环中的宏任务优先级高 

我们可以把宏微任务关系想象成 拔出萝卜带出泥,宏任务就是萝卜,微任务就是萝卜上的泥。
我们每次拔萝卜,都要把萝卜上的泥清理掉,再去拔下一个萝卜~~~
javascript
  function wait() {
      return new Promise((resolve) => {
          setTimeout(() => {  
              console.log(111)   
              const p =  new Promise(resolve => {
                  resolve(6)
              })
              p.then(res => {
                  console.log(res)
              })

          })

          console.log(222)  

          resolve(666)
      }, 1000)
  }
  wait().then((res) => {
      console.log(res)
      console.log(3)
  })

async / await

javascript
// async和await
// 作用:是异步终极解决方案——》是一对关键词,需要配合使用

// async关键字,
// 1. async用于修饰一个函数,表示该函数是异步的,=> 返回一个promsie对象
//  如果在async函数内部没有 await,此时async是没有意义的,函数内部就全是同步内容
//  如果在async函数内部遇到了await,await下面那一行的代码会以异步处理,相当于.then的回调


// 2. async函数内部return语句返回的值,会成为then方法回调函数的参数。


// await关键字:
// 1. await必须在async函数内使用,写在普通函数内会报错

// 2. await后面一般会跟着一个promise对象, 返回该对象的结果(成功或失败)
//    如果不是 Promise 对象,就直接返回对应的值。

// 3. await后面的Promise对象,运行结果可能是rejected,那么会报错
//   所以最好把await命令放在try...catch代码块中。

try {
  放可能会出错的语法
} catch(err) {
  一旦try中的代码出错,会被catch捕获到,其中的参数e就是错误信息
}
javascript
// async和await
// 作用:是异步终极解决方案——》是一对关键词,需要配合使用

// async关键字,
// 1. async用于修饰一个函数,表示该函数是异步的,=> 返回一个promsie对象
    async function fn(){
        // 内部按理说,应该写一些异步的代码
        return 'hello async'
    }

    console.log(fn())

// 2.1 如果在async函数内部没有 await,此时async是没有意义的,函数内部就全是同步内容
    async function foo(){
        let num = 100
        console.log(num)
    }
    foo()
    console.log(200)
// 2.2 如果在async函数内部遇到了await,await下面那一行的代码会以异步处理,相当于.then的回调
    async function foo(){
        let num = await 100  // ==> 这一行是同步执行的,
        // await下面的都相当于是放到了.then()的回调函数中
        console.log(333)
    }

    // ===> 相当于  
    function foo(){
        return Promise.resolve(100).then(num => {
            console.log(num)
            console.log(222)
            console.log(333)
        })
    }
// 3. async函数内部return语句返回的值,会成为then方法回调函数的参数。
        async function fn(){
            // 内部按理说,应该写一些异步的代码
            return 'hello async'
        }

        fn().then(res => {
            console.log(res)
        })

async有多种形式

javascript
// 1. 函数声明
async function foo(){}

// 2. 函数表达式
const bar = async function(){}

// 3. 对象的方法
const obj = {
    name:'jianguo',
    async sayHi(){
        console.log(111)
    }
}

// 4. 箭头函数
const foo = async () => {}

await 关键字

javascript
// await关键字:
// 1. await必须在async函数内使用,写在普通函数内会报错
    async function fn(){
        let num = await 100
        console.log(num)
    }
    fn()
// 2. await后面一般会跟着一个promise对象, 返回该对象的结果(成功或失败)
//    如果不是 Promise 对象,就直接返回对应的值。

const sleep = s => new Promise(resolve => setTimeout(() => resolve(s), s * 1000))
// const p = sleep(1)
// console.log(p)
// p.then(res => {
//     console.log(res)
// })

async function fn(){
    let res = await sleep(3)
    // 下面的代码,相当于.then(res => {})
    console.log(res)
}
fn()

const api_books = 'http://ajax-api.itheima.net/api/books'
const api_news = 'http://ajax-api.itheima.net/api/news'


// // 获取新闻列表
// fetch(api_news).then(res => res.json()).then(res => {
//     console.log(res)
// })
// // 获取图书列表
// fetch(api_books).then(res => res.json()).then(res => {
//     console.log(res)
// })

//Q:先获取新闻,等新闻的结果回来了之后,我再请求图书列表 ?

// 获取新闻列表
fetch(api_news).then(res => res.json()).then(res => {
    console.log(res)
    // 获取图书列表
    fetch(api_books).then(res => res.json()).then(res => {
        console.log(res)
    })
})

;(async function(){
    // await的意思就是等待 
   let res1 = await fetch(api_news).then(res => res.json())
   // await 会阻塞后面代码的执行 
   console.log(res1)
   let res2 = await fetch(api_books).then(res => res.json())
   console.log(res2)
})()
javascript
async function async1() {
    // 这里的代码是同步的 
    console.log('async1 start') 
    await async2() // 这里要执行,同步,不等待
    // 相当于放到了.then() 异步   微任务
    console.log('async1 end') 
    console.log(666)
}
async function async2() {
    console.log('async2') 
}

console.log('script start')  

setTimeout(function() {
    console.log('setTimeout') 
}, 0)

async1();

new Promise(function(resolve) {
    console.log('promise1')
    resolve();
}).then(function() {
    console.log('promise2')  
});
console.log('script end')

// script start
// async1 start
// async2
// promise1
// script end  ==> 所有的同步代码执行完了 , 清空微任务队列
// async1 end  666 
// promise2    ==> 当前事件循环结束 Tick结束 
// setTimeout

我们经常说微任务的优先级比宏任务高?怎么理解?
==> 在本轮事件循环中的微任务比下一次事件循环中的宏任务优先级高 

我们可以把宏微任务关系想象成 拔出萝卜带出泥,宏任务就是萝卜,微任务就是萝卜上的泥。
我们每次拔萝卜,都要把萝卜上的泥清理掉,再去拔下一个萝卜~~~
javascript
console.log(1)

setTimeout(function () {
  console.log(2)
  new Promise(function (resolve) {
    console.log(3)
    resolve()
  }).then(function () {
    console.log(4)
  })
})

const p = new Promise((resolve, reject) => {
  console.log(5)
  resolve() // 标记为成功
  console.log(6)
})

p.then(data => {
  console.log(7)
})

console.log(8)

// 1 5 6 8 7  /   2 3 4