Promise (Promise Chain)Callback Hell, bằng cách xử lý gọi lệnh từng dòng chạy song song, dễ nhìn và dễ chỉnh sửa.var newPromise = new Promise((resolve, reject) => {
resolve('Resolve');
});
newPromise
.then((result) => console.log('Successfully: ', result))
.catch((error) => console.error(error + ''));
handle của Promise với nhiều khối lệnh .then liên tiếpvar newPromise = new Promise((resolve, reject) => {
resolve('Success!');
});
newPromise
.then(() => console.log(1)) // Line 1
.then(() => console.log(2)) // Line 2
.then(() => console.log(3)) // Line 3
.catch((error) => console.error(error + ''))
.finally(() => console.log('Done!'));

.then thứ nhất, sẽ chạy tiếp .then thứ 2 rồi mới chạy tiếp .then thứ ba.handle của Promise với nhiều khối lệnh .then liên tiếp, trong đó có xử lý setTimeOut để kiểm tra các .then là xử lý bất đồng bộ hay đồng bộ.var newPromise = new Promise((resolve, reject) => {
resolve('Success!');
});
newPromise
.then(() => console.log(1)) // Line 1
.then(() => {
setTimeout(() => {
console.log(2); // Line 2
}, 1000);
})
.then(() => console.log(3)) // Line 3
.catch(() => console.error('Error!'))
.finally(() => console.log('Done!'));

.then thì xử lý ở đây vẫn là bất đồng bộ không theo thứ tự từng khối line..then trong chuỗi (Promise Chain)var newPromise = new Promise((resolve, reject) => {
resolve();
});
//prettier-ignore
newPromise
.then(function () {
console.log('Line1'); // Line 1
})
.then(function (data) {
console.log('Line2 : ', data); // Line 2
return 2
})
.then(function (data) {
console.log('Line3 : ', data); // Line 3
})
.catch(() => console.error('Error!'))
.finally(() => console.log('Done!'));

.then phía trước nếu không return một giá trị thì tham số data của khối lệnh .then trong callback kế tiếp sẽ là giá trị Undefinedvar newPromise = new Promise((resolve, reject) => {
resolve('Success!');
});
newPromise
.then((rs) => {
console.log(rs); // line Success
return 1;
})
.then((line2) => {
console.log(line2); // line 1
return 2;
})
.then((line3) => {
console.log(line3); // line 2
return 3;
})
.then((line4) => {
console.log(line4); // line 3
})
.catch(() => console.error('Error!'))
.finally(() => console.log('Done!'));

return của khối lệnh .then callback phía trước sẽ trở thành tham số của khối lệnh .then trong callback phía sau..then liên tiếp có return giá trị, và có setTimeOut để kiểm tra kế thừa giá trị và bất đồng bộ hay đồng bộ.var newPromise = new Promise((resolve, reject) => {
resolve('Success!');
});
newPromise
.then((rs) => {
setTimeout(() => {
console.log('Line 1: ', rs); // line 1
return 1;
}, 4000);
})
.then((line2) => {
setTimeout(() => {
console.log('Line 2: ', line2); // line 2
return 2;
}, 3000);
})
.then((line3) => {
setTimeout(() => {
console.log('Line 3: ', line3); // line 3
return 3;
}, 2000);
})
.then((line4) => {
setTimeout(() => {
console.log('Line 4: ', line4); // line 4
}, 1000);
})
.catch(() => console.error('Error!'))
.finally(() => console.log('Done!'));

return một Promise thì sẽ chạy xử lý tiếp ở .then kế tiếp mà không chờ xử lý.var newPromise = new Promise((resolve, reject) => {
resolve('Success!');
});
newPromise
.then((rs) => {
setTimeout(() => {
return 1;
}, 4000);
})
.then((data) => {
setTimeout(() => {
console.log('Line 2: ', data); // line 2
return 2;
}, 3000);
})
.then((data) => {
setTimeout(() => {
console.log('Line 3: ', data); // line 3
return 3;
}, 2000);
})
.then((data) => {
setTimeout(() => {
console.log('Line 4: ', data); // line 4
}, 1000);
})
.catch(() => console.error('Error!'))
.finally(() => console.log('Done!'));

.then này vẫn chạy theo tính chất đồng bộ và nếu không chạy xử lý .then phía trước không return đối tượng Promise.var newPromise = new Promise((resolve, reject) => {
resolve('Success!');
});
newPromise
.then((data) => {
setTimeout(() => {
return new Promise((resolve) => {
console.log('Line 1: ', data); // Line 1
resolve(2);
});
}, 2000);
})
.then((data) => {
setTimeout(() => {
return new Promise((resolve) => {
console.log('Line 2: ', data); // Line 2
resolve(3);
});
}, 1000);
})
.then((data) => {
console.log('Line 3: ', data); // Line 3
})
.catch(() => console.error('Error!'))
.finally(() => console.log('Done!'));

Ta thấy các khối lệnh .then do chạy setTimeout trước nên bị lướt qua chạy bất đồng bộ, sau đó chạy tiếp các .then kế tiếp mà không chờ xử lý Promise trong khối lệnh setTimeout
Như vậy nếu khối lệnh .then không xử lý return trả về một đối tượng Promise thì vẫn chạy theo kiểu đồng bộ chạy tiếp câu lệnh kế tiếp, nếu có xử lý setTimeOut thì sẽ chạy ngầm và chạy tiếp xử lý ở .then kế tiếp mà không dừng lại chờ.
var newPromise = new Promise((resolve, reject) => {
resolve('Success!');
});
newPromise
.then((data) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('Line 1: ', data); // Line 1
resolve(1);
}, 3000);
});
})
.then((data) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('Line 2: ', data); // Line 2
resolve(2);
}, 2000);
});
})
.then((data) => {
console.log('Line 3: ', data); // Line 3
})
.catch(() => console.error('Error!'))
.finally(() => console.log('Done!'));

