We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Promise 实现都是根据 Promise A+ 规范实现的,我们首先要理解这个规范。
一个常见的 Promise 例子是:
let p = new Promise((resolve, reject) => { resolve(1); }); p.then(val => { console.log(val); }, err => { console.log(err); });
接下来会以这个例子理解规范。
Promise 解决过程是一个抽象操作,其需要输入一个 promise 和一个值,表示为 [[Resolve]](promsie, x),如果 x 有 then 方法且看上去想一个 Promise,解决程序即尝试使 promise 接受 x 的状态,否则用 x 的值来执行 promise 。其中 promise 就是 上面例子的 p。这里还有一个概念就是 thenable:有 then 方法的对象或函数。
备注:上面例子中 Promise 回调函数的参数 resolve,reject 不表示三种状态,表示解决过程,只不过 resolve 结果会是成功态或失败态,而 reject 结果只有失败态。
如果 promise 和 x 指向同一个对象,则以 TypeError 为拒因拒绝执行 promise。
let p = new Promsie((resolve, reject) => { setTimeout(() => { resolve(p); }, 1); }); p.then(val => { console.log(val); }, err => { console.log(err); // TypeError: Chaining cycle detected for promise });
如果 x 是 Promise,那么就接受 x 的状态。假如 x 为等待态,返回的 promise 也是等待态。
let p1 = new Promise((resolve, reject) => { setTimeout(() => { resolve(1); }, 3000); }); let p2 = new Promise((resolve, reject) => { resolve(p1); }); p2.then(val => { console.log(val); // 3秒过后输出1 }, err => { console.log(err); });
刚开始 p1 是等待态,那么 p2 状态也是等待态,经过三秒过后,p1 状态变为成功态,那么 p2 也变为成功态。
将 x.then 赋值给 then ,如果取 x.then 时抛出错误 e, 则以 e 为拒因拒绝 promise。
let obj = { } Object.defineProperty(obj, 'then', { get() { throw 'err'; } }); let p = new Promise((resolve, reject) => { resolve(obj); }); p.then(val => { console.log(val); }, err => { console.log(err); // err });
当取 obj.then 时,会抛出 err 错误,那么 p 也会变为失败态。
如果 then 是函数,那么 x 作为函数的 this 调用。传递 resolvePromise,rejectPromise 作为 then 函数的参数。
let obj = { a: 123, then: function(resolvePromise , rejectPromise ) { console.log(this.a); // 123 resolvePromise (1); resolvePromise (2); rejectPromise (3); } }; let p = new Promise((resolve, reject) => { resolve(obj); }); p.then(val => { console.log(val); // 1 }, err => { console.log(err); });
obj.then 函数中 this 就是 obj 对象。resolvePromise,rejectPromise 是新的 Promise 解决过程。
如果多次调用 resolvePromise 或 rejectPromise 那么只采用第一次调用,后面的忽略。这个例子只采用了 resolvePromise(1),其他的被忽略。
let obj = { a: 123, then: function(resolvePromise , rejectPromise ) { console.log(err); // err 没有定义 resolvePromise (1); } }; let p = new Promise((resolve, reject) => { resolve(obj); }); p.then(val => { console.log(val); }, err => { console.log(err); // ReferenceError: err is not defined });
obj.then 函数抛出 err is not defined 错误,p 变为失败态。
如果在 obj.then 函数中的第一行添加 resolvePromise(10) 或 rejectPromise('err') 那么错误被忽略,会正常的运行。
如果 then 不是函数或者没有 then 这个属性,以 x 为参数执行 promise。
let obj = { a: 1, then: 'then' }; let p = new Promise((resolve, reject) => { resolve(obj); }); p.then(val => { console.log(val); }, err => { console.log(err); // Object });
let p = new Promise((resolve, reject) => { resolve(1); }); p.then(val => { console.log(val); // 1 }, err => { console.log(err); });
一个 Promise 必须提供一个 then 方法。这个方法接受两个可选参数
promise.then(onFulfilled, onRejected)
onFulfilled,onRejected 如果不是函数,那么忽略。
当 promise 是成功态时,调用 onFulfilled 函数,是失败态时调用 onRejected 函数。并且都只能调用一次。promise 是等待态时,不可调用 then 函数。
在严格模式下,onFulfilled 和 onRejected 必须作为函数调用(没有 this 值)。
'use strict'; var a = 1; let obj = { a: 10, fulfilled: function(val) { console.log(this); // undefined } }; let p = new Promise((resolve, reject) => { resolve(3); }); p.then(obj.fulfilled);
如果不是在严格模式下,在一般都将 this 赋值为 window(global)。
如果将 onFulfilled 、onRejected 通过 bind 绑定或者是箭头函数形式,即使在严格模式下也会存在 this 值。
'use strict'; var a = 1; let obj = { a: 10, fulfilled: function(val) { console.log(this.a); // 10 } }; let p = new Promise((resolve, reject) => { resolve(3); }); p.then(obj.fulfilled.bind(obj));
then 方法必须返回一个 Promise 对象。
let promise2 = promise1.then(onFulfilled, onRejected);
第一二点比较好理解,第三四点简单一点就是 promise1 是什么状态,promise2 就是什么状态。
let p = new Promise((resolve, reject) => { resolve(1); }); let p1 = p.then('a', 'b'); // onFulfilled 不是函数,那么 p1 的状态和 p 状态是一样的 p1.then(val => { console.log(val); // 1 });
另外如果 onFulfilled 或者 onRejected 函数没有返回值,还是返回一个 Promise。
let p = new Promise((resolve, reject) => { resolve(1); }); let p1 = p.then(val => {}); p1.then(val =>{ console.log(val); // undefined });
错误传递
Promise 发生错误,如果不处理,那么错误会一直传递,直到遇见 catch 或 then 函数中第二个参数。如果没有错误处理函数,错误会被抛弃。所以一般会在最后添加 catch 函数。
let p = Promise.resolve(12); p.then(val => { console.log(err); }) .catch(err => { console.log(err); // ReferenceError: err is not defined });
如果最后都没有处理错误,错误会被抛弃。
如果采用 try...catch 处理错误,那么 Promise 不会捕获错误
let p = new Promise((resolve, reject) => { try { console.log(err); } catch(err) { console.log(err); // ReferenceError: err is not defined } resolve(1); }); p.then(val => { console.log(val); // 1 }, err => { console.log(err); });
在 then 回调函数发生的错误,传递到下一个 promise 中处理
let p = Promise.resolve(); p.then(val => { console.log(err); }) .then(undefined, err => { console.log(err); // ReferenceError: err is not defined });
Promise 异步需要注意一下节点:
new Promise 回调函数是同步执行的
then 函数的回调函数是异步执行的。至于回调函数是放在 task(macrotask) 还是 microtask 中,Promise A+ 规范注释第一点都允许,所以需要看具体环境(一般都是在 microtask)。
链式调用时,then 函数的回调函数都是在同一个 tick 中执行
let p = Promise.resolve(1); p.then(val => { console.log(val); return 2; }) .then(val => { console.log(val); }) setTimeout(() => { console.log('timeout'); }, 0); // 1 // 2 // timeout
在业务上需要串行执行的情况很多,一般通过数组方法 reduce 或 forEach 实现,下面是一个简单的实现
let p1 = function () { return new Promise((resolve, reject) => { setTimeout(() => { resolve(1); }, 1000); }); } let p2 = function () { return new Promise((resolve, reject) => { setTimeout(() => { resolve(2); }, 3000); }); } let p3 = function () { return new Promise((resolve, reject) => { resolve(3); }); } let results = []; let p = [p1, p2, p3].reduce((promise, current) => { return promise.then(current).then((val) => { results.push(val); }) }, Promise.resolve()); p.then(val => { console.log(results); // [1, 2, 3] }, err => { console.log(err); });
采用 async/await 会更简单。一般在工作中使用成熟的代码库。
本来计划按照规范采用 JS 实现一遍规范,但是网上已经有非常多很好的例子了,就不在重复。
The text was updated successfully, but these errors were encountered:
No branches or pull requests
理解Promise
理解 Promise A+ 规范
Promise 实现都是根据 Promise A+ 规范实现的,我们首先要理解这个规范。
一个常见的 Promise 例子是:
接下来会以这个例子理解规范。
Promise 解决过程是一个抽象操作,其需要输入一个 promise 和一个值,表示为 [[Resolve]](promsie, x),如果 x 有 then 方法且看上去想一个 Promise,解决程序即尝试使 promise 接受 x 的状态,否则用 x 的值来执行 promise 。其中 promise 就是 上面例子的 p。这里还有一个概念就是 thenable:有 then 方法的对象或函数。
备注:上面例子中 Promise 回调函数的参数 resolve,reject 不表示三种状态,表示解决过程,只不过 resolve 结果会是成功态或失败态,而 reject 结果只有失败态。
Promise 解决过程分为以下三种情况:
x 与 promise 相等
如果 promise 和 x 指向同一个对象,则以 TypeError 为拒因拒绝执行 promise。
x 是 Promise
如果 x 是 Promise,那么就接受 x 的状态。假如 x 为等待态,返回的 promise 也是等待态。
刚开始 p1 是等待态,那么 p2 状态也是等待态,经过三秒过后,p1 状态变为成功态,那么 p2 也变为成功态。
x 是对象或函数
将 x.then 赋值给 then ,如果取 x.then 时抛出错误 e, 则以 e 为拒因拒绝 promise。
当取 obj.then 时,会抛出 err 错误,那么 p 也会变为失败态。
如果 then 是函数,那么 x 作为函数的 this 调用。传递 resolvePromise,rejectPromise 作为 then 函数的参数。
obj.then 函数中 this 就是 obj 对象。resolvePromise,rejectPromise 是新的 Promise 解决过程。
如果多次调用 resolvePromise 或 rejectPromise 那么只采用第一次调用,后面的忽略。这个例子只采用了 resolvePromise(1),其他的被忽略。
obj.then 函数抛出 err is not defined 错误,p 变为失败态。
如果在 obj.then 函数中的第一行添加 resolvePromise(10) 或 rejectPromise('err') 那么错误被忽略,会正常的运行。
如果 then 不是函数或者没有 then 这个属性,以 x 为参数执行 promise。
x 不为对象或函数,以 x 为参数执行 promise
Then 方法
一个 Promise 必须提供一个 then 方法。这个方法接受两个可选参数
onFulfilled,onRejected 如果不是函数,那么忽略。
当 promise 是成功态时,调用 onFulfilled 函数,是失败态时调用 onRejected 函数。并且都只能调用一次。promise 是等待态时,不可调用 then 函数。
在严格模式下,onFulfilled 和 onRejected 必须作为函数调用(没有 this 值)。
如果不是在严格模式下,在一般都将 this 赋值为 window(global)。
如果将 onFulfilled 、onRejected 通过 bind 绑定或者是箭头函数形式,即使在严格模式下也会存在 this 值。
返回值
then 方法必须返回一个 Promise 对象。
第一二点比较好理解,第三四点简单一点就是 promise1 是什么状态,promise2 就是什么状态。
另外如果 onFulfilled 或者 onRejected 函数没有返回值,还是返回一个 Promise。
Promise 错误处理
错误传递
Promise 发生错误,如果不处理,那么错误会一直传递,直到遇见 catch 或 then 函数中第二个参数。如果没有错误处理函数,错误会被抛弃。所以一般会在最后添加 catch 函数。
如果最后都没有处理错误,错误会被抛弃。
如果采用 try...catch 处理错误,那么 Promise 不会捕获错误
在 then 回调函数发生的错误,传递到下一个 promise 中处理
Promise 异步
Promise 异步需要注意一下节点:
new Promise 回调函数是同步执行的
then 函数的回调函数是异步执行的。至于回调函数是放在 task(macrotask) 还是 microtask 中,Promise A+ 规范注释第一点都允许,所以需要看具体环境(一般都是在 microtask)。
链式调用时,then 函数的回调函数都是在同一个 tick 中执行
其他
在业务上需要串行执行的情况很多,一般通过数组方法 reduce 或 forEach 实现,下面是一个简单的实现
采用 async/await 会更简单。一般在工作中使用成熟的代码库。
本来计划按照规范采用 JS 实现一遍规范,但是网上已经有非常多很好的例子了,就不在重复。
参考资料
The text was updated successfully, but these errors were encountered: