如何通过12个实例加固对promise的理解基础?

2026-05-22 06:391阅读0评论SEO问题
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计3170个文字,预计阅读时间需要13分钟。

如何通过12个实例加固对promise的理解基础?

在工作中常用到 promise, async, await,遇到问题需运用基础知识,总会有一部分记不得,便重新温习权限指南和 Es6 标准入门。花了几天时间啃完了这篇文章。喜欢的同学请动动手点赞。

工作中常常用到promise,async + await,遇到一些问题需要用到基础知识总会有一部分不记得,就重新温习权威指南和es6标准入门,花了几天肝下了这篇文章。喜欢的同学请动动发财手点个赞,文章有错误的地方还请指出。

例一

new Promise((resolve,reject) =>{ console.log('11') resolve() console.log('Promise') }) console.log('start')

结果:

11 Promise start

分析:

  1. Promise 新建后就会立即执行,从上往下执行,打印11
  2. 然后碰到resolve(),Promise状态由pending变为fulfilled
  3. 但调用resolvereject并不会终结 Promise 的参数函数的执行,所以会往下执行,打印出Promise
  4. 继续往下,打印出start
    总结:调用resolve或reject并不会终结 Promise 的参数函数的执行

再看一个代码类似的例子但执行过程却不一样

例二

new Promise((resolve, reject) => { return resolve(1); console.log(2); }).then((res) =>{ console.log('then',res) })

结果:

then 1

分析:

  1. Promise 新建后就会立即执行,碰到resolve(1),Promise状态由pending变为fulfilled
  2. 但这里加上了return,console.log(2)不会执行
  3. 执行.then(),打印出 then 1
    结果:Promise参数函数中加上return,后面的语句不会执行了,2不会被打印。.then().catch()中也是一样。

猜猜下面的执行会是什么

new Promise((resolve, reject) => { resolve(1); }).then((res) =>{ return 2; console.log('then1',res) }).then((res) =>{ console.log('then2',res) throw new Error('error') }).catch((err) =>{ return 'catch返回值' console.log('catch',err) }).then((res) =>{ console.log('then3',res) })

结果:

then2 2 then3 catch返回值

分析:

  1. new Promise立即执行,resolve(1)1作为返回值传给.then()
  2. 执行.then(),遇到 return 2,相当于return Promise.resolve(2),由于加了return,后面的 then1不会被打印
  3. 执行第二个.then(),打印 then2 2,然后抛出一个错误,相当于执行了 return Promise.reject('error')
  4. 往下执行,.catch()捕获到了错误,并 return 'catch返回值',相当于return Promise.resolve('catch返回值'),同样下面的 cosnole.log('catch',err)不会执行
  5. 最后的.then()会接收到上面的返回值,并打印 then3 catch返回值
例三

