promise
描述 promise 框架 - 规范
promise 有哪些状态?对应值有哪些 - pending、fulfilled、rejected
new Promise 执行器 executor(),执行器参数是? - resolve、reject
promise 的默认状态是?promise 状态的流转? - 默认 pending,pf,pr
promise,value 保存成功状态的枚举?- undefined/thenable/promise
promise,失败状态值?- reason 保存失败
描述 promise 接口
promise 一定会有 then,then 接收来源,两个回调 onFulfilled(value) + onRejected(reason)
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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 const PENDING = "pending" ;const FULFILLED = "fulfilled" ;const REJECTED = "rejected" ;class MPromise { #state = PENDING ; #result = undefined ; #handlers = []; constructor (executor ) { const resolve = (data ) => { this .#changeState (FULFILLED , data); }; const reject = (reason ) => { this .#changeState (REJECTED , reason); }; try { executor (resolve, reject); } catch (err) { reject (err); } } #changeState (state, result ) { if (this .#state !== PENDING ) return ; this .#state = state; this .#result = result; this .#run (); } #isPromiseLike (value ) {} #runMicroTask (func ) { if (typeof process === "object" && typeof process.nextTick === "function" ) { process.nextTick (func); } else if (typeof MutationObserver === "function" ) { const ob = new MutationObserver (func); const textNode = document .createTextNode ("1" ); ob.observe (textNode, { characterData : true , }); textNode.data = "2" ; } else { setTimeout (func, 0 ); } } #runOne (callback, resolve, reject ) { this .#runMicroTask (() => { if (typeof callback !== "function" ) { const settled = this .#state === FULFILLED ? resolve : reject; settled (this .#result); return ; } try { const data = callback (this .#result); if (this .#isPromiseLike (data)) { data.then (resolve, reject); } else { resolve (data); } } catch (err) { reject (err); } }); } #run ( ) { if (this .#state !== PENDING ) return ; while (this .#handlers.length ) { const { onFulfilled, onRejected, resolve, reject } = this .#handlers.shift (); if (this .#state === FULFILLED ) { this .#runOne (onFulfilled, resolve, reject); } else if (this .#state === REJECTED ) { this .#runOne (onRejected, resolve, reject); } else { } } } then (onFulfilled, onRejected ) { return new MyPromise ((resolve, reject ) => { this .#handlers.push ({ onFulfilled, onRejected, resolve, reject, }); this .#run (); }); } all (proms ) { let res, ref; const p = new MyPromise ((resolve, reject ) => { res = resolve; rej = reject; }); const result = []; let count = 0 ; let fulFilledCount = 0 ; for (const prom of proms) { const i = count; count++; MyPromise .resolve (prom).then ((data ) => { result[i] = data; fulFilledCount++; if (fulFilledCount === count) { res (result); } }, rej); } if (count === 0 ) { res (result); } return p; } catch (onRejected) { return this .then (undefined , onRejected); } finally (onFinally ) { return this .then ( (data ) => { onFinally (); return data; }, (err ) => { onFinally (); throw err; } ); } static resolve (value ) { if (value instanceof MyPromise ) return value; let res, rej; const p = new MyPromise ((resolve, reject ) => { res = resolve; rej = reject; }); if (p.#isPromiseLike (value)) { value.then (res, rej); } else { res (value); } return p; } static reject (reason ) { return new MyPromise ((resolve, reject ) => { reject (reason); }); } }
A+ 规范
判断一个值是否是 Promise Like
1 2 3 4 5 6 7 function isPromiseLike (value ) { return ( value !== null && (typeof value === "object" || typeof value === "function" ) && typeof value.then === "function" ); }
问题引入 为什么 promise resolve 了一个 value, 最后输出的 value 值确是 undefined
1 2 3 4 5 6 7 8 9 10 11 const test = new MPromise ((resolve, reject ) => { setTimeout (() => { resolve (111 ); }, 1000 ); }).then ((value ) => { console .log ("then" ); }); setTimeout (() => { console .log (test); }, 3000 );
因为现在这种写法, 相当于在.then 里 return undefined, 所以最后的 value 是 undefined,如果显式 return 一个值, 就不是 undefined 了;比如 return value
.then 返回的是一个新 Promise, 那么原来 promise 实现的时候, 用数组来存回调函数有什么意义?
情况 1,链式调用的时候,此时每一个.then 返回的都是一个新 promise, 所以每次回调数组 FULFILLED_CALLBACK_LIST 都是空数组。针对这种情况, 确实用数组来存储回调没意义, 完全可以就用一个变量来存储。
1 2 3 4 5 6 7 const test = new Promise ((resolve, reject ) => { setTimeout (() => { resolve (111 ); }, 1000 ); }) .then ((value ) => {}) .then (() => {});
情况 2,promise 实例是同一个, 数组的存在就有了意义
1 2 3 4 5 6 7 8 9 10 const test = new Promise ((resolve, reject ) => { setTimeout (() => { resolve (111 ); }, 1000 ); }); test.then (() => {}); test.then (() => {}); test.then (() => {}); test.then (() => {});
为什么在 catch 的回调里, 打印 promise, 显示状态是 pending
1 2 3 4 5 6 7 8 9 10 11 12 const test = new Promise ((resolve, reject ) => { setTimeout (() => { reject (111 ); }, 1000 ); }).catch ((reason ) => { console .log ("报错" + reason); console .log (test); }); setTimeout (() => { console .log (test); }, 3000 );
catch 函数会返回一个新的 promise, 而 test 就是这个新 promise
catch 的回调里, 打印 promise 的时候, 整个回调还并没有执行完成(所以此时的状态是 pending), 只有当整个回调完成了, 才会更改状态
catch 的回调函数, 如果成功执行完成了, 会改变这个新 Promise 的状态为 fulfilled
常用方法
race:返回一个新的 Promise 实例
const p = Promise.race([p1, p2, p3]);
只要 p1、p2、p3 之中有一个实例率先改变状态,p 的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给 p 的回调函数。
all:返回一个新的 Promise 实例,适用于需要确保所有 Promise 成功完成才能继续执行的情况。
const p = Promise.all([a、b、c]);
a、b、c 都是 Promise 实例,如果不是,就会先调用下面讲到的 Promise.resolve 方法,将参数转为 Promise 实例,再进一步处理
参数可以不是数组,但必须具有 Iterator 接口,且返回的每个成员都是 Promise 实例
allSettled:适用于需要获取所有 Promise 的最终状态(无论成功或失败)的情况,而不是仅仅关注成功的结果
finally:(es2018)不接受任何参数,无法知道前面的 Promise 状态到底是 fulfilled 还是 rejected。这表明,finally 方法里面的操作,应该是与状态无关的,不依赖于 Promise 的执行结果。
any:只要参数实例有一个变成 fulfilled 状态,包装实例就会变成 fulfilled 状态;如果所有参数实例都变成 rejected 状态,包装实例就会变成 rejected 状态。
async await & generator
promise 的语法糖,await 后面的语句放在 .then 回调里面
被 async 定义的函数会默认返回一个 Promise 对象 resolve 的值
对 async 函数可以直接 then,返回值就是 then 方法传入的函数
async await 是在 generator 的基础上,promise 执行器内部处理了中间状态,返回最终状态
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 async function foo ( ) { console .log (0 ); const n = await 1 ; console .log (n); } foo ();console .log (2 ); function foo ( ) { return Promise .resolve (1 ).then ((n ) => { console .log (n); }); }
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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 function wait500 (input ) { return new Promise ((resolve, reject ) => { console .log ("wait500" , input); setTimeout (() => { resolve (input + 500 ); }, 500 ); }); } wait500.then ((res ) => { wait500.then ((res ) => { wait500.then ((res ) => { wait500.then ((res ) => {}); }); }); }); async function asyncCall ( ) { const result = await wait500 (0 ); result = await wait500 (0 ); result = await wait500 (0 ); result = await wait500 (0 ); console .log ("asyncCall" , result); } asyncCall ();function * generator ( ) { let index = 0 ; while (true ) yield index++; } let gen = generator ();console .log (gen.next ().value );console .log (gen.next ().value );console .log (gen.next ().value );console .log (gen.next ().value );const GEN_LINE = [1 , 2 , 3 , 4 , 5 , 6 ](GEN_LINE || []).forEach ((it ) => { console .log (gen.next (it).value ); });
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 26 27 28 29 30 31 function getNum (num ) { return new Promise ((resolve, reject ) => { setTimeout (() => { resolve (num + 1 ); }, 1000 ); }); } function asyncFun (func ) { var gen = func (); function next (data ) { var result = gen.next (data); if (result.done ) return result.value ; result.value .then (function (data ) { next (data); }); } next (); } var func = function * () { var f1 = yield getNum (1 ); var f2 = yield getNum (f1); console .log (f2); }; asyncFun (func);
generator 传值 1 2 3 4 5 6 7 8 9 10 11 function * simpleGen ( ) { const a = yield 1 ; console .log (a); const b = yield 2 ; return a + b; } const gen = simpleGen ();gen.next (); gen.next (10 ); gen.next (20 );
gen.next(): 暂停在 yield 1 处,等待下一次 next() 调用,返回值: { value: 1, done: false },此时变量 a 尚未被赋值
gen.next(10): 参数 10 被传递给 Generator,成为第一个 yield 表达式的结果,赋值操作完成:const a = 10,执行 console.log(a) 输出 10,此时变量 b 尚未被赋值
yield
表达式的双重角色
向外部返回右侧表达式
的值
从外部接收下一次 next()
调用传入的值
参数传递时机
第一次 next() 调用通常不带参数 (传入的参数会被忽略)
后续 next() 调用的参数会成为上一个 yield 表达式的结果值
执行流程控制
每次 next() 调用会使 Generator 执行到下一个 yield 或 return
yield 暂停执行,next() 恢复执行