【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

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

相关文章
|
20天前
|
前端开发 JavaScript
如何处理 JavaScript 中的异步操作和 Promise?
如何处理 JavaScript 中的异步操作和 Promise?
16 1
|
20天前
|
前端开发 JavaScript
在JavaScript中,什么是promise、怎么使用promise、怎么手写promise
在JavaScript中,什么是promise、怎么使用promise、怎么手写promise
31 4
|
20天前
|
前端开发 JavaScript 开发者
JavaScript 中的异步编程:Promise 和 Async/Await
在现代的 JavaScript 开发中,异步编程是至关重要的。本文将介绍 JavaScript 中的异步编程概念,重点讨论 Promise 和 Async/Await 这两种常见的处理异步操作的方法。通过本文的阐述,读者将能够更好地理解和应用这些技术,提高自己在 JavaScript 开发中处理异步任务的能力。
|
20天前
|
JSON 前端开发 JavaScript
【JavaScript技术专栏】JavaScript异步编程:Promise、async/await解析
【4月更文挑战第30天】JavaScript中的异步编程通过Promise和async/await来解决回调地狱问题。Promise代表可能完成或拒绝的异步操作,有pending、fulfilled和rejected三种状态。它支持链式调用和Promise.all()、Promise.race()等方法。async/await是ES8引入的语法糖,允许异步代码以同步风格编写,提高可读性和可维护性。两者结合使用能更高效地处理非阻塞操作。
|
18天前
|
前端开发 JavaScript
前端 js 经典:Promise
前端 js 经典:Promise
21 1
|
20天前
|
前端开发 JavaScript
在JavaScript中,回调函数、Promise和async/await这三种异步处理机制的优缺点
JavaScript的异步处理包括回调函数、Promise和async/await。回调函数简单易懂,但可能导致回调地狱和错误处理困难。Promise通过链式调用改善了这一情况,但仍有回调函数需求和学习成本。async/await提供同步风格代码,增强可读性和错误处理,但需ES8支持,不适用于并发执行。根据项目需求选择合适机制。
|
20天前
|
前端开发 JavaScript
js开发:请解释Promise是什么,以及它如何解决回调地狱(callback hell)问题。
Promise是JavaScript解决异步操作回调地狱的工具,代表未来可能完成的值。传统的回调函数嵌套导致代码难以维护,而Promise通过链式调用`.then()`和`.catch()`使异步流程清晰扁平。每个异步操作封装为Promise,成功时`.then()`传递结果,出错时`.catch()`捕获异常。ES6的`async/await`进一步简化Promise的使用,使异步代码更接近同步风格。
27 1
|
20天前
|
前端开发 JavaScript API
JavaScript学习笔记(一)promise与async
JavaScript学习笔记(一)promise与async
|
20天前
|
前端开发 JavaScript UED
JavaScript中的异步编程和Promise
【2月更文挑战第3天】在Web开发中,JavaScript是一门非常重要的编程语言,而异步编程是JavaScript中的一个关键概念。本文将介绍JavaScript中的异步编程特点,以及如何使用Promise来更加优雅地处理异步操作,帮助开发者更好地理解和应用这一技术。
20 3
|
20天前
|
前端开发 JavaScript 数据处理
JavaScript中的异步编程及Promise对象
【2月更文挑战第3天】 传统的JavaScript编程模式在处理异步任务时常常会导致回调地狱和代码可读性较差的问题,而Promise对象的引入为解决这一问题提供了一种优雅的解决方案。本文将介绍JavaScript中的异步编程方式以及Promise对象的使用方法和优势,帮助读者更好地理解和运用异步编程技术。
23 8