【JavaScript】Promise(二) —— 几个关键问题

简介: 【JavaScript】Promise(二) —— 几个关键问题

一、几个关键问题

1. 如何改变一个 Promise 实例的状态

执行 resolve(value):如果当前是 pending 就会变为 fulfilled。

执行 reject(reason):如果当前是 pending 就会变为 rejected。

执行器函数 (executor) 抛出异常:如果当前是 pending 就会变为 rejected。

引擎抛异常:

  const p = new Promise((resolve, reject)=>{
        console.log(a); //引擎抛异常
    })
    p.then(
        value => {console.log('成功了', value);},
        reason => {console.log('失败了', reason);}
    )

00be034c6c214bba990533d49a561d67.png

编码抛异常:

  const p = new Promise((resolve, reject)=>{
        throw -100  //编码抛异常
    })
    p.then(
        value => {console.log('成功了', value);},
        reason => {console.log('失败了', reason);}
    )

1f087e0b468940419d7f5a853add4f4e.png

2. 改变 Promise 实例的状态和指定回调函数谁先谁后?
  1. 如果先指定的回调,那当状态发生改变时,回调函数就会调用,得到数据。
  2. 如果先改变的状态,那当指定回调时,回调函数就会调用,得到数据。

先指定回调,后改变状态:

    const p = new Promise((resolve, reject)=>{
        setTimeout(()=>{
            resolve(100)
        }, 1000)
    })
    p.then(
        value => {console.log('成功了', value);},
        reason => {console.log('失败了', reason);}
    )

a2936bec4b1042f8a13d8c9b18a93e01.png

先改状态,后指定回调:

    const p = new Promise((resolve, reject)=>{
        resolve('a')
    })
    setTimeout(()=>{
        p.then(
            value => {console.log('成功了', value);},
            reason => {console.log('失败了', reason);}
        )
    }, 1000)

3a2f65a22f054caa92d18658c77bb7c8.png

3. Promise实例.then返回的是一个【新的Promise实例】,它的值和状态由什么决定?

简单表达:由 then 所指定的回调函数执行的结果决定。

详细表达:

(1)如果 then 所指定的回调返回的是非 Promise 值 a,那么【新Promise实例】状态为:成功(fulfilled),成功的 value 为 a。

(2)如果 then 所指定的回调返回的是一个 Promise 实例 p,那么【新Promise实例】的状态、值,都与 p 一致。

(3)如果then所指定的回调抛出异常:那么【新Promise实例】状态为 rejected,reason 为抛出的那个异常。

  const p = new Promise((resolve, reject)=>{
        setTimeout(()=>{
            resolve('a')
        }, 1000)
    })
    const x = p.then(
        value => {console.log('成功了1', value); return 900},
        reason => {console.log('失败了1', reason);}
    )
    x.then(
        value => {console.log('成功了2', value);},
        reason => {console.log('失败了2', reason);}
    )

20a453837ec5416cb8b2651389c95c1d.png

then的链式调用:

  const p = new Promise((resolve, reject)=>{
        setTimeout(()=>{
            resolve('a')
        }, 1000)
    })
    p.then(
        value => {console.log('成功了1', value); return Promise.reject('b')},
        reason => {console.log('失败了1', reason);}
    ).then(
        value => {console.log('成功了2', value); return true},
        reason => {console.log('失败了2', reason); return 100}
    ).then(
        value => {console.log('成功了3', value); throw 900},
        reason => {console.log('失败了3', reason); return false}
    ).then(
        value => {console.log('成功了4', value); return 200},
        reason => {console.log('失败了4', reason);}
    )

9bd874b48743415ea22543b516d35c68.png

4. Promise如何串连多个异步任务?

通过 then 的链式调用

实例:发送三次请求,每次请求成功后再发下一次请求。

  // 封装ajax请求
    function sendAjax(url) {
        return new Promise((resolve, reject) => {
            // 实例xhr
            const xhr = new XMLHttpRequest()
            // 绑定监听
            xhr.onreadystatechange = () => {
                if (xhr.readyState === 4) {
                    if (xhr.status >= 200 && xhr.status < 300) {
                        resolve(xhr.response);
                    } else {
                        reject('请求出了点问题');
                    }
                }
            }
            xhr.open('GET', url)
            xhr.responseType = 'json'
            xhr.send()
        })
    }
  // 发送第1次请求
  sendAjax('https://api.apiopen.top/api/sentences')
    .then(
        value => {
            console.log('第1次请求成功了', value);
            return sendAjax('https://api.apiopen.top/api/sentences')
        },
        reason => {
            console.log('第1次请求失败了', reason);
        }
    )
    .then(
        value => {
            console.log('第2次请求成功了', value);
            return sendAjax('https://api.apiopen.top/api/sentences')
        },
        reason => {
            console.log('第2次请求失败了', reason);
        }
    )
    .then(
        value => {
            console.log('第3次请求成功了', value);
        },
        reason => {
            console.log('第3次请求失败了', reason);
        }
    )

then的链式调用,依次请求成功:

09aa37cab7e04febad89697698394e9c.png

5. 中断 promise 链

当使用 promise 的 then 链式调用时,在中间中断,不再调用后面的回调函数。

办法:在失败的回调函数中返回一个 pendding 状态的 Promise 实例。

在失败的回调中返回 pendding 状态的 Promise 实例

  return new Promise(() => {})

实例:

  // 封装ajax请求
  function sendAjax(url) {
      return new Promise((resolve, reject) => {
          // 实例xhr
          const xhr = new XMLHttpRequest()
          // 绑定监听
          xhr.onreadystatechange = () => {
              if (xhr.readyState === 4) {
                  if (xhr.status >= 200 && xhr.status < 300) {
                      resolve(xhr.response);
                  } else {
                      reject('请求出了点问题');
                  }
              }
          }
          xhr.open('GET', url)
          xhr.responseType = 'json'
          xhr.send()
      })
  }
  // 发送第1次请求
  sendAjax('https://api.apiopen.top/api/sentences')
    .then(
        value => {
            console.log('第1次请求成功了', value);
            return sendAjax('https://api.apiopen.top/api/sentences2')
        },
        reason => {
            console.log('第1次请求失败了', reason);
            return new Promise(() => {})
        }
    )
    .then(
        value => {
            console.log('第2次请求成功了', value);
            return sendAjax('https://api.apiopen.top/api/sentences')
        },
        reason => {
            console.log('第2次请求失败了', reason);
            return new Promise(() => {})
        }
    )
    .then(
        value => {console.log('第3次请求成功了', value);},
        reason => {
            console.log('第3次请求失败了', reason);
            return new Promise(() => {})
        }
    )

e9b20f6bddd944e987b476c710cb86e2.png

6. promise 的错误穿透
  1. 当使用 promise 的 then 链式调用时,可以在最后用 catch 指定一个失败的回调
  2. 前面任何操作出了错误,都会传到最后失败的回调中处理了
  3. 如果不存在 then 的链式调用,就不需要考虑 then 的错误穿透

使用定时器:

  const p = new Promise((resolve, reject)=>{
        setTimeout(()=>{
            reject(-1)
        }, 500)
    })
    p.then(
        value => {console.log('成功了1', value);}
    )
    .then(
        value => {console.log('成功了2', value);}
    )
    .catch(
        reason => {console.log('失败了', reason);}
    )

5e78a1686ce94d74b8c3146b763e039b.png

发送 Ajax 请求:

    // 封装ajax请求
    function sendAjax(url, index) {
        return new Promise((resolve, reject) => {
            // 实例xhr
            const xhr = new XMLHttpRequest()
            // 绑定监听
            xhr.onreadystatechange = () => {
                if (xhr.readyState === 4) {
                    if (xhr.status >= 200 && xhr.status < 300) {
                        resolve(xhr.response);
                    } else {
                        reject(`第${index}次请求出了点问题`);
                    }
                }
            }
            xhr.open('GET', url)
            xhr.responseType = 'json'
            xhr.send()
        })
    }
  sendAjax('https://api.apiopen.top/api/sentences', 1)
        .then(
            value => {
                console.log('第1次请求成功了', value);
                return sendAjax('https://api.apiopen.top/api/sentences2', 2)
            },
        )
        .then(
            value => {
                console.log('第2次请求成功了', value);
                return sendAjax('https://api.apiopen.top/api/sentences', 3)
            },
        )
        .then(
            value => {
                console.log('第3次请求成功了', value);
            },
        )
        .catch(
            reason => {
                console.log('失败了', reason);
            }
        )

c6389315cf9d48619b76e69320ddf8e1.png

不积跬步无以至千里,不积小流无以成江海

相关文章
|
4月前
|
前端开发 JavaScript API
JavaScript异步编程:从Promise到async/await
JavaScript异步编程:从Promise到async/await
506 204
|
2月前
|
前端开发 JavaScript API
js实现promise常用场景使用示例
本文介绍JavaScript中Promise的6种常用场景:异步请求、定时器封装、并行执行、竞速操作、任务队列及与async/await结合使用,通过实用示例展示如何优雅处理异步逻辑,避免回调地狱,提升代码可读性与维护性。
251 10
|
前端开发 JavaScript
用JavaScript 实现一个简单的 Promise 并打印结果
用 JavaScript 实现一个简单的 Promise 并打印结果
|
JSON 前端开发 JavaScript
在 JavaScript 中,如何使用 Promise 处理异步操作?
通过以上方式,可以使用Promise来有效地处理各种异步操作,使异步代码更加清晰、易读和易于维护,避免了回调地狱的问题,提高了代码的质量和可维护性。
|
前端开发 JavaScript Java
一文带你了解和使用js中的Promise
欢迎来到我的博客,我是瑞雨溪,一名热爱JavaScript和Vue的大一学生。自学前端2年半,正向全栈进发。如果我的文章对你有帮助,请关注我,将持续更新更多优质内容!🎉🎉🎉
682 0
一文带你了解和使用js中的Promise
|
JSON 前端开发 JavaScript
浅谈JavaScript中的Promise、Async和Await
【10月更文挑战第30天】Promise、Async和Await是JavaScript中强大的异步编程工具,它们各自具有独特的优势和适用场景,开发者可以根据具体的项目需求和代码风格选择合适的方式来处理异步操作,从而编写出更加高效、可读和易于维护的JavaScript代码。
337 1
|
前端开发 JavaScript 开发者
JavaScript 中的异步编程:深入了解 Promise 和 async/await
【10月更文挑战第8天】JavaScript 中的异步编程:深入了解 Promise 和 async/await
|
前端开发 JavaScript 小程序
JavaScript的ES6中Promise的使用以及个人理解
JavaScript的ES6中Promise的使用以及个人理解
179 1
|
前端开发 JavaScript
JavaScript中的Promise:简化异步编程
JavaScript中的Promise:简化异步编程