[英]Implementing promise class in javascript
我正在嘗試使用可鏈接的.then()
功能在JavaScript中實現一個簡單的promise類。 這是我到目前為止所做的-
class APromise {
constructor(Fn) {
this.value = null;
Fn(resolved => { this.value = resolved; });
}
then(fn) {
fn(this.value);
return this;
}
}
function myFun() {
return new APromise(resolve => {
// just resolve('Hello'); works but this doesn't
setTimeout(() => { resolve('Hello'); }, 2000);
});
}
const log = v => { console.log(v); };
myFun().then(log).then(log);
輸出-
null
null
而不是'Hello'
2次。 我認為它目前正在忽略setTimeout()
調用,我應該如何使其工作?
您的代碼無法按照您想要的方式工作,因為您將異步流與同步流混合在一起。
當您調用.then()
,它將同步返回this
。 由於setTimeout()
是一個異步函數,會在一段時間(2秒)后調用,因此this.value
仍然為null
。
如果您想進一步了解JS的異步流程,建議您觀看此視頻 。 它有點長,但超級有幫助。
由於我們無法確定setTimeout()
何時調用傳遞給它的函數,因此我們無法調用和回調依賴於其操作的函數。 我們將這些回調存儲在數組中,以備后用。
當調用setTimeout()
函數(承諾解決)時,我們得到了承諾解決的結果。 因此,我們現在調用所有綁定的回調。
class APromise {
constructor(Fn) {
this.value = null;
- Fn(resolved => { this.value = resolved; });
+ this.callbacks = [];
+ Fn(resolved => {
+ this.value = resolved;
+
+ this.callbacks.forEach(cb => {
+ cb(this.value);
+ });
+ });
}
then(fn) {
- fn(this.value);
+ this.callbacks.push(fn);
return this;
}
}
function myFun() {
return new APromise(resolve => {
setTimeout(() => { resolve('Hello'); }, 2000);
});
}
const log = v => { console.log(v); };
myFun().then(log).then(log);
上面的代碼部分解決了該問題。
當一個回調的結果傳遞到下一個回調時,可以實現真正的鏈接。 在當前代碼中情況並非如此。 為了實現這一點,每個.then(cb)
必須返回一個新的APromise
,它可以在調用cb
函數時解析。
完整且符合Promises / A +的實現方式超出了單個SO答案的范圍,但這不應給人以為它不可行的印象。 這是精選的定制命令列表 。
讓我們從一個干凈的開始。 我們需要一個Promise
類,該類實現一個方法, then
該方法還返回一個允許鏈接的承諾。
class Promise {
constructor(main) {
// ...
}
then(cb) {
// ...
}
}
在這里, main
是一個函數, 它將一個函數作為參數,並在promise被解析/實現時調用它-我們稱此方法resolve()
。 所述函數resolve()
由我們的Promise
類實現並提供。
function main(resolve) {
// ...
resolve(/* resolve value */);
}
then()
方法的基本功能是,一旦諾言實現,就用諾言值觸發/激活提供的回調函數cb()
。
考慮到這兩點,我們可以重新連接Promise
類。
class Promise {
constructor(main) {
this.value = undefined;
this.callbacks = [];
const resolve = resolveValue => {
this.value = resolveValue;
this.triggerCallbacks();
};
main(resolve);
}
then(cb) {
this.callbacks.push(cb);
}
triggerCallbacks() {
this.callbacks.forEach(cb => {
cb(this.value);
});
}
}
我們可以使用tester()
函數測試當前代碼。
(function tester() {
const p = new Promise(resolve => {
setTimeout(() => resolve(123), 1000);
});
const p1 = p.then(x => console.log(x));
const p2 = p.then(x => setTimeout(() => console.log(x), 1000));
})();
// 123 <delayed by 1 second>
// 123 <delayed by 1 more second>
到此為止我們的基礎。 現在,我們可以實現鏈接。 我們面臨的最大問題是, then()
方法必須同步返回promise,該promise將異步解決。
我們需要等待父承諾解決,然后才能解決下一個承諾 。 這意味着,除了向父諾言中添加cb()
,我們還必須添加下一個諾言的resolve()
方法,該方法使用cb()
返回值作為resolveValue
。
then(cb) {
- this.callbacks.push(cb);
+ const next = new Promise(resolve => {
+ this.callbacks.push(x => resolve(cb(x)));
+ });
+
+ return next;
}
如果這最后一點使您感到困惑,那么這里有一些提示:
Promise
構造函數接受main()
函數作為參數 main()
將函數resolve()
作為參數
resolve()
由Promise
構造函數提供 resolve()
將任何類型的參數用作resolveValue
class Promise {
constructor(main) {
this.value = undefined;
this.callbacks = [];
const resolve = resolveValue => {
this.value = resolveValue;
this.triggerCallbacks();
};
main(resolve);
}
then(cb) {
const next = new Promise(resolve => {
this.callbacks.push(x => resolve(cb(x)));
});
return next;
}
triggerCallbacks() {
this.callbacks.forEach(cb => {
cb(this.value);
});
}
}
(function tester() {
const p = new Promise(resolve => {
setTimeout(() => resolve(123), 1000);
});
const p1 = p.then(x => console.log(x));
const p2 = p.then(x => setTimeout(() => console.log(x), 1000));
const p3 = p2.then(x => setTimeout(() => console.log(x), 100));
const p4 = p.then((x) => new Promise(resolve => {
setTimeout(() => resolve(x), 1000);
}))
/*
p: resolve after (1s) with resolveValue = 123
p1: resolve after (0s) after p resolved with resolveValue = undefined
p2: resolve after (0s) after p resolved with resolveValue = timeoutID
p3: resolve after (0s) after p2 resolved with resolveValue = timeoutID
p4: resolve after (1s) after p resolved with resolveValue = Promise instance
*/
})();
// 123 <delayed by 1s>
// 2 <delayed by 1.1s>
// 123 <delayed by 2s>
我在客戶端js中使用Promise
,但在舊的瀏覽器中卻發現該類不存在。 因此,我為他們實施了具有resolve
和reject
方法的resolve
。
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
var Promise = function () {
function Promise(main) {
var _this = this;
_classCallCheck(this, Promise);
this.value = undefined;
this.callbacks = [];
var resolve = function resolve(resolveValue) {
_this.value = resolveValue;
_this.triggerCallbacks();
};
var reject = function reject(rejectValue) {
_this.value = rejectValue;
_this.triggerCallbacks();
};
main(resolve, reject);
}
Promise.prototype.then = function then(cb) {
var _this2 = this;
var next = new Promise(function (resolve) {
_this2.callbacks.push(function (x) {
return resolve(cb(x));
});
});
return next;
};
Promise.prototype.catch = function catch_(cb) {
var _this2 = this;
var next = new Promise(function (reject) {
_this2.callbacks.push(function (x) {
return reject(cb(x));
});
});
return next;
};
Promise.prototype.triggerCallbacks = function triggerCallbacks() {
var _this3 = this;
this.callbacks.forEach(function (cb) {
cb(_this3.value);
});
};
return Promise;
}();
解決該問題,在Promise中進行通話同步時:
class MyPromise{
constructor(fn){
this.callback= null;
this.data= null;
this.calledInNext= false;
fn((data, state)=>{ // unsafe when call resolve({}, 'string')
this.calledInNext= (state === 'CALLED_IN_NEXT') ? true : false;
this.data= data;
if(this.callback) this.callback(this.data);
}, function(_err){
console.log('resolve({error}) to without catch')
})
}
then(cb){ // next
if(this.data || this.calledInNext){
return new MyPromise(r => {
r(cb(this.data), 'CALLED_IN_NEXT');
});
} else {
return new MyPromise(r => {
this.callback = x=> r(cb(x))
})
}
}
}
或連鎖:
class MyPromise{
constructor(fn){
this.callbacks= [];
this.data= null;
fn((data)=>{
this.data= data;
var gg= this.data;
this.callbacks.forEach(el=>{
gg= el(gg);
})
})
}
then(cb){
if(this.data || this._calledInNext){
this._calledInNext= true; this.data= cb(this.data); return this;
} else {
this.callbacks.push(cb); return this;
}
}
}
測試:
(new MyPromise(function(resolve, reject){
// setTimeout(resolve, 1000, {done: 1})
resolve({done: 1})
})).then(data=>{
console.log(data); // {done: 1}
return data;
}).then(data=>{
console.log(data); // {done: 1}
return {};
}).then(data=>{
console.log(data); // {}
}).then(data=>{
console.log(data); // undefine
}).then(data=>{
console.log(data); // undefine
}).then(data=>{
console.log(data); // undefine
})
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.