.then xử lý return trả về một Promise thì các khối lệnh .then chạy theo xử lý Đồng bộ theo thứ tự và chờ xử lý xong câu lệnh .then phía trước mới chạy tiếp các khối lệnh .then kế tiếp.var newPromise = new Promise((resolve, reject) => {
resolve();
});
//prettier-ignore
newPromise
.then(function () {
return new Promise((resolve) => {
console.log('Line1'); // Line 1
setTimeout(resolve,3000)
})
})
.then(function (data) {
console.log('Line2'); // Line 2
return 2
})
.then(function (data) {
console.log('Line3 : ', data); // Line 3
})
.catch(() => console.error('Error!'))
.finally(() => console.log('Done!'));

Reject() để kiểm tra kết quả trả về.var newPromise = new Promise((resolve, reject) => {
resolve();
});
//prettier-ignore
newPromise
.then(function () {
return new Promise((resolve) => {
console.log('Line1'); // Line 1
setTimeout(() => {
resolve(2);
},3000)
})
})
.then(function (data) {
return new Promise((resolve, reject) => {
console.log('Line2: ', data); // Line 2
setTimeout(() => {
reject("Error1") // Rejected 1
},2000)
})
})
.then(function (data) {
return new Promise((resolve) => {
console.log('Line3: ', data); // Line3
setTimeout(() => {
resolve(3) // Resolve
},2000)
})
})
.catch((error) => console.error('Error 1: ', error))
.then(function (data) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('Line4: ', data); // Line 4
reject("Error1") // Rejected 2
},2000)
})
})
.catch((error) => console.error('Error: ',error)) // Rejected Catch
.finally(() => console.log('Done!'));

Reject() của .then thì sẽ tìm khối lệnh .catch gần nhất để xử lý, sau đó chạy tiếp khối lệnh .then phía sau của .catchvar newPromise = new Promise((resolve, reject) => {
resolve();
});
//prettier-ignore
newPromise
.then(function () {
return new Promise((resolve) => {
console.log('Line1'); // Line 1
setTimeout(() => {
resolve(2);
},3000)
})
})
.then(function (data) {
return new Promise((resolve, reject) => {
console.log('Line2: ', data); // Line 2
setTimeout(() => {
reject("Error1") // Rejected 1
},2000)
})
})
.then(function (data) {
return new Promise((resolve) => {
console.log('Line3: ', data); // Line 3
setTimeout(() => {
resolve(3)
},2000)
})
})
.then(function (data) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('Line4: ', data); // Line 4
reject("Error1")
},2000)
})
})
.catch((error) => console.error('Error: ',error))
.finally(() => console.log('Done!'));

Reject() thì sẽ nhảy đến xử lý ở khối lệnh .catch gần nhất, nếu sau khối lệnh .catch không có khối lệnh .then thì xử lý handle đối tượng newPromise sẽ được dừng lại..then khi trả về đối tượng Promise thì có thể dùng chung một khối lệnh .catch và từ khối lệnh .then được return sẽ không chạy xử lý tiếp các khối lệnh .then còn lại, như vậy chuỗi .then hay tính chất chuỗi của Promise Chain sẽ được dừng lại khi gặp xử lý .then return trả về một đối tượng Promise bị Rejected thì sẽ dừng lại không xử lý tiếp các khối lệnh .then tiếp theo phía sau.Bài tập: In ra màn hình các số theo thứ tự sau mỗi giây, không dùng setInterval.
function sleep(ms) {
return new Promise(function (resolve) {
setTimeout(() => {
return resolve();
}, ms);
});
}
function sleep(ms) {
return new Promise(function (resolve) {
setTimeout(resolve, ms);
});
}
sleep(1000)
.then(function (data) {
console.log(1);
return sleep(1000);
})
.then(function (data) {
console.log(2);
return sleep(1000);
})
.then(function (data) {
console.log(3);
return sleep(1000);
})
.then(function (data) {
console.log(4);
return sleep(1000);
})
.then(function (data) {
console.log(5);
return sleep(1000);
})
.catch((error) => console.error('Error: ', error))
.finally(() => console.log('Done!'));
function sleep(ms, data) {
return new Promise(function (resolve) {
setTimeout(() => resolve(++data), ms);
});
}
sleep(1000, 0)
.then(function (data) {
console.log(data);
return sleep(1000, data);
})
.then(function (data) {
console.log(data);
return sleep(1000, data);
})
.then(function (data) {
console.log(data);
return sleep(1000, data);
})
.then(function (data) {
console.log(data);
return sleep(1000, data);
})
.then(function (data) {
console.log(data);
return sleep(1000, data);
})
.then(function (data) {
console.log(data);
return sleep(1000, data);
})
.catch((error) => console.error('Error: ', error))
.finally(() => console.log('Done!'));
Arrow Function sẽ viết gọn lại như sau:function printLog(ms, count) {
return new Promise((resolve, reject) => {
setTimeout(() => {
count++;
console.log(count);
return resolve(count);
}, ms);
});
}
printLog(1000, 0)
.then((data) => printLog(1000, data))
.then((data) => printLog(1000, data))
.then((data) => printLog(1000, data))
.then((data) => printLog(1000, data))
.then((data) => printLog(1000, data))
.then((data) => printLog(1000, data))
.then((data) => printLog(1000, data))
.then((data) => printLog(1000, data))
.then((data) => printLog(1000, data))
.catch((error) => console.error('Error: ', error))
.finally(() => console.log('Done!'));