Promise.resolve('start') .then((res) =>{ console.log('then1',res) return 11 //相当于 return Promise.resolve(11) }).then((res) =>{ console.log('then2',res) //相当于 return Promise.resolve(undefined) }).then((res) =>{ console.log('then3',res) throw new Error('then3 error') //相当于 return Promise.reject(new Error('then3 error')) }).catch((res) =>{ console.log('catch',res) })

结果:

then1 start then2 11 then3 undefined catch Error: then3 error

分析:在Promise中,返回任意一个非 promise 的值都会被包裹成promise对象

例四

const promise = new Promise((resolve, reject) => { console.log(1); console.log(2); }); promise.then(() => { console.log(3); }); console.log(4);

结果:

1 2 4

分析:

  1. new Promise立即执行,打印 12,
  2. 遇到promise.then(),由于Promise中没有resolve()或者reject(),所以promise的状态会一直是pending,promise.then()方法不会执行,3 不会被打印,
  3. 继续往下,打印4
    总结:promise里面没有resolve()或reject(),promise会一直是pending状态,并且不会执行对应的.then()或者.catch()
例五:.then()的参数

new Promise((resolve,reject) =>{ resolve('start') }) .then(1) .then(Promise.resolve(2)) .then((res) =>{ console.log(res) })

结果:

start

分析:

  1. Promise的.then或者.catch的参数期望是函数,传入非函数则会发生值透传,所以.then(1)相当于.then((res) => Promise.resolve(res)),
  2. .then(Promise.resolve(2))相当于

.then((res) => { Promise.resolve(2) return Promise.resolve(res) })

  1. 最后的.then()打印start

总结:.then或者.catch的参数期望是函数,传入非函数则会发生值透传

将上面例子中再加入一行.then(console.log),打印结果又有所不同了

new Promise((resolve,reject) =>{ resolve('start') }) .then(1) .then(Promise.resolve(2)) .then(console.log) .then((res) =>{ console.log('res',res) })

结果:

start res undefined

分析:

  1. start是由第三个.then()打印的,
  2. .then(console.log)相当于

.then((res) =>{ console.log(res) return Promise.resolve(undefined) }) 例六:Promise的状态

const p = new Promise((resolve,reject) =>{ resolve('11') }) p.then(() =>{ console.log('then1',p) }) p.then(() =>{ console.log('then2',p) })

结果:

then1 Promise{<fulfilled>: '11'} then2 Promise{<fulfilled>: '11'}

分析:Promise的状态一经改变就不能再改变

例七:.catch()处理错误

new Promise((resolve,reject) =>{ resolve() }).then((res) =>{ throw new Error('throw error') },(err) =>{ console.log('err',err) }).catch((err) =>{ console.log('catch:',err) })

结果:

如何通过12个实例加固对promise的理解基础?

catch: Error: throw error

分析:对promise而言,处理错误可以给.then()方法传递第二个函数,但问题在于.then()中的第二个函数无法捕获第一个函数出现的错误。而用.catch()则能捕获到上层抛出的错误

例八:.catch()回调

new Promise((resolve,reject) =>{ reject() }).catch((err) =>{ return 'catch1 正常返回了' }).then((res) =>{ console.log('then1:',res) }).catch((err) =>{ console.log('catch2:',err) })

结果:

then1: catch1 正常返回了

分析:

  1. new Promise中 reject(),promise 状态由 pending 转为 rejected
  2. 执行.catch(),并return 'catch1 正常返回了',这里相当于 Promise.resolve('catch1 正常返回了')
  3. 执行.then(),打印 then1
    总结:.catch()回调正常返回,则返回值会传递给与之关联的promise

而在.catch()中抛出错误,则会被下一个.catch()捕获,如果没有再定义.catch()则错误会直接抛出

new Promise((resolve,reject) =>{ reject() }).catch((err) =>{ throw new Error('ee') }).then((res) =>{ console.log('then1:',res) }).catch((err) =>{ console.log('catch2:',err) })

结果:

catch2: Error: ee 例九

Promise.reject('start') .catch((res) =>{ console.log('catch1',res) return new Error('new error1') }).then((res) =>{ console.log('then1',res) return new Error('new error2') }).then((res) =>{ console.log('then2',res) }).catch((err) =>{ console.log('catch2',err) })

结果:

catch1 start then1 Error: new error1 then2 Error: new error2

分析:

  1. 从上往下执行start将会被.catch()捕获,并打印catch1 start
  2. 继续执行,.catch()返回一个promise包装的错误对象error1,注意这里是错误对象,会被当前一个对象来处理,而不是一个错误;相当于Promise.resolve(new Error('error1'));所以.catch()返回值会被紧接着的.then()方法接收到,并打印then1 Error: new error1
  3. 继续执行,.then()又返回了一个promise包装的错误对象error2,同样这里不会当成错误被最后的.catch()捕获,而是会被下一个.then()接收到,此时打印了then2 Error: new error2

总结:.then 或者 .catch 中 return 一个 error 对象并不会抛出错误,所以不会被后续的 .catch 捕获

例十

const p = new Promise((resolve,reject) =>{ resolve(11) }).then(() =>{ return p })

结果:

Uncaught (in promise) TypeError: Chaining cycle detected for promise #<Promise>

分析:.then().catch() 返回的值如果是 promise 本身,会造成死循环;就像无线回调,不停的往下注册、调用.then()

例十一

Promise.resolve('start') .finally((res1) =>{ console.log('finally',res1) return 'finally' }).then((res2) =>{ console.log('then',res2) }).finally(() =>{ throw new Error('error') }).catch((res3) =>{ console.log('catch',res3) })

结果:

finally undefined then start catch Error: error

分析:

  1. finally的回调函数接收不到promise的结果,所以res1返回的是undefined
  2. finally的返回值没有抛出错误的情况下默认是上一个promise的返回值,所以.then()方法接收的实际上是Promise.resolve('start')的返回值,打印的是start
  3. 然后.then()方法没有return任何值,此时会等同于Promise.resolve('undefined')
  4. 往下执行又碰到了finally,此时.finally()方法抛出了一个错误,会被下一个最近的.catch()方法捕获,所以res3打印了Error:error
例十二:串行promise

传入一个url组成的数组,按顺序执行数组中的url并返回结果,下面例子的fetchUrl函数为了测试可以设置setTimeout,而在实际开发中类似长这样:

function fetchUrl(url){ return fetch(url) .then((response) =>{ return response.text() }).then((val) =>{ arr.push(val) }) } promise实现

var urls = [1,2,3,4] function fetchAll(urls){ let arr = [] let p = Promise.resolve(undefined) function fetchUrl(url){ return new Promise((resolve,reject) =>{ setTimeout(() =>{ console.log(url) resolve(url*2) },1000) }) } for (let url of urls) { p = p.then((function(url){ return () => fetchUrl(url) })(url)).then((res) =>{ arr.push(res) }) } return p.then(() => arr) } fetchAll(urls).then((res) =>{ console.log(res) })

分析:

  1. fetchAll里面定义fetchUrl函数,该函数会去调用url对应的接口,返回值会用promise包装,并将返回值保存在arr
  2. 这里需要注意的是,如果在循环中写 p = p.then(() => fetchUrl(url)),那么这个url将会是数组中的最后一个url
  3. 因为要p.then()中的参数回调是一个异步任务,在循环时参数回调会被放入微任务队列,不会立即执行,导致不能绑定正确的url
  4. 所以在for of循环中 p.then()的参数回调需要用立即执行表达式绑定每个url(或者用forEach循环,forEach循环的内部会给每个元素执行一遍回调函数)
    结果:

1 2 3 4 [2, 4, 6, 8] async await 实现

var urls = [1,2,3,4] function fetchUrl(url){ return new Promise((resolve,reject) =>{ setTimeout(() =>{ console.log(url) resolve(url*2) },1000) }) } async function awaitFetch(urls) { let arr = [] for (let url of urls){ let p = await fetchUrl(url) arr.push(p) } console.log(arr) return arr } awaitFetch(urls)

分析:await 会等后面的fetch(url)返回的promise resolve()之后,才会执行后面的代码,在此之前,await阻塞之后的代码执行,所以这个for of循环相当于同步循环了
结果:

1 2 3 4 [2, 4, 6, 8] 生成器实现

var urls = [1,2,3,4] function fetchUrl(url){ return new Promise((resolve,reject) =>{ setTimeout(() =>{ console.log(url) resolve(url*2) },1000) }) } async function* fetchGen(urls){ for (let url of urls){ let p = await fetchUrl(url) yield p } } async function fetchAllByGen(urls) { let arr = [] for await(let p of fetchGen(urls)){ arr.push(p) } console.log(arr) return arr; } fetchAllByGen(urls)

分析:

  1. for of 循环专门用于可迭代对象,而生成器就是一个迭代器对象。fetchGen是一个异步生成器函数
  2. for await 循环中,每次循环会等待 fetchGen(url)返回结果,再往下执行 arr.push(p)的操作
  3. 为了测试,将fetchUrl函数中的 fetch api 改成了 setTimeout

结果:

1 2 3 4 [2, 4, 6, 8]

本文共计3170个文字,预计阅读时间需要13分钟。

如何通过12个实例加固对promise的理解基础?

在工作中常用到 promise, async, await,遇到问题需运用基础知识,总会有一部分记不得,便重新温习权限指南和 Es6 标准入门。花了几天时间啃完了这篇文章。喜欢的同学请动动手点赞。

工作中常常用到promise,async + await,遇到一些问题需要用到基础知识总会有一部分不记得,就重新温习权威指南和es6标准入门,花了几天肝下了这篇文章。喜欢的同学请动动发财手点个赞,文章有错误的地方还请指出。

例一

new Promise((resolve,reject) =>{ console.log('11') resolve() console.log('Promise') }) console.log('start')

结果:

11 Promise start

分析:

  1. Promise 新建后就会立即执行,从上往下执行,打印11
  2. 然后碰到resolve(),Promise状态由pending变为fulfilled
  3. 但调用resolvereject并不会终结 Promise 的参数函数的执行,所以会往下执行,打印出Promise
  4. 继续往下,打印出start
    总结:调用resolve或reject并不会终结 Promise 的参数函数的执行

再看一个代码类似的例子但执行过程却不一样

例二

new Promise((resolve, reject) => { return resolve(1); console.log(2); }).then((res) =>{ console.log('then',res) })

结果:

then 1

分析:

  1. Promise 新建后就会立即执行,碰到resolve(1),Promise状态由pending变为fulfilled
  2. 但这里加上了return,console.log(2)不会执行
  3. 执行.then(),打印出 then 1
    结果:Promise参数函数中加上return,后面的语句不会执行了,2不会被打印。.then().catch()中也是一样。

猜猜下面的执行会是什么

new Promise((resolve, reject) => { resolve(1); }).then((res) =>{ return 2; console.log('then1',res) }).then((res) =>{ console.log('then2',res) throw new Error('error') }).catch((err) =>{ return 'catch返回值' console.log('catch',err) }).then((res) =>{ console.log('then3',res) })

结果:

then2 2 then3 catch返回值

分析:

  1. new Promise立即执行,resolve(1)1作为返回值传给.then()
  2. 执行.then(),遇到 return 2,相当于return Promise.resolve(2),由于加了return,后面的 then1不会被打印
  3. 执行第二个.then(),打印 then2 2,然后抛出一个错误,相当于执行了 return Promise.reject('error')
  4. 往下执行,.catch()捕获到了错误,并 return 'catch返回值',相当于return Promise.resolve('catch返回值'),同样下面的 cosnole.log('catch',err)不会执行
  5. 最后的.then()会接收到上面的返回值,并打印 then3 catch返回值
例三

Promise.resolve('start') .then((res) =>{ console.log('then1',res) return 11 //相当于 return Promise.resolve(11) }).then((res) =>{ console.log('then2',res) //相当于 return Promise.resolve(undefined) }).then((res) =>{ console.log('then3',res) throw new Error('then3 error') //相当于 return Promise.reject(new Error('then3 error')) }).catch((res) =>{ console.log('catch',res) })

结果:

then1 start then2 11 then3 undefined catch Error: then3 error

分析:在Promise中,返回任意一个非 promise 的值都会被包裹成promise对象

例四

const promise = new Promise((resolve, reject) => { console.log(1); console.log(2); }); promise.then(() => { console.log(3); }); console.log(4);

结果:

1 2 4

分析:

  1. new Promise立即执行,打印 12,
  2. 遇到promise.then(),由于Promise中没有resolve()或者reject(),所以promise的状态会一直是pending,promise.then()方法不会执行,3 不会被打印,
  3. 继续往下,打印4
    总结:promise里面没有resolve()或reject(),promise会一直是pending状态,并且不会执行对应的.then()或者.catch()
例五:.then()的参数

new Promise((resolve,reject) =>{ resolve('start') }) .then(1) .then(Promise.resolve(2)) .then((res) =>{ console.log(res) })

结果:

start

分析:

  1. Promise的.then或者.catch的参数期望是函数,传入非函数则会发生值透传,所以.then(1)相当于.then((res) => Promise.resolve(res)),
  2. .then(Promise.resolve(2))相当于

.then((res) => { Promise.resolve(2) return Promise.resolve(res) })

  1. 最后的.then()打印start

总结:.then或者.catch的参数期望是函数,传入非函数则会发生值透传

将上面例子中再加入一行.then(console.log),打印结果又有所不同了

new Promise((resolve,reject) =>{ resolve('start') }) .then(1) .then(Promise.resolve(2)) .then(console.log) .then((res) =>{ console.log('res',res) })

结果:

start res undefined

分析:

  1. start是由第三个.then()打印的,
  2. .then(console.log)相当于

.then((res) =>{ console.log(res) return Promise.resolve(undefined) }) 例六:Promise的状态

const p = new Promise((resolve,reject) =>{ resolve('11') }) p.then(() =>{ console.log('then1',p) }) p.then(() =>{ console.log('then2',p) })

结果:

then1 Promise{<fulfilled>: '11'} then2 Promise{<fulfilled>: '11'}

分析:Promise的状态一经改变就不能再改变

例七:.catch()处理错误

new Promise((resolve,reject) =>{ resolve() }).then((res) =>{ throw new Error('throw error') },(err) =>{ console.log('err',err) }).catch((err) =>{ console.log('catch:',err) })

结果:

如何通过12个实例加固对promise的理解基础?

catch: Error: throw error

分析:对promise而言,处理错误可以给.then()方法传递第二个函数,但问题在于.then()中的第二个函数无法捕获第一个函数出现的错误。而用.catch()则能捕获到上层抛出的错误

例八:.catch()回调

new Promise((resolve,reject) =>{ reject() }).catch((err) =>{ return 'catch1 正常返回了' }).then((res) =>{ console.log('then1:',res) }).catch((err) =>{ console.log('catch2:',err) })

结果:

then1: catch1 正常返回了

分析:

  1. new Promise中 reject(),promise 状态由 pending 转为 rejected
  2. 执行.catch(),并return 'catch1 正常返回了',这里相当于 Promise.resolve('catch1 正常返回了')
  3. 执行.then(),打印 then1
    总结:.catch()回调正常返回,则返回值会传递给与之关联的promise

而在.catch()中抛出错误,则会被下一个.catch()捕获,如果没有再定义.catch()则错误会直接抛出

new Promise((resolve,reject) =>{ reject() }).catch((err) =>{ throw new Error('ee') }).then((res) =>{ console.log('then1:',res) }).catch((err) =>{ console.log('catch2:',err) })

结果:

catch2: Error: ee 例九

Promise.reject('start') .catch((res) =>{ console.log('catch1',res) return new Error('new error1') }).then((res) =>{ console.log('then1',res) return new Error('new error2') }).then((res) =>{ console.log('then2',res) }).catch((err) =>{ console.log('catch2',err) })

结果:

catch1 start then1 Error: new error1 then2 Error: new error2

分析:

  1. 从上往下执行start将会被.catch()捕获,并打印catch1 start
  2. 继续执行,.catch()返回一个promise包装的错误对象error1,注意这里是错误对象,会被当前一个对象来处理,而不是一个错误;相当于Promise.resolve(new Error('error1'));所以.catch()返回值会被紧接着的.then()方法接收到,并打印then1 Error: new error1
  3. 继续执行,.then()又返回了一个promise包装的错误对象error2,同样这里不会当成错误被最后的.catch()捕获,而是会被下一个.then()接收到,此时打印了then2 Error: new error2

总结:.then 或者 .catch 中 return 一个 error 对象并不会抛出错误,所以不会被后续的 .catch 捕获

例十

const p = new Promise((resolve,reject) =>{ resolve(11) }).then(() =>{ return p })

结果:

Uncaught (in promise) TypeError: Chaining cycle detected for promise #<Promise>

分析:.then().catch() 返回的值如果是 promise 本身,会造成死循环;就像无线回调,不停的往下注册、调用.then()

例十一

Promise.resolve('start') .finally((res1) =>{ console.log('finally',res1) return 'finally' }).then((res2) =>{ console.log('then',res2) }).finally(() =>{ throw new Error('error') }).catch((res3) =>{ console.log('catch',res3) })

结果:

finally undefined then start catch Error: error

分析:

  1. finally的回调函数接收不到promise的结果,所以res1返回的是undefined
  2. finally的返回值没有抛出错误的情况下默认是上一个promise的返回值,所以.then()方法接收的实际上是Promise.resolve('start')的返回值,打印的是start
  3. 然后.then()方法没有return任何值,此时会等同于Promise.resolve('undefined')
  4. 往下执行又碰到了finally,此时.finally()方法抛出了一个错误,会被下一个最近的.catch()方法捕获,所以res3打印了Error:error
例十二:串行promise

传入一个url组成的数组,按顺序执行数组中的url并返回结果,下面例子的fetchUrl函数为了测试可以设置setTimeout,而在实际开发中类似长这样:

function fetchUrl(url){ return fetch(url) .then((response) =>{ return response.text() }).then((val) =>{ arr.push(val) }) } promise实现

var urls = [1,2,3,4] function fetchAll(urls){ let arr = [] let p = Promise.resolve(undefined) function fetchUrl(url){ return new Promise((resolve,reject) =>{ setTimeout(() =>{ console.log(url) resolve(url*2) },1000) }) } for (let url of urls) { p = p.then((function(url){ return () => fetchUrl(url) })(url)).then((res) =>{ arr.push(res) }) } return p.then(() => arr) } fetchAll(urls).then((res) =>{ console.log(res) })

分析:

  1. fetchAll里面定义fetchUrl函数,该函数会去调用url对应的接口,返回值会用promise包装,并将返回值保存在arr
  2. 这里需要注意的是,如果在循环中写 p = p.then(() => fetchUrl(url)),那么这个url将会是数组中的最后一个url
  3. 因为要p.then()中的参数回调是一个异步任务,在循环时参数回调会被放入微任务队列,不会立即执行,导致不能绑定正确的url
  4. 所以在for of循环中 p.then()的参数回调需要用立即执行表达式绑定每个url(或者用forEach循环,forEach循环的内部会给每个元素执行一遍回调函数)
    结果:

1 2 3 4 [2, 4, 6, 8] async await 实现

var urls = [1,2,3,4] function fetchUrl(url){ return new Promise((resolve,reject) =>{ setTimeout(() =>{ console.log(url) resolve(url*2) },1000) }) } async function awaitFetch(urls) { let arr = [] for (let url of urls){ let p = await fetchUrl(url) arr.push(p) } console.log(arr) return arr } awaitFetch(urls)

分析:await 会等后面的fetch(url)返回的promise resolve()之后,才会执行后面的代码,在此之前,await阻塞之后的代码执行,所以这个for of循环相当于同步循环了
结果:

1 2 3 4 [2, 4, 6, 8] 生成器实现

var urls = [1,2,3,4] function fetchUrl(url){ return new Promise((resolve,reject) =>{ setTimeout(() =>{ console.log(url) resolve(url*2) },1000) }) } async function* fetchGen(urls){ for (let url of urls){ let p = await fetchUrl(url) yield p } } async function fetchAllByGen(urls) { let arr = [] for await(let p of fetchGen(urls)){ arr.push(p) } console.log(arr) return arr; } fetchAllByGen(urls)

分析:

  1. for of 循环专门用于可迭代对象,而生成器就是一个迭代器对象。fetchGen是一个异步生成器函数
  2. for await 循环中,每次循环会等待 fetchGen(url)返回结果,再往下执行 arr.push(p)的操作
  3. 为了测试,将fetchUrl函数中的 fetch api 改成了 setTimeout

结果:

1 2 3 4 [2, 4, 6, 8]