打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
如何写出一个惊艳面试官的 Promise【近 1W字】

前言

1.高级 WEB 面试会让你手写一个Promise,Generator 的 PolyFill(一段代码);
2.在写之前我们简单回顾下他们的作用;
3.手写模块见PolyFill.

源码

源码地址请戳,原创码字不易,欢迎 star

如果觉得看文章太啰嗦,可以直接 git clone ,直接看代码

1.Promise

1.1 作用

Promise 大家应该都用过,ajax 库就是利用 Promise封装的;
作用主要是解决地狱回调问题.

1.2 使用

1.2.1.方法一

new Promise((resolve,reject)=>{  resolve('这是第一个 resolve 值')}).then((data)=>{  console.log(data) //会打印'这是第一个 resolve 值'}).catch(()=>{})new Promise((resolve,reject)=>{  reject('这是第一个 reject 值')}).then((data)=>{  console.log(data)}).catch((data)=>{  console.log(data) //会打印'这是第一个 reject 值'})

1.2.2.方法二(静态方法)

Promise.resolve('这是第二个 resolve 值').then((data)=>{  console.log(data) // 会打印'这是第二个 resolve 值'})Promise.reject('这是第二个 reject 值').then((data)=>{  console.log(data)}).catch(data=>{  console.log(data) //这是第二个 reject 值})

1.2.3.方法三(多个 Promise并行执行异步操作)

表示多个 Promise 都进入到 FulFilled 或者 Rejected 就会执行

const pOne = new Promise((resolve, reject) => {    resolve(1);});const pTwo = new Promise((resolve, reject) => {    resolve(2);});const pThree = new Promise((resolve, reject) => {    resolve(3);});Promise.all([pOne, pTwo, pThree]).then(data => {     console.log(data); // [1, 2, 3] 正常执行完毕会执行这个,结果顺序和promise实例数组顺序是一致的}, err => {    console.log(err); // 任意一个报错信息});

1.2.4.方法四(多个中一个正常执行)

表示多个 Promise 只有一个进入到 FulFilled 或者 Rejected 就会执行

const pOne = new Promise((resolve, reject) => {    resolve(1);});const pTwo = new Promise((resolve, reject) => {    resolve(2);});const pThree = new Promise((resolve, reject) => {    // resolve(3);});Promise.race([pOne, pTwo, pThree]).then(data => {     console.log(data); // 1 只要碰到FulFilled 或者 Rejected就会停止执行}, err => {    console.log(err); // 任意一个报错信息});

1.3 作用分析

1.3.1 参数和状态

1.Promise接受一个函数handle作为参数,handle包括resolve和reject两个是函数的参数
2.Promise 相当于一个状态机,有三种状态:pending,fulfilled,reject,初始状态为 pending
3.调用 resolve,状态由pending => fulfilled
4.调用reject,会由pending => rejected
5.改变之后不会变化

1.3.2 then 方法

1.接受两个参数,onFulfilled和onRejected可选的函数

2.不是函数必须被忽略

3.onFullfilled:
A.当 promise 状态变为成功时必须被调用,其第一个参数为 promise 成功状态传入的值( resolve 执行时传入的值;
B.在 promise 状态改变前其不可被调用
C.其调用次数不可超过一次

4.onRejected:作用和onFullfilled类似,只不过是promise失败调用

5.then方法可以链式调用
A.每次返回一个新的Promise
B.执行规则和错误捕获:then的返回值如果是非Promise直接作为下一个新Promise参数,如果是Promise会等Promise执行

// 返回非Promiselet promise1 = new Promise((resolve, reject) => {  setTimeout(() => {    resolve()  }, 1000)})promise2 = promise1.then(res => {  // 返回一个普通值  return '这里返回一个普通值'})promise2.then(res => {  console.log(res) //1秒后打印出:这里返回一个普通值})// 返回Promiselet promise1 = new Promise((resolve, reject) => {  setTimeout(() => {    resolve()  }, 1000)})promise2 = promise1.then(res => {  // 返回一个Promise对象  return new Promise((resolve, reject) => {    setTimeout(() => {     resolve('这里返回一个Promise')    }, 2000)  })})promise2.then(res => {  console.log(res) //3秒后打印出:这里返回一个Promise})

C. onFulfilled 或者onRejected 抛出一个异常 e ,则 promise2 必须变为失败(Rejected),并返回失败的值 e

let promise1 = new Promise((resolve, reject) => {  setTimeout(() => {    resolve('success')  }, 1000)})promise2 = promise1.then(res => {  throw new Error('这里抛出一个异常e')})promise2.then(res => {  console.log(res)}, err => {  console.log(err) //1秒后打印出:这里抛出一个异常e})

D.onFulfilled 不是函数且 promise1 状态为成功(Fulfilled), promise2 必须变为成功(Fulfilled)并返回 promise1 成功的值

let promise1 = new Promise((resolve, reject) => {  setTimeout(() => {    resolve('success')  }, 1000)})promise2 = promise1.then('这里的onFulfilled本来是一个函数,但现在不是')promise2.then(res => {  console.log(res) // 1秒后打印出:success}, err => {  console.log(err)})

E.onRejected 不是函数且 promise1 状态为失败(Rejected),promise2必须变为失败(Rejected) 并返回 promise1 失败的值

let promise1 = new Promise((resolve, reject) => {  setTimeout(() => {    reject('fail')  }, 1000)})promise2 = promise1.then(res => res, '这里的onRejected本来是一个函数,但现在不是')promise2.then(res => {  console.log(res)}, err => {  console.log(err)  // 1秒后打印出:fail})

F.resolve和reject结束一个Promise的调用
G.catch方法,捕获异常
其实复杂的是在then的异常处理上,不过不用急,边看边理解

1.3.3 方法

1.静态resolve方法
参照1.3.1用法2

2.静态reject方法
参照1.3.1用法2

3.静态all方法
参照1.3.1用法3

4.静态race方法
参照1.3.1用法4

5.自定义done方法
Promise 对象的回调链,不管以then方法或catch方法结尾,要是最后一个方法抛出错误,都有可能无法捕捉到(因为 Promise内部的错误不会冒泡到全局)
因此,我们可以提供一个done方法,总是处于回调链的尾端,保证抛出任何可能出现的错误

 Promise.prototype.done = function (onFulfilled, onRejected) {    this      .then(onFulfilled, onRejected)      .catch(function (reason) {        // 抛出一个全局错误        setTimeout(() => {          throw reason        }, 0)      })  }

6.自定义finally方法
finally方法用于指定不管Promise对象最后状态如何,都会执行的操作
它与done方法的最大区别,它接受一个普通的回调函数作为参数,该函数不管怎样都必须执行

Promise.prototype.finally = function (callback) {    let P = this.constructor    return this.then(      value => P.resolve(callback()).then(() => value),      reason => P.resolve(callback()).then(() => {        throw reason      })    )  }

1.4 PolyFill

1.4.1 初级版

class MyPromise {  constructor (handle) {    // 判断handle函数与否    if (typeof handle!=='function') {      throw new Error('MyPromise must accept a function as a parameter')    }    // 添加状态    this._status = 'PENDING'    // 添加状态    this._value = undefined    // 执行handle    try {      handle(this._resolve.bind(this), this._reject.bind(this))     } catch (err) {      this._reject(err)    }  }  // 添加resovle时执行的函数  _resolve (val) {    if (this._status !== 'PENDING') return    this._status = 'FULFILLED'    this._value = val  }  // 添加reject时执行的函数  _reject (err) {     if (this._status !== 'PENDING') return    this._status = 'REJECTED'    this._value = err  }}

回顾一下,初级版实现了1,2,3这三点功能,怎么样还是so-easy吧!

1.4.2 中级版

1.由于 then 方法支持多次调用,我们可以维护两个数组,将每次 then 方法注册时的回调函数添加到数组中,等待执行
在初级的基础上加入成功回调函数队列和失败回调队列和then方法

this._fulfilledQueues = []this._rejectedQueues = []

2.then方法

then (onFulfilled, onRejected) {  const { _value, _status } = this  switch (_status) {    // 当状态为pending时,将then方法回调函数加入执行队列等待执行    case 'PENDING':      this._fulfilledQueues.push(onFulfilled)      this._rejectedQueues.push(onRejected)      break    // 当状态已经改变时,立即执行对应的回调函数    case 'FULFILLED':      onFulfilled(_value)      break    case 'REJECTED':      onRejected(_value)      break  }  // 返回一个新的Promise对象  return new MyPromise((onFulfilledNext, onRejectedNext) => {  })}

3.then方法规则完善

// 添加then方法then (onFulfilled, onRejected) {  const { _value, _status } = this  // 返回一个新的Promise对象  return new MyPromise((onFulfilledNext, onRejectedNext) => {    // 封装一个成功时执行的函数    let fulfilled = value => {      try {        if (typeof onFulfilled!=='function') {          onFulfilledNext(value)        } else {          let res =  onFulfilled(value);          if (res instanceof MyPromise) {            // 如果当前回调函数返回MyPromise对象,必须等待其状态改变后在执行下一个回调            res.then(onFulfilledNext, onRejectedNext)          } else {            //否则会将返回结果直接作为参数,传入下一个then的回调函数,并立即执行下一个then的回调函数            onFulfilledNext(res)          }        }      } catch (err) {        // 如果函数执行出错,新的Promise对象的状态为失败        onRejectedNext(err)      }    }    // 封装一个失败时执行的函数    let rejected = error => {      try {        if (typeof onRejected!=='function') {          onRejectedNext(error)        } else {            let res = onRejected(error);            if (res instanceof MyPromise) {              // 如果当前回调函数返回MyPromise对象,必须等待其状态改变后在执行下一个回调              res.then(onFulfilledNext, onRejectedNext)            } else {              //否则会将返回结果直接作为参数,传入下一个then的回调函数,并立即执行下一个then的回调函数              onFulfilledNext(res)            }        }      } catch (err) {        // 如果函数执行出错,新的Promise对象的状态为失败        onRejectedNext(err)      }    }    switch (_status) {      // 当状态为pending时,将then方法回调函数加入执行队列等待执行      case 'PENDING':        this._fulfilledQueues.push(fulfilled)        this._rejectedQueues.push(rejected)        break      // 当状态已经改变时,立即执行对应的回调函数      case 'FULFILLED':        fulfilled(_value)        break      case 'REJECTED':        rejected(_value)        break    }  })}

4.当 resolve 或 reject 方法执行时,我们依次提取成功或失败任务队列当中的函数开始执行,并清空队列,从而实现 then 方法的多次调用

// 添加resovle时执行的函数_resolve (val) {  if (this._status !== PENDING) return  // 依次执行成功队列中的函数,并清空队列  const run = () => {    this._status = FULFILLED    this._value = val    let cb;    while (cb = this._fulfilledQueues.shift()) {      cb(val)    }  }  // 为了支持同步的Promise,这里采用异步调用  setTimeout(() => run(), 0)}// 添加reject时执行的函数_reject (err) {   if (this._status !== PENDING) return  // 依次执行失败队列中的函数,并清空队列  const run = () => {    this._status = REJECTED    this._value = err    let cb;    while (cb = this._rejectedQueues.shift()) {      cb(err)    }  }  // 为了支持同步的Promise,这里采用异步调用  setTimeout(run, 0)}

5.当 resolve 方法传入的参数为一个 Promise 对象时,则该 Promise 对象状态决定当前 Promise 对象的状态

// 添加resovle时执行的函数_resolve (val) {  const run = () => {    if (this._status !== PENDING) return    this._status = FULFILLED    // 依次执行成功队列中的函数,并清空队列    const runFulfilled = (value) => {      let cb;      while (cb = this._fulfilledQueues.shift()) {        cb(value)      }    }    // 依次执行失败队列中的函数,并清空队列    const runRejected = (error) => {      let cb;      while (cb = this._rejectedQueues.shift()) {        cb(error)      }    }    /* 如果resolve的参数为Promise对象,则必须等待该Promise对象状态改变后,      当前Promsie的状态才会改变,且状态取决于参数Promsie对象的状态    */    if (val instanceof MyPromise) {      val.then(value => {        this._value = value        runFulfilled(value)      }, err => {        this._value = err        runRejected(err)      })    } else {      this._value = val      runFulfilled(val)    }  }  // 为了支持同步的Promise,这里采用异步调用  setTimeout(run, 0)}

6.catch方法

// 添加catch方法catch (onRejected) {  return this.then(undefined, onRejected)}

1.4.3 高级版

1.静态 resolve 方法

// 添加静态resolve方法static resolve (value) {  // 如果参数是MyPromise实例,直接返回这个实例  if (value instanceof MyPromise) return value  return new MyPromise(resolve => resolve(value))}

2.静态 reject 方法

// 添加静态reject方法static reject (value) {  return new MyPromise((resolve ,reject) => reject(value))}

3.静态 all 方法

// 添加静态all方法static all (list) {  return new MyPromise((resolve, reject) => {    /**     * 返回值的集合     */    let values = []    let count = 0    for (let [i, p] of list.entries()) {      // 数组参数如果不是MyPromise实例,先调用MyPromise.resolve      this.resolve(p).then(res => {        values[i] = res        count++        // 所有状态都变成fulfilled时返回的MyPromise状态就变成fulfilled        if (count === list.length) resolve(values)      }, err => {        // 有一个被rejected时返回的MyPromise状态就变成rejected        reject(err)      })    }  })}

4.静态 race 方法

// 添加静态race方法static race (list) {  return new MyPromise((resolve, reject) => {    for (let p of list) {      // 只要有一个实例率先改变状态,新的MyPromise的状态就跟着改变      this.resolve(p).then(res => {        resolve(res)      }, err => {        reject(err)      })    }  })}

5.done方法
作用:不管以then方法或catch方法结尾,要是最后一个方法抛出错误,都有可能无法捕捉到(因为 Promise 内部的错误不会冒泡到全局);处于回调链的尾端,保证抛出任何可能出现的错误
目前 Promise 上还没有 done,我们可以自定义一个

Promise.prototype.done = function (onFulfilled, onRejected) {  console.log('done')    this.then(onFulfilled, onRejected)      .catch((reason)=> {        // 抛出一个全局错误        setTimeout(() => {          throw reason        }, 0)      })  }Promise.resolve('这是静态方法的第一个 resolve 值').then(()=>{  return '这是静态方法的第二个 resolve 值'}).then(()=>{  throw('这是静态方法的第一个 reject 值')  return '这是静态方法的第二个 resolve 值'}).done()

6.finally方法
作用:不管 Promise 对象最后状态如何,都会执行的操作
与done方法的最大区别,它接受一个普通的回调函数作为参数,该函数不管怎样都必须执行

finally (cb) {  return this.then(    value  => MyPromise.resolve(cb()).then(() => value),    reason => MyPromise.resolve(cb()).then(() => { throw reason })  );};

7.完整代码
请戳,源码地址
欢迎 star!

2.Generator

2.1 定义

1.Generator可以理解为一个状态机,内部封装了很多状态,同时返回一个迭代器Iterator对象;
2.迭代器Iterator对象:定义标准方式产生一个有限或无限序列值,迭代器有next()对象;
3.多次返回可以被 next多次调用,最大特点是可以控制执行顺序;

2.2 声明方法

2.是一种特殊的函数

function* gen(x){ const y = yield x + 6; return y;}// yield 如果用在另外一个表达式中,要放在()里面// 像上面如果是在=右边就不用加()function* genOne(x){  const y = `这是第一个 yield 执行:${yield x + 1}`; return y;}

整个 Generator 函数就是一个封装的异步任务,或者说是异步任务的容器。异步操作需要暂停的地方,都用 yield 语句注明

2.3 执行

1.普通执行

const g = gen(1);//执行 Generator 会返回一个Object,而不是像普通函数返回return 后面的值g.next() // { value: 7, done: false }//调用指针的 next 方法,会从函数的头部或上一次停下来的地方开始执行,直到遇到下一个 yield 表达式或return语句暂停,也就是执行yield 这一行// 执行完成会返回一个 Object,// value 就是执行 yield 后面的值,done 表示函数是否执行完毕g.next() // { value: undefined, done: true }// 因为最后一行 return y 被执行完成,所以done 为 true

2.next 方法传参数

const g = gen(1);g.next() // { value: 7, done: false }g.next(2) // { value: 2, done: true } // next 的参数是作为上个阶段异步任务的返回结果3.嵌套执行  必须用到yield*关键字  

function* genTwo(x){
yield* gen(1)
yield* genOne(1)
const y = 这是第 二个 yield 执行:${yield x + 2};
return y;
}
const iterator=genTwo(1)
// 因为 Generator 函数运行时生成的是一个 Iterator 对象,所以可以直接使用 for...of 循环遍历
for(let value of iterator) {

console.log(value)

}

2.4 yield和 return 的区别

相同点:
1.都能返回语句后面的那个表达式的值
2.都可以暂停函数执行
区别:
一个函数可以有多个 yield,但是只能有一个 return
yield 有位置记忆功能,return 没有

2.5 throw

抛出错误,可以被try...catch...捕捉到

g.throw('这是抛出的一个错误');// 这是抛出的一个错误

2.6 应用

// 要求:函数valOne,valTwo,valThree 以此执行function* someTask(){try{  const valOne=yield 1  const valTwo=yield 2  const valThree=yield 3}catch(e){}}scheduler(someTask());function scheduler(task) {  const taskObj = task.next(task.value);  console.log(taskObj)  // 如果Generator函数未结束,就继续调用  if (!taskObj.done) {    task.value = taskObj.value    scheduler(task);  }}

2.7 PolyFill

原理图

2.7.1 初级版

实现一个迭代器(Iterator)

// 源码实现function createIterator(items) {    var i = 0    return {        next: function() {            var done = (i >= items.length)            var value = !done ? items[i++] : undefined                        return {                done: done,                value: value            }        }    }}// 应用const iterator = createIterator([1, 2, 3])console.log(iterator.next())    // {value: 1, done: false}console.log(iterator.next())    // {value: 2, done: false}console.log(iterator.next())    // {value: 3, done: false}console.log(iterator.next())    // {value: undefined, done: true}

2.7.2 中级版

实现可迭代(Iterable)
1.可以通过 for...of...遍历的对象,即原型链上有Symbol.iterator属性;
2.Symbol.iterator:返回一个对象的无参函数,被返回对象符合迭代器协议;
3.for...of接受一个可迭代对象(Iterable),或者能强制转换/包装成一个可迭代对象的值(如’abc’),遍历时,for...of会获取可迭代对象的'Symbol.iterator',对该迭代器逐次调用next(),直到迭代器返回对象的done属性为true时,遍历结束,不对该value处理;

const a = ['a', 'b', 'c', 'd', 'e']for (let val of a) {    console.log(val)}// 'a' 'b' 'c' 'd' 'e'// 等价于const a = ["a", "b", "c", "d", "e"]for (let val, ret, it = a[Symbol.iterator]();    (ret = it.next()) && !ret.done;    ) {    let = ret.value    console.log(val)}// "a" "b" "c" "d" "e"

4.yield* 可返回一个 Iterable对象;
5.源码改造

function createIterator(items) {    let i = 0    return {        next: function () {            let done = (i >= items.length)            let value = !done ? items[i++] : undefined            return {                done: done,                value: value            }        }        [Symbol.iterator]: function () {            return this        }    }}let iterator = createIterator([1, 2, 3])...iterator        // 1, 2, 3

2.7.3 高级版

1.for...of...接收可迭代对象,能强制转换或包装可迭代对象的值;
2.遍历时,for...of会获取可迭代对象的'Symbol.iterator',对该迭代器逐次调用next(),直到迭代器返回对象的done属性为true时,遍历结束,不对该value处理;
3.所以可以利用 for...of...封装到原型链上.

Object.prototype[Symbol.iterator] = function* () {    for (const key in this) {        if (this.hasOwnProperty(key)) {            yield [key, this[key]]        }    }}

3.async 和 await

3.1 async作用

1.async 函数返回的是一个 Promise 对象
在函数中 return 一个直接量,async 会把这个直接量通过 Promise.resolve() 封装成 Promise 对象

async function testAsync() {    return "hello async";}const result = testAsync();console.log(result); //Promise 对象

2.async和then
async返回一个Promise,所以可以通过then获取值

testAsync().then(v => {    console.log(v);    // 输出 hello async});

所以async里面的函数会马上执行,这个就类似Generator的‘*’

3.2 await作用

1.await后面可以是Promise对象或其他表达式

function getSomething() {    return "something";}async function testAsync() {    return Promise.resolve("hello async");}async function test() {    const v1 = await getSomething();    const v2 = await testAsync();    console.log(v1, v2); //something 和 hello async}test();

2.await后面不是Promise对象,直接执行

3.await后面是Promise对象会阻塞后面的代码,Promise 对象 resolve,然后得到 resolve 的值,作为 await 表达式的运算结果

4.所以这就是await必须用在async的原因,async刚好返回一个Promise对象,可以异步执行阻塞

3.3 async和await结合作用

1.主要是处理Promise的链式回调或函数的地狱回调
回到Generator中要求函数valOne,valTwo,valThree函数依次执行

function valOne(){}function valTwo(){}function valThree(){}async ()=>{  await valOne()  await valTwo()  await valThree()}

2.处理异常
try...catch...
或者await .catch()

3.4 和Generator的区别

1.async是内置执行器,Generator 函数的执行必须依靠执行器,无需手动执行next()
2.更广的适用性。co模块约定,yield命令后面只能是 Thunk 函数或 Promise 对象,而await后面可以是任意表达式,都会返回一个Promise对象

// Thunk函数:是能将执行结果传入回调函数,并将该回调函数返回的函数function f(m) {  return m * 2;}f(x + 5);// 等同于var thunk = function () {  return x + 5;};function f(thunk) {  return thunk() * 2;}

3.返回Promise,而Generator返回 Iterator
4.async 函数就是 Generator 函数的语法糖
async就相当于Generator的*,await相当于yield,用法有很多相似之处

3.5 执行器PolyFill

实现执行器两种方式:
回调函数(Thunk 函数)
Promise 对象

3.5.1 初级版

https://juejin.im/post/5dc28e...

async function fn(args) {  // ...}// 等价于function fn(args) {  return spawn(function* () {    // ...  });}function spawn(gen){  let g = gen();  function next(data){    let result = g.next(data);    if (result.done) return result.value;    result.value.then(function(data){      next(data);    });  }  next();}

3.5.2 高级版

function spawn(genF) { //spawn函数就是自动执行器,跟简单版的思路是一样的,多了Promise和容错处理  return new Promise(function(resolve, reject) {    const gen = genF();    function step(nextF) {      let next;      try {        next = nextF();      } catch(e) {        return reject(e);      }      if(next.done) {        return resolve(next.value);      }      Promise.resolve(next.value).then(function(v) {        step(function() { return gen.next(v); });      }, function(e) {        step(function() { return gen.throw(e); });      });    }    step(function() { return gen.next(undefined); });  });}

4.Promise,Generator,async和await对比

4.1 代码

1.代码对比:
场景:假定某个 DOM 元素上面,部署了一系列的动画,前一个动画结束,才能开始后一个。如果当中有一个动画出错,就不再往下执行,返回上一个成功执行的动画的返回值。
A.Promise

function chainAnimationsPromise(elem, animations) {  // 变量ret用来保存上一个动画的返回值  let ret = null;  // 新建一个空的Promise  let p = Promise.resolve();  // 使用then方法,添加所有动画  for(let anim of animations) {    p = p.then(function(val) {      ret = val;      return anim(elem);    });  }  // 返回一个部署了错误捕捉机制的Promise  return p.catch(function(e) {    /* 忽略错误,继续执行 */  }).then(function() {    return ret;  });}

B.Generator

function chainAnimationsGenerator(elem, animations) {  return spawn(function*() {    let ret = null;    try {      for(let anim of animations) {        ret = yield anim(elem);      }    } catch(e) {      /* 忽略错误,继续执行 */    }    return ret;  });}

C.async

async function chainAnimationsAsync(elem, animations) {  let ret = null;  try {    for(let anim of animations) {      ret = await anim(elem);    }  } catch(e) {    /* 忽略错误,继续执行 */  }  return ret;}

对比可以看出 async...await...代码更优雅

4.2 原理

async 和 await 是在 Generator 的基础上封装了自执行函数和一些特性;
具体对比见没个 API 的 PolyFill

4.3 执行顺序

来道头条的面试

console.log('script start')async function async1() {await async2()console.log('async1 end')}async function async2() {console.log('async2 end')}async1()setTimeout(function() {console.log('setTimeout')}, 0)new Promise(resolve => {console.log('Promise')resolve()}).then(function() {console.log('promise1')}).then(function() {console.log('promise2')})console.log('script end')// 旧版 Chrome 打印// script start => async2 end => Promise => script end => promise1 => promise2 => async1 end => setTimeout// 新版 Chrome 打印// script start => async2 end => Promise =>  script end => async1 end => promise1 => promise2 => setTimeout// 这里面其他的顺序除了async1 end , promise1 , promise2 这几个顺序有点争议,其他应该没有什么问题// 新版是因为V8 团队将最新的规范进行了修改,await变得更快了,这道题细节分析不再赘述,上面原理都有讲到

后语

原创码字不易,欢迎 star!

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
目前最好的 JavaScript 异步方案 async/await
20分钟带你掌握JavaScript Promise和 Async/Await
JavaScript异步之从promise到await
js 宏观任务和微观任务> promise的代码为什么比setTimeout先执行
ES6新特性(5)之Promise/async
细说 JavaScript 中的 Promise
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服