基本概念 高阶函数 JS 中 函数是一等公民 函数可以作为参数和返回值传递
回调函数的问题
不能 trycatch
不能 return
回调地狱
解决回调地狱 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 let EventEmitter = require ("events" );let eve = new EventEmitter();let html = {}eve.on("ready" , function (key, value ) { html[key] = value; if (Object .keys(html).length === 2 ){ console .log("ok) } }); fs.readFile(" ./node/template.txt", " utf8", function(err, data) { eve.emit(" ready", " template", data); }); fs.readFile(" ./node/data.txt", " utf8", function(err, data) { eve.emit(" ready", " data", data); });
哨兵函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 let html = {};function done (key, value ) { html[key] = value; if (Object .keys(html).length === 2 ) { console .log("ok" ); } } fs.readFile("./node/template.txt" , "utf8" , function (err, data ) { done("template" , data); }); fs.readFile("./node/data.txt" , "utf8" , function (err, data ) { done("data" , data); });
进一步优化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 function render (length,cb ) { return function (key,value ) { html[key] = value if (Object .keys(html).length === length){ cb() } } } function done = render (2 ,function (){ console .log("ok" ) } )fs .readFile ("./node/template.txt" , "utf8" , function (err, data) { done("template" , data); } ) ;fs.readFile("./node/data.txt" , "utf8" , function (err, data ) { done("data" , data); });
generator 生成器是一个函数,可以用来生成迭代器,生成器函数和普通函数不同,生成器函数中间可以暂停
1 2 3 4 5 6 7 8 9 10 11 12 13 async function read ( ) { let template = await readFile('./template.txt) let data = await readFile(' ./data.txt') return template + data } // 等同于 return read(){ return co(function*(){ let template = yield readFile(' ./template') let data = yield readFile(' ./data') return template + data }) }
co 1 2 3 4 5 6 7 8 9 10 11 12 13 function co (gen ) { let it = gen(); return new Promise ((resolve,reject ) => { !function next (lastVal ) { if {value,done} = it.next(lastVal); if (done){ resolve(value); }else { value.then(next,reject) } } }) }
Promise 详解 生命周期 Promise 的生命周期,初始为 pending state,表示异步操作尚未结束。挂起状态可以认为是未决的 unsettled,一旦异步操作结束, Promise 就会被认为是 已决的,进入两种可能状态
已完成( fulfilled ): Promise 的异步操作已成功结束;
已拒绝( rejected ): Promise 的异步操作未成功结束,可能是一个错误,或由其他原 因导致。 then()方法在所有的 Promise 上都存在,并且接受两个参数。第一个参数是 Promise 被完成时要调用的函数,与异步操作关联的任何附加数据都会被传入这个完成函数。第二个参数则是 Promise 被拒绝时要调用的函数,与完成函数相似,拒绝函数会被传入与拒绝相关联的任何附加数据。用这种方式实现 then() 方法的任何对象都被称为一个 thenable 。所有的 Promise 都是 thenable ,反之则未必成立。 Promis 也具有一个 catch() 方法,其行为等同于只传递拒绝处理函数给 then()。
创建未决的 Promise 使用 Promise 构造函数,Promise 执行器被调用的时候立即运行,当 resolve 或 reject 在执行器内部被调用时,一个作业被添加到作业队列,以决议这个 Promise。这和 setTimeout 或 setInterval 类似。
1 2 3 4 5 6 7 8 let promise = new Promise (function (resolve, reject ) { console .log("Promise" ); resolve(); }); promise.then(function ( ) { console .log("Resolved." ); }); console .log("Hi!" );
输出: Promise Hi! Resolved
完成处理函数与拒绝处理函数总是会在执行器的操作结束后被添加到作业队列的尾部,所以 then 中的操作会在最后执行。
创建已决的 Promise 使用 Promise.resolve 或者 Promise.reject
1 2 3 4 let promise = Promise .resolve(42 );promise.then(function (value ) { console .log(value); });
经过我自己的测试,书上内容有误。以下为我自己测试的结果 若传入的 Promise 为挂起态,则 Promise.resolve 调用会将该 Promise 原样返回。此后如果决议原 Promise,在 then() 中可以接收到参数,如果拒绝,可以在 catch 中接收到参数。 Promise.resove 始终会返回原 Promise,而 Promise.reject 始终会对 Promise 重新包装,包装后的 Promise 处于拒绝态,且其 catch 接受的参数是原先处于拒绝态度的 Promise
thenable 当一个对象拥有一个能接受 resolve 与 reject 参数的 then() 方法,该对象就会被认为是一个非 Promise 的 thenable
1 2 3 4 5 6 7 8 9 let thenable = { then : function (resolve, reject ) { resolve(42 ); }, }; let p1 = Promise .resolve(thenable);p1.then(function (value ) { console .log(value); });
Promise.resolve 方法会将其转换为 Promise,其状态为 Thenable 的 then 方法返回的状态,而 Promise.reject 方法会始终返回一个 reject 态的 Promise,传递给 catch 的参数为原 Thenable 对象
执行器错误 如果在执行器内部抛出了错误,那么 Promise 的拒绝处理函数就会被调用。
Promise A+ 实现 对照 https://promisesaplus.com/ 实现就好。
需要注意的规范中的 3.1 注明了 then 中的 onFulfilled and onRejected 需要在本次事件循环结束后方可执行。
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 const PENDING = "pending" ;const FULFILLED = "fulfilled" ;const REJECTED = "rejected" ;function Promise (executor ) { let self = this ; self.status = PENDING; self.onResolvedCallbacks = []; self.onRejectedCallbacks = []; function resolve (value ) { setTimeout (() => { if (self.status === PENDING) { self.status = FULFILLED; self.value = value; self.onResolvedCallbacks.forEach((cb ) => cb()); } }); } function reject (reason ) { setTimeout (() => { if (self.status === PENDING) { self.status = REJECTED; self.value = reason; self.onRejectedCallbacks.forEach((cb ) => cb()); } }); } try { executor(resolve, reject); } catch (err) { reject(err); } } Promise .prototype.then = function (onFulfilled, onRejected ) { onFulfilled = typeof onFulfilled === "function" ? onFulfilled : (value ) => value; onRejected = typeof onRejected === "function" ? onRejected : (reason ) => { throw reason; }; const self = this ; let promise2; if (self.status === FULFILLED) { return (promise2 = new Promise ((resolve, reject ) => { setTimeout (() => { try { let x = onFulfilled(self.value); resolvePromise(promise2, x, resolve, reject); } catch (err) { reject(err); } }); })); } if (self.status === REJECTED) { return (promise2 = new Promise ((resolve, reject ) => { setTimeout (() => { try { let x = onRejected(self.value); resolvePromise(promise2, x, resolve, reject); } catch (e) { reject(e); } }); })); } if (self.status === PENDING) { return (promise2 = new Promise (function (resolve, reject ) { self.onResolvedCallbacks.push(function ( ) { try { let x = onFulfilled(self.value); resolvePromise(promise2, x, resolve, reject); } catch (e) { reject(e); } }); self.onRejectedCallbacks.push(function ( ) { try { let x = onRejected(self.value); resolvePromise(promise2, x, resolve, reject); } catch (e) { reject(e); } }); })); } }; function resolvePromise (promise2, x, resolve, reject ) { if (x === promise2) { return reject(new TypeError ("Circular reference" )); } let called = false ; if (x !== null && (typeof x === "object" || typeof x === "function" )) { try { let then = x.then; if (typeof then === "function" ) { then.call( x, function (y ) { if (called) return ; called = true ; resolvePromise(promise2, y, resolve, reject); }, function (err ) { if (called) return ; called = true ; reject(err); } ); } else { if (called) return ; called = true ; resolve(x); } } catch (err) { if (called) return ; called = true ; reject(err); } } else { resolve(x); } } Promise .prototype.catch = function (onRejected ) { return this .then(null , onRejected); }; Promise .prototype.resolve = function (value ) { new Promise (function (resolve ) { resolve(vzlue); }); }; Promise .reject = function (reason ) { return new Promise (function (resolve, reject ) { reject(reason); }); }; Promise .deferred = function ( ) { let res, rej; const promise = new Promise ((resolve, reject ) => { res = resolve; rej = reject; }); return { promise, resolve : res, reject : rej, }; }; module .exports = Promise ;