æä»¬å顾ä¸ä¸ ç®ä»ï¼åè° ä¸ç« 䏿å°çé®é¢ï¼æä»¬æä¸ç³»åç弿¥ä»»å¡è¦ä¸ä¸ªæ¥ä¸ä¸ªå°æ§è¡ ââ ä¾å¦ï¼å è½½èæ¬ãæä»¬å¦ä½ååºæ´å¥½ç代ç å¢ï¼
Promise æä¾äºä¸äºæ¹æ¡æ¥åå°è¿ä¸ç¹ã
卿¬ç« ä¸ï¼æä»¬å°ä¸èµ·å¦ä¹ promise é¾ã
å®çèµ·æ¥å°±åè¿æ ·ï¼
new Promise(function(resolve, reject) {
setTimeout(() => resolve(1), 1000); // (*)
}).then(function(result) { // (**)
alert(result); // 1
return result * 2;
}).then(function(result) { // (***)
alert(result); // 2
return result * 2;
}).then(function(result) {
alert(result); // 4
return result * 2;
});
å®çæ³æ³æ¯éè¿ .then å¤çç¨åºï¼handlerï¼é¾è¿è¡ä¼ é resultã
è¿è¡æµç¨å¦ä¸ï¼
- åå§ promise å¨ 1 ç§å resolve
(*)ï¼ - ç¶å
.thenå¤çç¨åºè¢«è°ç¨(**)ï¼å®åå建äºä¸ä¸ªæ°ç promiseï¼ä»¥2ä½ä¸ºå¼ resolveï¼ã - ä¸ä¸ä¸ª
then(***)å¾å°äºåä¸ä¸ªthençå¼ï¼å¯¹è¯¥å¼è¿è¡å¤çï¼*2ï¼å¹¶å°å ¶ä¼ éç»ä¸ä¸ä¸ªå¤çç¨åºã - â¦â¦ä¾æ¤ç±»æ¨ã
éç result å¨å¤çç¨åºé¾ä¸ä¼ éï¼æä»¬å¯ä»¥çå°ä¸ç³»åç alert è°ç¨ï¼1 â 2 â 4ã
è¿æ ·ä¹æä»¥æ¯å¯è¡çï¼æ¯å 为æ¯ä¸ªå¯¹ .then çè°ç¨é½ä¼è¿åäºä¸ä¸ªæ°ç promiseï¼å æ¤æä»¬å¯ä»¥å¨å
¶ä¹ä¸è°ç¨ä¸ä¸ä¸ª .thenã
å½å¤çç¨åºè¿åä¸ä¸ªå¼æ¶ï¼å®å°æä¸ºè¯¥ promise ç resultï¼æä»¥å°ä½¿ç¨å®è°ç¨ä¸ä¸ä¸ª .thenã
æ°æå¸¸ç¯çä¸ä¸ªç»å
¸é误ï¼ä»ææ¯ä¸è®²ï¼æä»¬ä¹å¯ä»¥å°å¤ä¸ª .then æ·»å å°ä¸ä¸ª promise ä¸ãä½è¿å¹¶ä¸æ¯ promise é¾ï¼chainingï¼ã
ä¾å¦ï¼
let promise = new Promise(function(resolve, reject) {
setTimeout(() => resolve(1), 1000);
});
promise.then(function(result) {
alert(result); // 1
return result * 2;
});
promise.then(function(result) {
alert(result); // 1
return result * 2;
});
promise.then(function(result) {
alert(result); // 1
return result * 2;
});
æä»¬å¨è¿éæåçåªæ¯ä¸ä¸ª promise çå 个å¤çç¨åºãå®ä»¬ä¸ä¼ç¸äºä¼ é resultï¼ç¸åï¼å®ä»¬ä¹é´å½¼æ¤ç¬ç«è¿è¡å¤çä»»å¡ã
è¿æ¯å®çä¸å¼ 示æå¾ï¼ä½ å¯ä»¥å°å ¶ä¸ä¸é¢çé¾å¼è°ç¨åä¸ä¸æ¯è¾ï¼ï¼
å¨åä¸ä¸ª promise ä¸çææ .then è·å¾çç»æé½ç¸å ââ 该 promise çç»æãæä»¥ï¼å¨ä¸é¢ç代ç ä¸ï¼ææ alert 齿¾ç¤ºç¸åçå
容ï¼1ã
å®é 䏿们æå°éå°ä¸ä¸ª promise éè¦å¤ä¸ªå¤çç¨åºçæ åµã使ç¨é¾å¼è°ç¨çé¢çæ´é«ã
è¿å promise
.then(handler) ä¸æä½¿ç¨çå¤çç¨åºï¼handlerï¼å¯ä»¥å建并è¿åä¸ä¸ª promiseã
å¨è¿ç§æ åµä¸ï¼å ¶ä»çå¤çç¨åºå°çå¾ å® settled ååè·å¾å ¶ç»æã
ä¾å¦ï¼
new Promise(function(resolve, reject) {
setTimeout(() => resolve(1), 1000);
}).then(function(result) {
alert(result); // 1
return new Promise((resolve, reject) => { // (*)
setTimeout(() => resolve(result * 2), 1000);
});
}).then(function(result) { // (**)
alert(result); // 2
return new Promise((resolve, reject) => {
setTimeout(() => resolve(result * 2), 1000);
});
}).then(function(result) {
alert(result); // 4
});
è¿é第ä¸ä¸ª .then æ¾ç¤º 1 å¹¶å¨ (*) è¡è¿å new Promise(â¦)ã1 ç§åå®ä¼è¿è¡ resolveï¼ç¶å resultï¼resolve çåæ°ï¼å¨è¿é宿¯ result*2ï¼è¢«ä¼ éç»ç¬¬äºä¸ª .then çå¤çç¨åºãè¿ä¸ªå¤çç¨åºä½äº (**) è¡ï¼å®æ¾ç¤º 2ï¼å¹¶æ§è¡ç¸åçè¡ä¸ºã
æä»¥è¾åºä¸åé¢ç示ä¾ç¸åï¼1 â 2 â 4ï¼ä½æ¯ç°å¨å¨æ¯æ¬¡ alert è°ç¨ä¹é´ä¼æ 1 ç§éçå»¶è¿ã
è¿å promise 使æä»¬è½å¤æå»ºå¼æ¥è¡ä¸ºé¾ã
示ä¾ï¼loadScript
让æä»¬å°æ¬ç« æè®²çè¿ä¸ªç¹æ§ä¸å¨ ä¸ä¸ç« ä¸å®ä¹ç promise åç loadScript ç»å使ç¨ï¼æé¡ºåºä¾æ¬¡å è½½èæ¬ï¼
loadScript("/article/promise-chaining/one.js")
.then(function(script) {
return loadScript("/article/promise-chaining/two.js");
})
.then(function(script) {
return loadScript("/article/promise-chaining/three.js");
})
.then(function(script) {
// 使ç¨å¨èæ¬ä¸å£°æç彿°
// ä»¥è¯æèæ¬ç¡®å®è¢«å è½½å®æäº
one();
two();
three();
});
æä»¬å¯ä»¥ç¨ç®å¤´å½æ°æ¥éå代ç ï¼è®©å ¶åå¾ç®çä¸äºï¼
loadScript("/article/promise-chaining/one.js")
.then(script => loadScript("/article/promise-chaining/two.js"))
.then(script => loadScript("/article/promise-chaining/three.js"))
.then(script => {
// èæ¬å è½½å®æï¼æä»¬å¯ä»¥å¨è¿å¿ä½¿ç¨èæ¬ä¸å£°æç彿°
one();
two();
three();
});
å¨è¿å¿ï¼æ¯ä¸ª loadScript è°ç¨é½è¿åä¸ä¸ª promiseï¼å¹¶ä¸å¨å® resolve æ¶ä¸ä¸ä¸ª .then å¼å§è¿è¡ãç¶åï¼å®å¯å¨ä¸ä¸ä¸ªèæ¬çå è½½ãæä»¥ï¼èæ¬æ¯ä¸ä¸ªæ¥ä¸ä¸ªå°å è½½çã
æä»¬å¯ä»¥åé¾ä¸æ·»å æ´å¤ç弿¥è¡ä¸ºã请注æï¼ä»£ç ä»ç¶æ¯âæå¹³âç ââ å®åä¸å¢é¿ï¼è䏿¯åå³ãè¿é没æâåè¿éåå¡âç迹象ã
仿æ¯ä¸è®²ï¼æä»¬å¯ä»¥åæ¯ä¸ª loadScript ç´æ¥æ·»å .thenï¼å°±åè¿æ ·ï¼
loadScript("/article/promise-chaining/one.js").then(script1 => {
loadScript("/article/promise-chaining/two.js").then(script2 => {
loadScript("/article/promise-chaining/three.js").then(script3 => {
// æ¤å½æ°å¯ä»¥è®¿é®åé script1ï¼script2 å script3
one();
two();
three();
});
});
});
è¿æ®µä»£ç åäºç¸åçäºå¿ï¼æé¡ºåºå è½½ 3 ä¸ªèæ¬ãä½å®æ¯âåå³å¢é¿âçãæä»¥ä¼æå使ç¨åè°å½æ°ä¸æ ·çé®é¢ã
åå¼å§ä½¿ç¨ promise ç人å¯è½ä¸ç¥é promise é¾ï¼æä»¥ä»ä»¬å°±è¿æ ·åäºãé常ï¼é¾å¼æ¯é¦éã
ææ¶åç´æ¥å .then 乿¯å¯ä»¥çï¼å 为åµå¥ç彿°å¯ä»¥è®¿é®å¤é¨ä½ç¨åãå¨ä¸é¢çä¾åä¸ï¼åµå¥å¨ææ·±å±çé£ä¸ªåè°ï¼callbackï¼å¯ä»¥è®¿é®ææåé script1ï¼script2 å script3ãä½è¿æ¯ä¸ä¸ªä¾å¤ï¼è䏿¯ä¸æ¡è§åã
ç¡®åå°è¯´ï¼å¤çç¨åºè¿åçä¸å®å
¨æ¯ä¸ä¸ª promiseï¼èæ¯è¿åç被称为 âthenableâ 对象 ââ ä¸ä¸ªå
·ææ¹æ³ .then çä»»æå¯¹è±¡ãå®ä¼è¢«å½åä¸ä¸ª promise æ¥å¯¹å¾
ã
è¿ä¸ªæ³æ³æ¯ï¼ç¬¬ä¸æ¹åºå¯ä»¥å®ç°èªå·±çâpromise å
¼å®¹ï¼promise-compatibleï¼â对象ãå®ä»¬å¯ä»¥å
·ææ©å±çæ¹æ³éï¼ä½ä¹ä¸åçç promise å
¼å®¹ï¼å 为å®ä»¬å®ç°äº .then æ¹æ³ã
è¿æ¯ä¸ä¸ª thenable 对象ç示ä¾ï¼
class Thenable {
constructor(num) {
this.num = num;
}
then(resolve, reject) {
alert(resolve); // function() { native code }
// 1 ç§åä½¿ç¨ this.num*2 è¿è¡ resolve
setTimeout(() => resolve(this.num * 2), 1000); // (**)
}
}
new Promise(resolve => resolve(1))
.then(result => {
return new Thenable(result); // (*)
})
.then(alert); // 1000ms åæ¾ç¤º 2
JavaScript æ£æ¥å¨ (*) è¡ä¸ç± .then å¤çç¨åºè¿åç对象ï¼å¦æå®å
·æå为 then çå¯è°ç¨æ¹æ³ï¼é£ä¹å®å°è°ç¨è¯¥æ¹æ³å¹¶æä¾åçç彿° resolve å reject ä½ä¸ºåæ°ï¼ç±»ä¼¼äº executorï¼ï¼å¹¶çå¾
ç´å°å
¶ä¸ä¸ä¸ªå½æ°è¢«è°ç¨ãå¨ä¸é¢ç示ä¾ä¸ï¼resolve(2) å¨ 1 ç§å被è°ç¨ (**)ãç¶åï¼result ä¼è¢«è¿ä¸æ¥æ²¿çé¾åä¸ä¼ éã
è¿ä¸ªç¹æ§å
许æä»¬å°èªå®ä¹çå¯¹è±¡ä¸ promise é¾éæå¨ä¸èµ·ï¼èä¸å¿
ç»§æ¿èª Promiseã
æ´å¤æç示ä¾ï¼fetch
å¨å端ç¼ç¨ä¸ï¼promise é常被ç¨äºç½ç»è¯·æ±ãé£ä¹ï¼è®©æä»¬ä¸èµ·æ¥çä¸ä¸ªç¸å ³çæ©å±ç¤ºä¾å§ã
æä»¬å°ä½¿ç¨ fetch æ¹æ³ä»è¿ç¨æå¡å¨å è½½ç¨æ·ä¿¡æ¯ã宿å¾å¤å¯éçåæ°ï¼æä»¬å¨ åç¬çä¸ç« ä¸å¯¹å ¶è¿è¡äºè¯¦ç»ä»ç»ï¼ä½åºæ¬è¯æ³å¾ç®åï¼
let promise = fetch(url);
æ§è¡è¿æ¡è¯å¥ï¼å url ååºç½ç»è¯·æ±å¹¶è¿åä¸ä¸ª promiseãå½è¿ç¨æå¡å¨è¿å headerï¼æ¯å¨ å
¨é¨ååºå è½½å®æåï¼æ¶ï¼è¯¥ promise 使ç¨ä¸ä¸ª response 对象æ¥è¿è¡ resolveã
为äºè¯»å宿´çååºï¼æä»¬åºè¯¥è°ç¨ response.text() æ¹æ³ï¼å½å
¨é¨æåå
容ä»è¿ç¨æå¡å¨ä¸è½½å®æåï¼å®ä¼è¿åä¸ä¸ª promiseï¼è¯¥ promise 以ååä¸è½½å®æçè¿ä¸ªææ¬ä½ä¸º result è¿è¡ resolveã
ä¸é¢è¿æ®µä»£ç å user.json åé请æ±ï¼å¹¶ä»æå¡å¨å è½½è¯¥ææ¬ï¼
fetch('/article/promise-chaining/user.json')
// å½è¿ç¨æå¡å¨ååºæ¶ï¼ä¸é¢ç .then å¼å§æ§è¡
.then(function(response) {
// å½ user.json å è½½å®ææ¶ï¼response.text() ä¼è¿åä¸ä¸ªæ°ç promise
// 该 promise 以å è½½ç user.json 为 result è¿è¡ resolve
return response.text();
})
.then(function(text) {
// â¦â¦è¿æ¯è¿ç¨æä»¶çå
容
alert(text); // {"name": "iliakan", "isAdmin": true}
});
ä» fetch è¿åç response 对象è¿å
å« response.json() æ¹æ³ï¼è¯¥æ¹æ³å¯ä»¥è¯»åè¿ç¨æ°æ®å¹¶å°å
¶è§£æä¸º JSONã卿们çä¾åä¸ï¼è¿æ´å æ¹ä¾¿ï¼æä»¥æä»¬ç¨è¿ä¸ªæ¹æ³å§ã
为äºç®æ´ï¼æä»¬è¿å°ä½¿ç¨ç®å¤´å½æ°ï¼
// åä¸ï¼ä½ä½¿ç¨ response.json() å°è¿ç¨å
容解æä¸º JSON
fetch('/article/promise-chaining/user.json')
.then(response => response.json())
.then(user => alert(user.name)); // iliakanï¼è·åå°äºç¨æ·å
ç°å¨ï¼è®©æä»¬ç¨å 载好çç¨æ·ä¿¡æ¯æç¹äºæ ã
ä¾å¦ï¼æä»¬å¯ä»¥åå GitHub åéä¸ä¸ªè¯·æ±ï¼å è½½ç¨æ·ä¸ªäººèµæå¹¶æ¾ç¤ºå¤´åï¼
// åéä¸ä¸ªå¯¹ user.json ç请æ±
fetch('/article/promise-chaining/user.json')
// å°å
¶å 载为 JSON
.then(response => response.json())
// åéä¸ä¸ªå° GitHub ç请æ±
.then(user => fetch(`https://api.github.com/users/${user.name}`))
// å°ååºå 载为 JSON
.then(response => response.json())
// æ¾ç¤ºå¤´åå¾çï¼githubUser.avatar_urlï¼3 ç§ï¼ä¹å¯ä»¥å ä¸å¨ç»ææï¼
.then(githubUser => {
let img = document.createElement('img');
img.src = githubUser.avatar_url;
img.className = "promise-avatar-example";
document.body.append(img);
setTimeout(() => img.remove(), 3000); // (*)
});
è¿æ®µä»£ç å¯ä»¥å·¥ä½ï¼å ·ä½ç»èè¯·çæ³¨éã使¯ï¼è¿æä¸ä¸ªæ½å¨çé®é¢ï¼ä¸ä¸ªæ°æä½¿ç¨ promise æ¶çå ¸åé®é¢ã
请ç (*) è¡ï¼æä»¬å¦ä½è½å¨å¤´åæ¾ç¤ºç»æå¹¶è¢«ç§»é¤ ä¹å åç¹ä»ä¹ï¼ä¾å¦ï¼æä»¬æ³æ¾ç¤ºä¸ä¸ªç¨äºç¼è¾è¯¥ç¨æ·æè
å
¶ä»å
容ç表åãå°±ç®åèè¨ï¼æ¯åä¸å°çã
为äºä½¿é¾å¯æ©å±ï¼æä»¬éè¦è¿åä¸ä¸ªå¨å¤´åæ¾ç¤ºç»ææ¶è¿è¡ resolve ç promiseã
å°±åè¿æ ·ï¼
fetch('/article/promise-chaining/user.json')
.then(response => response.json())
.then(user => fetch(`https://api.github.com/users/${user.name}`))
.then(response => response.json())
.then(githubUser => new Promise(function(resolve, reject) { // (*)
let img = document.createElement('img');
img.src = githubUser.avatar_url;
img.className = "promise-avatar-example";
document.body.append(img);
setTimeout(() => {
img.remove();
resolve(githubUser); // (**)
}, 3000);
}))
// 3 ç§å触å
.then(githubUser => alert(`Finished showing ${githubUser.name}`));
ä¹å°±æ¯è¯´ï¼ç¬¬ (*) è¡ç .then å¤çç¨åºç°å¨è¿åä¸ä¸ª new Promiseï¼åªæå¨ setTimeout ä¸ç resolve(githubUser) (**) 被è°ç¨åæä¼å为 settledãé¾ä¸çä¸ä¸ä¸ª .then å°ä¸ç´çå¾
è¿ä¸æ¶å»çå°æ¥ã
ä½ä¸ºä¸ä¸ªå¥½çåæ³ï¼å¼æ¥è¡ä¸ºåºè¯¥å§ç»è¿åä¸ä¸ª promiseãè¿æ ·å°±å¯ä»¥ä½¿å¾ä¹åæä»¬è®¡ååç»çè¡ä¸ºæä¸ºå¯è½ãå³ä½¿æä»¬ç°å¨ä¸æç®å¯¹é¾è¿è¡æ©å±ï¼ä½æä»¬ä¹åå¯è½ä¼éè¦ã
æåï¼æä»¬å¯ä»¥å°ä»£ç æå为å¯éç¨ç彿°ï¼
function loadJson(url) {
return fetch(url)
.then(response => response.json());
}
function loadGithubUser(name) {
return loadJson(`https://api.github.com/users/${name}`);
}
function showAvatar(githubUser) {
return new Promise(function(resolve, reject) {
let img = document.createElement('img');
img.src = githubUser.avatar_url;
img.className = "promise-avatar-example";
document.body.append(img);
setTimeout(() => {
img.remove();
resolve(githubUser);
}, 3000);
});
}
// 使ç¨å®ä»¬ï¼
loadJson('/article/promise-chaining/user.json')
.then(user => loadGithubUser(user.name))
.then(showAvatar)
.then(githubUser => alert(`Finished showing ${githubUser.name}`));
// ...
æ»ç»
妿 .thenï¼æ catch/finally é½å¯ä»¥ï¼å¤çç¨åºè¿åä¸ä¸ª promiseï¼é£ä¹é¾çå
¶ä½é¨åå°ä¼çå¾
ï¼ç´å°å®ç¶æå为 settledãå½å®è¢« settled åï¼å
¶ resultï¼æ errorï¼å°è¢«è¿ä¸æ¥ä¼ éä¸å»ã
è¿æ¯ä¸ä¸ªå®æ´çæµç¨å¾ï¼
è¯è®º
<code>æ ç¾æå ¥åªæå 个è¯ç代ç ï¼æå ¥å¤è¡ä»£ç å¯ä»¥ä½¿ç¨<pre>æ ç¾ï¼å¯¹äºè¶ è¿ 10 è¡ç代ç ï¼å»ºè®®ä½ ä½¿ç¨æ²ç®±ï¼plnkrï¼JSBinï¼codepenâ¦ï¼