1 p r o m i s e 规 范 及 应 用 . P r o m i s e s /A /A + . 传 统 异 步 任 务 的 处 理 . P r o m i s e 介 绍 . 手 写 P r o m i s e 的 实 现 . a s y n c 和 a w a i t . P r o m i s e 相 关 面 试 题 目 讲解 . 作 业 . 代 码 输 出 结 果 . 代 码 输 出 结 果 . 代 码 输 出 结 果 . 代 码 输 出 结 果 . 代 码 输 出 结 果 . 代 码 输 出 结 果 . 代 码 输 出 结 果 . 代 码 输 出 结 果 本 节 课 程 需随 堂 手 写 代 码 , 请 务 必 准 备好 代 码 环 境 p r o m i s e 相 关 代 码 分 析 的 面 试 题 , 通 常 与 j s 的 事件 循 环 结 合 , 请 提 前 预 习 js 中 的 e v e n t L o o p ( 宏 任 务 与 微 任 务 ) 1 . P r o m i s e s /A +
2 1 . 状 态 P r o m i s e 必 须 从 p e n d i n g 转 位 f u l f i l l e d 或 r e j e c t e d , 且 一 旦 转 换 后 状 态 和 值 ( 或 原 因 ) 不 能 改 变 例 如 , 一 个 异 步 操 作 , 在 成 功 时 调 用 r e s o v e 并 传 入 数据 , 在 出 错 的 时 候 调 用 r e j e c t 并 传 入 错 误 原 因 2. t h e n 方 法 t h e n 接收 两个 回 调 , 分别 用 于 处 理 成 功 和 失 败 如 果 回 调 返 回 值 , 则 将 值 传 递 给 下 一 个 the n ; 如 果 抛 出 异常 , 则 下 一 个 t h e n 会 接收 到 拒 绝 原 因 3. P r o m i s e 解 析 过 程 如 果 一 个 then 回 调 返 回 了 另 一 个 P r o m i s e , 那 么 当 前 P r o m i s e 就 会 “ 跟 随 ” 这 个 返 回 的 p r o m i s e 状 态 ● ● ● ● ● 2 . 传 统 异 步 任 务 的 处 理 let promise1
new Promise ( ( resolve ) => setTimeout ( ( ) => resolve ( 10 ) , 1000 ) ; let promise2
Promise . resolved ( promise1 ) //promise2 会 在 promise1 fulfilled 时 , 自 动 以 同 样 的 值 fulfilled let thenable
{ then : function ( resolve , reject ) { setTimeout ( ( ) => resolve ( 'success' ) , 1000 ) } } let promise
Promise . resolve ( thenable ) // promise 最 终 fulfilled, 值 为 success 1 2 3 4 5 6 7 8 9 10 11 12 13 J a v a S c r i p t someAsyncOperation ( ) . then ( value => { console . log ( ' 成 功 ' , value ) ; return value + 1 } ) . then ( value => { console . log ( ' 链 式 调 用 成 功 ' , value ) } ) . catch ( error => { console . error ( ' 错 误 ' , error ) } ) 1 2 3 4 5 6 7 8 J a v a S c r i p t
3 回 调 函 数 一 个 简 单 的的 需 求 调 用 一 个 函 数 , 这 个 函 数 中 返 回 网 络 请 求 发 送 网 络 请 求 成 功 , 就 告 知 调 用 者 成 功 , 并 返 回 数据 发 送 网 络 请 求 失 败 , 就 告 知 调 用 者 失 败 , 并 返 回 失 败 信 息 回 调 地 狱 如 果是 自 己 封 装 的 请 求 方 法 , 必 须 设计 好 规 范 , 如 果 使 用 他 人 库 , 则 必 须 要 通过 查 看 文 档 或 源 码 才 能 知 道 如 何使 用 这 个 函 数 及 其 容 易 出 现 回 调 地 狱 ● ○ ■ ■ ■ ● ○ ○ 3 . P r o m i s e 介 绍 function request ( cb ) { // 模 拟 网 络 请 求 let flag
Math . random ( ) <= 0.5 ? true : false ; setTimeout ( ( ) => { cb ( flag , flag ? ' 成 功 的 数据 ' : ' 失 败 的 数据 ' ) ; } , 1000 ) ; } console . log ( ' 发 起 请 求 ' ) ; request ( ( status , msg ) => { console . log ( status , msg ) ; } ) request ( ( s1 , m1 ) => { // 业 务 处 理 逻辑 1 request ( ( s2 , m2 ) => { // 业 务 处 理 逻辑 2 request ( ( s3 , m3 ) => { // 业 务 处 理 逻辑 3 console . log ( s3 , m3 ) ; } ) } ) } ) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 J a v a S c r i p t
4 什么 是 P r o m i s e 是 一 个 类 当 通过 n e w 创 建 P r o m i s e 实 例 , 需 要 传 入 一 个 回 调 函 数 , 我 们 称 之为 e x e c u t o r 这 个 回 调 函 数 会 被 立 即 执 行 , 并 传 入 两个 回 调 函 数 的 参 数 (r e s o l v e , r e j e c t ) 当 调 用 r e s o l v e 回 调 函 数 时 , 会 执 行 P r o m i s e 对 象 的 t h e n 方 法 传 入 的 回 调 当 调 用 r e j e c t 回 调 函 数 时 , 会 执 行 P r o m i s e 对 象 的 c a t c h 方 法 传 入 的 回 调 P r o m i s e 是 一 个 状 态 机 , 分 为 3 种 状 态 p e n d i n g : 待 定 状 态 , 执 行 了 exec u t o r 后 , 处 于 该 状 态 f u l f i l l e d : 兑 现 状 态 , 调 用 r e s o l v e ( ) 后 , P r o m i s e 的 状 态 更 改 为 f u l l f i l l e d , 且 无 法 再 次 更 改 r e j e c t e d : 拒 绝 状 态 , 调 用 r e j e c t ( ) 后 , P r o m i s e 的 状 态 更 改 为 r e j e c t e d ,且 无 法 再 次 更 改 r e s o l v e 的 参 数 如 果 传 入 的 是普 通 的 值 或 者 对 象 , 则 会传 递 到 the n 的 参 数 中 如 果 传 入 的 是 一 个 P r o m i s e , 那 么 当 前 的 P r o m i s e 状 态 会 由 传 入 的 P r o m i s e 决 定 ● ○ ○ ■ ■ ■ ○ ■ ■ ■ ● ○ ○ function request ( cb ) { // 模 拟 网 络 请 求 let flag
Math . random ( ) <= 0.5 ? true : false ; return new Promise ( ( resolve , reject ) => { setTimeout ( ( ) => { if ( flag ) { resolve ( ' 成 功 的 消 息 ' ) ; return } reject ( ' 失 败 的 消 息 ' ) } , 2000 ) } ) } console . log ( ' 请 求 开 始 ' ) request ( ) . then ( msg => console . log ( msg ) , err => console . log ( err ) ) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 J a v a S c r i p t
5 如 果 传 入 的 是 一 个 对 象 , 并 且 该 对 象 实 现 了 the n 方 法 ( t h e n a b l e ) , 也会 执 行 该 t h e n 方 法 , 并 且 由 该 t h e n 方 法 决 定 后 续 的 状 态 P r o m i s e 的 实 例 方 法 t h e n 方 法 通过 t h e n 方 法 可 以 对 P r o m i s e 种 的 r e s o l v e 进 行 处 理 , t h e n 方 法 的 返 回 值 是 一 个 Pr o m i s e 实 例 多 次 调 用 then 方 法 同 一 个 P r o m i s e 实 例 可 以 调 用 多 个 then 方 法 , 当 P r o m i s e 种 r e s o l v e 被 回 调 时 , 所 有 t h e n 方 法 传 入 的 回 调 函 数 都 会 被调 用 ○ ● ○ ○ const newPromise
new Promise ( ( resolve , reject ) => { resolve ( 'success' ) } ) new Promise ( ( resolve , reject ) => { // 当 前 Promise 的 状 态 由 传 入 的 Promise 决 定 resolve ( newPromise ) } ) . then ( res => { console . log ( 'res' , res ) } ) . catch ( err => { console . log ( 'err' , err ) } ) 1 2 3 4 5 6 7 8 9 10 11 J a v a S c r i p t new Promise ( ( resolve , reject ) => { // 如 果 resolve 传 入 的 是 对 象 ,且 该 对 象 实 现 了 then 方 法 // 则 该 Promise 的 状 态 由 then 方 法 决 定 resolve ( { then ( resolve , reject ) { reject ( 'error' ) } } ) } ) . then ( res => { console . log ( 'res' , res ) } ) . catch ( err => { console . log ( 'err' , err ) } ) 1 2 3 4 5 6 7 8 9 10 11 12 13 J a v a S c r i p t
6 t h e n 方 法 传 入 的 回 调 函 数 可 以 有 返 回 值 如 果 返 回 的 是普 通 值 , 那 么 这 个 普 通 值 作为 一 个 新 的 Pr o m i s e 的 r e s o l v e 值 如 果 返 回 的 是 P r o m i s e , 那 么 就 可 以 再 次 调 用 t h e n 方 法 如 果 返 回 的 是 一 个 对 象 , 并 且 该 对 象 实 现 了 the n a b l e , 该 t h e n 函 数 由 两个 参 数 r e s o l v e , r e j e c t , 则 r e s o l v e 会传 递 给 下 一 个 P r o m i s e c a t c h 方 法 ○ ○ const promise
new Promise ( resolve => { resolve ( ' 你 好 ' ) } ) // 同 时 调 用 promise . then ( res => console . log ( res ) ) promise . then ( res => console . log ( res ) ) promise . then ( res => console . log ( res ) ) 1 2 3 4 5 6 7 J a v a S c r i p t const promise
new Promise ( resolve => { resolve ( ' 你 好 ' ) } ) promise . then ( ( ) => 'then' ) . then ( res => console . log ( res ) ) // 打 印 then // promise.then(() => 'then') 等 价于 promise . then ( ( ) => { return new Promise ( resolve => { resolve ( 'then' ) } ) } ) 1 2 3 4 5 6 7 8 9 J a v a S c r i p t const promise
new Promise ( resolve => { resolve ( ' 你 好 ' ) } ) promise . then ( ( ) => { return { then ( resolve ) { return resolve ( 'success' ) } } } ) . then ( msg => console . log ( msg ) ) 1 2 3 4 5 6 7 8 9 10 11 J a v a S c r i p t
7 除 了 t h e n 方 法 的 第 二 个 参 数 来 捕 获 r e j e c t 错 误 之 外 , 我 们 还 可 以 通过 c a t c h 方 法 , c a t c h 返 回 一 个 P r o m i s e c a t c h 方 法 也 是 可 以 多 次 调 用 的 , 只 要 Pr o m i s e 实 例 的 状 态 是 r e j e c t e d , 那 么 就 会 调 用 c a t c h 方 法 f i n a l l y 方 法 无 论 一 个 P r o m i s e 实 例 是 f u l l f i l l e d 或 r e j e c t e d , f i n a l l y 都 会 执 行 , f i n a l l y 不 接 受 任何 参 数 P r o m i s e 的 类 方 法 r e s o l v e 方 法 ○ ● ○ const promise
new Promise ( ( resolve , reject ) => { reject ( 'error' ) } ) promise . then ( undefined , err => { // 打 印 err console . log ( err ) } ) // 这 种 写 法 不 太 符 合 'promise/a+ 规 范 ' promise . catch ( err => { // 打 印 err console . log ( err ) } ) // 符 合 规 范 的 写 法 promise . then ( ( ) => { } ) . catch ( err => { console . log ( err ) } ) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 J a v a S c r i p t const promise
new Promise ( ( resolve , reject ) => { reject ( 'error' ) } ) promise . then ( ( ) => { } ) . catch ( err => { console . log ( err ) } ) . finally ( ( ) => { console . log ( 'finally code execute' ) } ) 1 2 3 4 5 6 7 8 J a v a S c r i p t
8 r e s o l v e 参 数 : 参 数 本 身 是 P r o m i s e 参 数 是 原 始 值 / 对 象 参 数 是 一 个 then a b l e r e j e c t 方 法 a l l 方 法 a l l 方 法 P r o m i s e . a l l ( ) 接收 一 个 P r o m i s e [ ] , 返 回 一 个 P r o m i s e 实 例 , 当 所 有 的 P r o m i s e 执 行 完 毕 且 都 是 f u l l f i l l e d 状 态 时 , 该 实 例 的 状 态 才 会 变 成 fullfille d , 只 要 队 列 中 有 一 个 实 例 的 状 态 是 r e j e c t e d , 那 么 该 实 例 的 状 态 也会 变 成 r e j e c t e 如 果 P r o m i s e 队 列 中 所 有 的 实 例 状 态 都 是 f u l l f i l l e d , 那 么 P r o m i s e . a l l ( ) 返 回 的 是 实 例 状 态 就 会 变 成 f u l l f i l l e d , 并 且 t h e n ( ) 的 参 数 是 一 个 数 组 , 按 照 顺 序 防 止 的 队 列 中 每 个 Pr o m i s e 成 功 后 的 结 果 ○ ○ ○ ○ ○ ○ const foo
{ name : 'alex' } function bar ( obj ) { return new Promise ( resolve => { resolve ( obj ) } ) } bar ( boo ) . then ( res => { console . log ( res ) } ) 1 2 3 4 5 6 7 8 9 10 11 12 J a v a S c r i p t function bar ( obj ) { return Promise . resolve ( obj ) } 1 2 3 J a v a S c r i p t /16