共计 4396 个字符,预计需要花费 11 分钟才能阅读完成。
源码参考 https://github.com/kriskowal/… 主要内容:promise 的迭代设计中主要的代码片段,翻译一部分加上自己的理解,同时指出 promise 的一些特性。
promise 的雏形
var maybeOneOneSecondLater = function () {
var callback;
setTimeout(function () {
callback(1);
}, 1000);
return {
then: function (_callback) {
callback = _callback;
}
};
};
maybeOneOneSecondLater().then(callback1);
promise 诞生,比起传统回调,它返回了一个表示最终结果的对象(一个承诺),我们可以在这个对象上调用函数观察它的实现或者是拒绝。但本质上还是传入回调,任人宰割。好的是,promise 在异步操作和回调之间提供了一个中间层,在这个中间层里可以搞一些事情,解决传统回调的蛋疼问题。改进后的 promise 可以让我们的回调不’任人宰割‘了。
第一次改进
很明显目前这个 promise 只能处理一个回调,传入多个回调会覆盖,所以数据结构上应该用一个数组来储存回调函数,需要执行的时候,依次执行。
let defer = () => {
let pending = [],value;
return {
resolve(_value){
value = _value
for(let i = 0;i < pending.length; i++){
pending[i](value)
}
pending = undefined;
},
then(_callback){
if(pending){
pending.push(_callback)
}else{
_callback();
}
}
}
}
let oneOneSecondLater = () => {
let result = defer();
setTimeout(()=> {
result.resolve(1);
}, 1000);
return result;
};
oneOneSecondLater().then(callback);
这里对代码做一些解释:
defer 函数的作用:产生 promise 对象, 可以理解为 promise 的构造函数;
oneOneSecondLater 函数封装了我们的异步操作 setTimeout;
result.resolve():异步操作完成后告诉 promise,promise 会替你执行回调,这是它作为一个中介应该做的;
oneOneSecondLater().then(callback):oneOneSecondLater 函数的使用者需要告诉 promise,成功后执行什么;
好了,目前我们的 promise 可以接受多次回调,并在异步操作完成后顺序执行了。
第二次改进
promise 这个中介规定,异步操作只能成功一次(resove 只能调用一次哟)。也就是说,使用 promise 封装异步操作的同事们不可能让你的回调执行两次了。。你就大胆的传进去吧。。
let defer = () => {
let pending = [],value
return {
resolve(_value){
if(pending){
value = _value
for(let i = 0;i < pending.length; i++){
pending[i](value)
}
pending = undefined;
}else{
throw new Error(“A promise can only be resolved once.”)
}
},
then(_callback){
if(pending){
pending.push(_callback)
}else{
_callback();
}
}
}
}
补充一点:
因为 promise 在异步操作成功后,就将 pending 设为了 undefined,这也说明,promise 向我们保证了:异步状态一旦改变,就定格了。
所以如果一个异步操作已经成功,你再传回调进去,那就会直接执行:if(pending){pending.push(_callback)}else{_callback();}
第三次改进:职责分离
let defer = () => {
let pending = [],value;
return {
resolve(_value){
if(pending){
value = _value
for(let i = 0;i < pending.length; i++){
pending[i](value)
}
pending = undefined;
}else{
throw new Error(“A promise can only be resolved once.”)
}
},
promise: {
then (callback) {
if (pending) {
pending.push(callback);
} else {
callback(value);
}
}
}
}
}
这个改进就很小了,只是把 then 封装到 promise 对象中,让 resolve 和 promise 两个对象各司其职;
resolve 是在封装异步操作的时候用的,promise 是在使用异步操作时候用的;
第四次改进:加链式操作
熟悉 promise 的同学应该知道,每次 then 执行完成后都是会默认返回 promis 的,就是为了方便链式操作。
var defer = function () {
var pending = [], value;
return {// then called instead
}
resolve: function (_value) {
if (pending) {
value = ref(_value); // values wrapped in a promise
for (var i = 0, ii = pending.length; i < ii; i++) {
var callback = pending[i];
value.then(callback);
pending = undefined;
}
},
promise: {
then: function (_callback) {
var result = defer();
// callback is wrapped so that its return
// value is captured and used to resolve the promise
// that “then” returns
var callback = function (value) {
result.resolve(_callback(value));
};
if (pending) {
pending.push(callback);
} else {
value.then(callback);
}
return result.promise;
}
}
};
};
有两个难点,怎么返回 promise?resolve 要考虑处理 promise 的情况?把 callback 包装到一个新 promise 中,callback 执行的时候直接触发 resolve 这里有点难解释,日后再补。
错误处理
var defer = function () {
var pending = [], value;
return {
resolve: function (_value) {
if (pending) {
value = ref(_value);
for (var i = 0, ii = pending.length; i < ii; i++) {
// apply the pending arguments to “then”
value.then.apply(value, pending[i]);
}
pending = undefined;
}
},
promise: {
then: function (_callback, _errback) {
var result = defer();
var callback = function (value) {
result.resolve(_callback(value));
};
var errback = function (reason) {
result.resolve(_errback(reason));
};
if (pending) {
pending.push([callback, errback]);
} else {
value.then(callback, errback);
}
return result.promise;
}
}
};
};
let ref = (value) => {
if (value && typeof value.then === “function”)
return value;
return {
then: function (callback) {
return ref(callback(value));
}
};
};
let reject = (reason) => {
return {
then: function (callback, errback) {
return ref(errback(reason));
}
};
};
提供默认函数,一个容错
// 提供一个默认的成功回调和错误回调
_callback = _callback || function (value) {
// 默认执行
return value;
};
_errback = _errback || function (reason) {
// 默认拒绝
return reject(reason);
};
安全性和稳定性
保证 callbacks 和 errbacks 在未来他们被调用的时候,应该是和注册时的顺序是保持一致的。这将显著降低异步编程中流程控制出错可能性。
let enqueue = (callback) => {
setTimeout(callback,1)
}
resolve: function (_value) {
if (pending) {
value = ref(_value);
for (let i = 0, ii = pending.length; i < ii; i++) {
enqueue(function () {
value.then.apply(value, pending[i]);
});
}
pending = undefined;
}
}
let ref = function (value) {
if (value && value.then)
return value;
return {
then: function (callback) {
let result = defer();
// XXX
enqueue(function () {
result.resolve(callback(value));
});
return result.promise;
}
};
};
let reject = function (reason) {
return {
then: function (callback, errback) {
var result = defer();
// XXX
enqueue(function () {
result.resolve(errback(reason));
});
return result.promise;
}
};
};
执行的时候如果是异步任务,很有可能会乱?
when 函数和消息传递?