promise的几个关键问题
-
如何改变 promise 的状态?
(1) resolve(value): 如果当前是 pending 就会变为 resolved
(2) reject(reason): 如果当前是 pending 就会变为 rejected
(3) 抛出异常: 如果当前是 pending 就会变为 rejected -
一个 promise 指定多个成功/失败回调函数, 都会调用吗?
当 promise 改变为对应状态时都会调用
-
改变 promise 状态和指定回调函数谁先谁后?
(1) 都有可能, 正常情况下是先指定回调再改变状态, 但也可以先改状态再指定回调
(2) 如何先改状态再指定回调?
① 在执行器中直接调用 resolve()/reject()
② 延迟更长时间才调用 then()
(3) 什么时候才能得到数据?
① 如果先指定的回调, 那当状态发生改变时, 回调函数就会调用, 得到数据
② 如果先改变的状态, 那当指定回调时, 回调函数就会调用, 得到数据 -
promise.then()返回的新 promise 的结果状态由什么决定?
(1) 简单表达: 由 then()指定的回调函数执行的结果决定
(2) 详细表达:
① 如果抛出异常, 新 promise 变为 rejected, reason 为抛出的异常
② 如果返回的是非promise的任意值, 新promise变为resolved, value为返回的值
③ 如果返回的是另一个新promise, 此promise的结果就会成为新promise的结果 -
promise 如何串连多个操作任务?
(1) promise 的 then()返回一个新的 promise, 可以开成 then()的链式调用
(2) 通过 then 的链式调用串连多个同步/异步任务 -
promise 异常传透?
(1) 当使用 promise 的 then 链式调用时, 可以在最后指定失败的回调,
(2) 前面任何操作出了异常, 都会传到最后失败的回调中处理 -
如何中断 promise 链?
(1) 当使用 promise 的 then 链式调用时, 在中间中断, 不再调用后面的回调函数
(2) 办法: 在回调函数中返回一个 pendding 状态的 promise 对象 -
then等方法为什么要定义在原型上?
(1)当方法定义在构造函数内部的this上时,在实例化多个对象的时候,同样的会把方法也会复制一遍(即每个实例化后的对象,都有一个方法),这样的话,当需要该构造函数实例化很多对象的时候,每一个实例化后的对象的方法都要占用一定的内存,这样就会导致内存开销太大了
(2)而通过prototype来定义的方法,在实例化对象的时候,都只是在每个对象中复制了一个指向该方法的一个指针,所以实际上,占用的内存只有一个方法
(3)所以对比两者的话,使用prototype来定义方法的话,可以节省很多的内存开销。但是,在构造函数里面,定义的变量有私有变量(即通过var 定义的变量)和公有变量(即通过this来定义的变量),因为私有变量不能被外界访问,所以我们需要有可以在外界访问私有变量的途径,而在构造函数里面通过this定义的方法可以有效的访问私有变量
-
Promise then中回调为什么是异步执行?
回调(例如 then 中的)如果可能同步、也可能异步,执行顺序就变成了不确定的,无法保证程序逻辑的一致性 ,也就类似多线程中的竞态条件。为了避免这种不确定性,then 的回调总是作为 Job Queue 中的下一个 Job 执行(异步执行)。
例如:
promise.then(function(){ if (trueOrFalse) { // 同步执行 foo(); } else { // 异步执行 (如:使用第三方库) setTimeout(function(){ foo(); }) } }); bar();
-
如果 promise then 回调是同步执行的,请问 foo() 和 bar() 函数谁先执行? 答案是,如果 trueOrFalse 为 true 则 foo() 先执行,bar() 后执行;否则 bar() 先执行,foo() 后执行。在大部分情况下,你没法预料到 trueOrFalse 的值,这也就意味着,你不能确定这段代码真正的执行顺序,这可能会导致一些难以想到的 bug。
-
如果 promise then 回调是异步执行的,请问 foo() 和 bar() 函数谁先执行? 答案一目了然,bar() 先执行,foo() 后执行。
所以为了保证代码执行顺序的一致性, then 回调必须保证是异步的。
promise的代码实现
//Promise是一个构造函数 //打印原生Promise发现[[PromiseState]],[[PromiseResult]]都是有双中括号的,表明这两个属性都是内置的,外部无法修改的 //executor函数里的内容是同步执行的 function Promise(executor) { //状态值 this.PromiseState = 'pending'; //属性值 this.PromiseResult = null; //用来保存所有待调用的包含onResolved和onRejected回调函数的对象的数组 this.callbacks = []; const self = this; // function中的this指向window function resolve(data) { if(self.PromiseState !== 'pending') return; self.PromiseState = 'fulfilled'; self.PromiseResult = data; //异步调用所有待处理的onResolved成功回调函数 if(self.callbacks.length > 0) { setTimeout(() => { self.callbacks.forEach(item => { item.onResolved(); }); }) } } function reject(data) { if(self.PromiseState !== 'pending') return; self.PromiseState = 'fulfilled'; self.PromiseResult = data; //异步调用所有待处理的onRejected成功回调函数 if(self.callbacks.length > 0) { setTimeout(() => { self.callbacks.forEach(item => { item.onRejected(); }); }) } } try { //同步调用执行器函数 executor(resolve, reject); }catch(e) { reject(e); //异常则直接失败 } } Promise.prototype.then = function(onResolved, onRejected) { const self = this; // 处理异常穿透 //当出现异常或者rejected时,虽然then中没有处理rejected的函数,但如果有catch函数,则会一直穿透,交给catch去处理 if(typeof onRejected !== 'function') { onRejected = reason => { throw reason; } } if(typeof onResolved !== 'function') { onResolved = value => value; } return new Promise((resolve, reject) => { function callback(type) { try { let result = type(self.PromiseResult); if(result instanceof Promise) { // 返回一个新的promise result.then(v => { resolve(v); }, r => { reject(r); }) }else { resolve(result); } }catch(e) { reject(e); } } if(this.PromiseState === 'fulfilled') { setTimeout(() => { callback(onResolved); }) } if(this.PromiseState === 'rejected') { setTimeout(() => { callback(onRejected); }) } if(this.PromiseState === 'pending') { //将onResolved和onRejected保存起来 this.callbacks.push({ onResolved: function() { callback(onResolved); }, onRejected: function() { callback(onRejected); } }) } }) } Promise.prototype.catch = function(onRejected) { return this.then(undefined, onRejected); } //返回一个成功的 promise 对象 Promise.resolve = function(value) { return new Promise((resolve, reject) => { if(value instanceof Promise) { value.then(v => { resolve(v); }, r => { reject(r); }) }else { resolve(value); } }) } //返回一个失败的 promise 对象 Promise.reject = function(reason) { return new Promise((resolve, reject) => { reject(reason); }) } // 返回一个新的 promise, 只有所有的 promise 都成功才成功, 只要有一个失败了就直接失败 Promise.all = function(promises) { return new Promise((resolve, reject) => { let count = 0; let arr = []; for(let i=0; i<promises.length; i++) { promises[i].then(v => { count++; arr[i] = v; //只有所有promise都成功,才返回成功 if(count === promises.length) { resolve(arr); } }, r => { // 只要有一个失败,就返回失败 reject(r); }) } }) } // 返回一个新的 promise, 第一个完成的 promise 的结果状态就是最终的结果状态 Promise.race = function(promises) { return new Promise((resolve, reject) => { for(let i=0; i<promises.length; i++) { promises[i].then(v => { resolve(v); }, r => { reject(r); }) } }) }
-