成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

學(xué)習(xí) Promise,掌握未來世界 JS 異步編程基礎(chǔ)

Vicky / 433人閱讀

摘要:構(gòu)造函數(shù)規(guī)定,對(duì)象是一個(gè)構(gòu)造函數(shù),用來生成實(shí)例。如果中的回調(diào)函數(shù)拋出一個(gè)錯(cuò)誤,那么返回的將會(huì)成為拒絕狀態(tài),并且將拋出的錯(cuò)誤作為拒絕狀態(tài)的回調(diào)函數(shù)的參數(shù)值。

其實(shí)想寫 Promise 的使用已經(jīng)很長時(shí)間了。一個(gè)是在實(shí)際編碼的過程中經(jīng)常用到,一個(gè)是確實(shí)有時(shí)候小伙伴們?cè)谑褂脮r(shí)也會(huì)遇到一些問題。
Promise 也確實(shí)是 ES6 中 對(duì)于寫 JS 的方式,有著真正最大影響的 API 特性之一。
本文是實(shí)際使用使用過程中的一個(gè)總結(jié)
看一下文件創(chuàng)建時(shí)間 2017-10-09,拖延癥真是太可怕了。。。還是得增強(qiáng)執(zhí)行力啊!不忘初心,加油吧!
博客原址
前言 && 基礎(chǔ)概念

Promise 是解決 JS 異步的一種方案,相比傳統(tǒng)的回調(diào)函數(shù),Promise 能解決多個(gè)回調(diào)嚴(yán)重嵌套的問題。

Promise 對(duì)象代表一個(gè)異步操作,有三種狀態(tài): pending、fulfilled 或 rejected ,狀態(tài)的轉(zhuǎn)變只能是 pending -> fulfilled 或者 pending -> rejected ,且這個(gè)過程一旦發(fā)生就不可逆轉(zhuǎn)

個(gè)人認(rèn)為講解 Promise 實(shí)際上需要分成兩個(gè)部分

對(duì)于 Promise 構(gòu)造函數(shù)的使用說明。

Promise 原型對(duì)象上的一些方法。

Promise 構(gòu)造函數(shù)

ES6 規(guī)定,Promise 對(duì)象是一個(gè)構(gòu)造函數(shù),用來生成 Promise 實(shí)例。

Promise 構(gòu)造函數(shù)接受一個(gè)函數(shù)作為參數(shù),該函數(shù)的兩個(gè)參數(shù)分別是 resolve 和 reject 。它們是兩個(gè)函數(shù),由 JavaScript 引擎提供,不用自己部署。

resolve 函數(shù)的作用是將 Promise 對(duì)象的狀態(tài)從“未完成”變?yōu)椤俺晒Α保磸?pending 變?yōu)?fulfilled ),在異步操作成功時(shí)調(diào)用,并將異步操作的結(jié)果,作為參數(shù)傳遞出去;
reject 函數(shù)的作用是,將 Promise 對(duì)象的狀態(tài)從“未完成”變?yōu)椤笆 保磸?pending 變?yōu)?rejected ),在異步操作失敗時(shí)調(diào)用,并將異步操作報(bào)出的錯(cuò)誤,作為參數(shù)傳遞出去。

下面代碼創(chuàng)造了一個(gè) Promise 實(shí)例。

function request() {
  return new Promise((resolve, reject) => {
    /* 異步操作成功 */
    setTimeout(() => {
      resolve("success");
    }, 1000);
    // 取消注釋這里可以體現(xiàn),Promise 的狀態(tài)一旦變更就不會(huì)再變化的特性
    // reject("error");
  });
}

接收

request()
  .then(result => {
    console.info(result);
  })
  .catch(error => {
    console.info(error);
  });

上述 new Promise() 之后,除去用 catch 去捕獲錯(cuò)誤之外,也可以用 then 方法指定 resolvereject 的回調(diào)函數(shù)
也能達(dá)到捕獲錯(cuò)誤的目的。

request().then(
  result => {
    console.info(result);
  },
  error => {
    console.info(error);
  }
);

原型上的方法

Promise.prototype.then()
p.then(onFulfilled, onRejected);

then 方法 是定義在 Promise.prototype 上的方法,如上面的例子一樣,有兩個(gè)參數(shù),fulfilled 的回調(diào)函數(shù)和 rejected 的回調(diào)函數(shù),第二個(gè)參數(shù)時(shí)可選的。

兩個(gè)關(guān)鍵點(diǎn):

then 方法的返回值是一個(gè)新的 Promise 實(shí)例,所以對(duì)于調(diào)用者而言,拿到一個(gè) Promise 對(duì)象,調(diào)用 then 后仍然返回一個(gè) Promise ,而它的行為與 then 中的回調(diào)函數(shù)的返回值有關(guān)。如下:

如果 then 中的回調(diào)函數(shù)返回一個(gè)值,那么 then 返回的 Promise 將會(huì)成為接受狀態(tài),并且將返回的值作為接受狀態(tài)的回調(diào)函數(shù)的參數(shù)值。

如果 then 中的回調(diào)函數(shù)拋出一個(gè)錯(cuò)誤,那么 then 返回的 Promise 將會(huì)成為拒絕狀態(tài),并且將拋出的錯(cuò)誤作為拒絕狀態(tài)的回調(diào)函數(shù)的參數(shù)值。

如果 then 中的回調(diào)函數(shù)返回一個(gè)已經(jīng)是接受狀態(tài)的 Promise,那么 then 返回的 Promise 也會(huì)成為接受狀態(tài),并且將那個(gè) Promise 的接受狀態(tài)的回調(diào)函數(shù)的參數(shù)值作為該被返回的 Promise 的接受狀態(tài)回調(diào)函數(shù)的參數(shù)值。

如果 then 中的回調(diào)函數(shù)返回一個(gè)已經(jīng)是拒絕狀態(tài)的 Promise,那么 then 返回的 Promise 也會(huì)成為拒絕狀態(tài),并且將那個(gè) Promise 的拒絕狀態(tài)的回調(diào)函數(shù)的參數(shù)值作為該被返回的 Promise 的拒絕狀態(tài)回調(diào)函數(shù)的參數(shù)值。

如果 then 中的回調(diào)函數(shù)返回一個(gè)未定狀態(tài)(pending)的 Promise,那么 then 返回 Promise 的狀態(tài)也是未定的,并且它的終態(tài)與那個(gè) Promise 的終態(tài)相同;同時(shí),它變?yōu)榻K態(tài)時(shí)調(diào)用的回調(diào)函數(shù)參數(shù)與那個(gè) Promise 變?yōu)榻K態(tài)時(shí)的回調(diào)函數(shù)的參數(shù)是相同的。

鏈?zhǔn)秸{(diào)用。把嵌套回調(diào)的代碼格式轉(zhuǎn)換成一種鏈?zhǔn)秸{(diào)用的縱向模式。

比如說回調(diào)形式: 一個(gè)回調(diào)地獄的例子

a(a1 => {
  b(a1, b1 => {
    c(b1, c1 => {
      d(c1, d1 => {
        console.log(d1);
      });
    });
  });
});

這樣的橫向擴(kuò)展可以修改成(a,b,c,d)均為返回 Promise 的函數(shù)

a()
  .then(b)
  .then(c)
  .then(d)
  .then(d1 => {
    console.log(d1);
  });
//===== 可能上面的例子并不太好看 ===下面這樣更直觀
a()
  .then(a1 => b(a1))
  .then(b1 => c(b1))
  .then(c1 => d(c1))
  .then(d1 => {
    console.log(d1);
  });

這樣的縱向結(jié)構(gòu),看上去清爽多了。

Promise.prototype.catch()

除了 then() ,在 Promise.prototype 原型鏈上的還有 catch() 方法,這個(gè)是拒絕的情況的處理函數(shù)。

其實(shí) 它的行為與調(diào)用 Promise.prototype.then(undefined, onRejected) 相同。 (事實(shí)上, calling obj.catch(onRejected) 內(nèi)部 calls obj.then(undefined, onRejected)).

// 1.
request().then(
  result => {
    console.info(result);
  },
  error => {
    console.info(error);
  }
);

// 2.
request()
  .then(result => {
    console.info(result);
  })
  .catch(error => {
    console.info(error);
  });

如上這個(gè)例子:兩種方式在使用,與結(jié)果基本上是等價(jià)的,但是 仍然推薦第二種寫法,下面我會(huì)給出原因:

在 Promise 鏈中 Promise.prototype.then(undefined, onRejected),onRejected 方法無法捕獲當(dāng)前 Promise 拋出的錯(cuò)誤,而后續(xù)的 .catch 可以捕獲之前的錯(cuò)誤。

代碼冗余

new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("reject");
  }, 1000);
})
  .then(
    result => {
      console.log(result + "1");
      throw Error(result + "1"); // 拋出一個(gè)錯(cuò)誤
    },
    error => {
      console.log(error + ":1"); // 不會(huì)走到這里
    }
  )
  .then(
    result => {
      console.log(result + "2");
      return Promise.resolve(result + "2");
    },
    error => {
      console.log(error + ":2");
    }
  );
// reject1, Error: reject1:2

如果使用 .catch 方法,代碼會(huì)簡化很多,這樣實(shí)際上是延長了 Promise 鏈

new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("reject");
  }, 1000);
})
  .then(result => {
    console.log(result + "1");
    throw Error(result + "1"); // 拋出一個(gè)錯(cuò)誤
  })
  .then(result => {
    console.log(result + "2");
    return Promise.resolve(result + "2");
  })
  .catch(err => {
    console.log(err);
  });
// reject1, Error: reject1:2
Promise.prototype.finally()

暫未完全成為標(biāo)準(zhǔn)的一部分,處于:Stage 4

finally() 方法返回一個(gè) Promise,在執(zhí)行 then()catch() 后,都會(huì)執(zhí)行finally指定的回調(diào)函數(shù)。(回調(diào)函數(shù)中無參數(shù),僅僅代表 Promise 的已經(jīng)結(jié)束

等同于使用 .then + .catch 延長了原有的 Promise 鏈的效果,避免同樣的語句需要在 then()catch() 中各寫一次的情況。

mdn-Promise-finally

Promise 對(duì)象上的方法 Promise.all() 用來處理 Promise 的并發(fā)

Promise.all 會(huì)將多個(gè) Promise 實(shí)例封裝成一個(gè)新的 Promise 實(shí)例,新的 promise 的狀態(tài)取決于多個(gè) Promise 實(shí)例的狀態(tài),只有在全體 Promise 都為 fulfilled 的情況下,新的實(shí)例才會(huì)變成 fulfilled 狀態(tài)。;如果參數(shù)中 Promise 有一個(gè)失?。?b>rejected),此實(shí)例回調(diào)失?。?b>rejecte),失敗原因的是第一個(gè)失敗 Promise 的結(jié)果。

舉個(gè)例子:

Promise.all([
  new Promise(resolve => {
    setTimeout(resolve, 1000, "p1");
  }),
  new Promise(resolve => {
    setTimeout(resolve, 2000, "p2");
  }),
  new Promise(resolve => {
    setTimeout(resolve, 3000, "p3");
  })
])
  .then(result => {
    console.info("then", result);
  })
  .catch(error => {
    console.info("catch", error);
  });
// [p1,p2,p3]

Promise.all([
  new Promise(resolve => {
    setTimeout(resolve, 1000, "p1");
  }),
  new Promise(resolve => {
    setTimeout(resolve, 2000, "p2");
  }),
  Promise.reject("p3 error")
])
  .then(result => {
    console.info("then", result);
  })
  .catch(error => {
    console.info("catch", error);
  });
// p3 error

獲取 cnode 社區(qū)的 精華貼的前十條內(nèi)容

fetch("https://cnodejs.org/api/v1/topics?tab=good&limit=10")
  .then(res => res.json())
  .then(res => {
    const fetchList = res.data.map(item => {
      return fetch(`https://cnodejs.org/api/v1/topic/${item.id}`)
        .then(res => res.json())
        .then(res => res.data);
    });
    Promise.all(fetchList).then(list => {
      console.log(list);
    });
  });
Promise.race() 競態(tài)執(zhí)行

Promise.race 也會(huì)將多個(gè) Promise 實(shí)例封裝成一個(gè)新的Promise實(shí)例,只不過新的 Promise 的狀態(tài)取決于最先改變狀態(tài)的 Promise 實(shí)例的狀態(tài)。

在前端最典型的一個(gè)用法是為 fetch api 模擬請(qǐng)求超時(shí)。

Promise.race([
  fetch("https://cnodejs.org/api/v1/topics?tab=good&limit=10").then(res =>
    res.json()
  ),
  new Promise((resolve, reject) => {
    setTimeout(reject, 1, "error");
  })
])
  .then(result => {
    console.info("then", result);
  })
  .catch(error => {
    console.info("catch", error); // 進(jìn)入這里
  });

上述例子中只要請(qǐng)求 未在 1 毫秒內(nèi)結(jié)束就會(huì)進(jìn)入 .catch() 方法中,雖然不能將請(qǐng)求取消,但是超時(shí)模擬卻成功了

Promise.resolve(value) && Promise.reject(reason)

這兩個(gè)方法都能用來創(chuàng)建并返回一個(gè)新的 Promise , 區(qū)別是 Promise.resolve(value) 攜帶進(jìn)新的 Promise 狀態(tài)是 fulfilled。而 Promise.reject(reason) 帶來的 rejected

有的時(shí)候可以用來簡化一些創(chuàng)建 Promise 的操作如:

const sleep = (time = 0) => new Promise(resolve => setTimeout(resolve, time));
// 這里創(chuàng)建一個(gè) 睡眠,并且打印的鏈
Promise.resolve()
  .then(() => {
    console.log(1);
  })
  .then(() => sleep(1000))
  .then(() => {
    console.log(2);
  })
  .then(() => sleep(2000))
  .then(() => {
    console.log(3);
  });

有時(shí)也用來 手動(dòng)改變 Promise 鏈中的返回狀態(tài) ,當(dāng)然這樣實(shí)際上和 直接返回一個(gè)值,或者是 使用 throw Error 來構(gòu)造一個(gè)錯(cuò)誤,并無區(qū)別。到底要怎么用 就看個(gè)人喜好了

new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("resolve"); // 1.
  }, 1000);
})
  .then(result => {
    return Promise.reject("reject1"); // 2.
  })
  .then(
    result => {
      return Promise.resolve(result + "2");
    },
    err => {
      return Promise.resolve(err); // 3.
    }
  )
  .then(res => {
    console.log(res); // 4.
  })
  .catch(err => {
    console.log(err + "err");
  });
// reject1
幾個(gè)例子

下面來看幾個(gè)例子:

關(guān)于執(zhí)行順序,具體可搜索,js 循環(huán)

new Promise((resolve, reject) => {
  console.log("step 1");
  resolve();
  console.log("step 2");
}).then(() => {
  console.log("step 3");
});
console.log("step 4");

// step 1, step 2, step 4 , step 3

在使用 Promise 構(gòu)造函數(shù)構(gòu)造 一個(gè) Promise 時(shí),回調(diào)函數(shù)中的內(nèi)容就會(huì)立即執(zhí)行,而 Promise.then 中的函數(shù)是異步執(zhí)行的。

關(guān)于狀態(tài)不可變更

let start;
const p = new Promise((resolve, reject) => {
  setTimeout(() => {
    start = Date.now();
    console.log("once");
    resolve("success");
  }, 1000);
});
p.then(res => {
  console.log(res, Date.now() - start);
});
p.then(res => {
  console.log(res, Date.now() - start);
});
p.then(res => {
  console.log(res, Date.now() - start);
});

Promise 構(gòu)造函數(shù)只執(zhí)行一次,內(nèi)部狀態(tài)一旦改變,有了一個(gè)值,后續(xù)不論調(diào)用多少次then()都只拿到那么一個(gè)結(jié)果。

關(guān)于好像狀態(tài)可以變更

const p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("success");
  }, 1000);
});

const p2 = p1.then((resolve, reject) => {
  throw new Error("error");
});

console.log("p1", p1);
console.log("p2", p2);

setTimeout(() => {
  console.log("p1", p1);
  console.log("p2", p2);
}, 2000);

觀察這一次的打印
第一次打印出兩個(gè) Promise 的時(shí)候都是 pending ,因?yàn)?p2 是基于 p1 的結(jié)果,p1 正在 pending ,立即打印出的時(shí)候肯定是 pending ;第二次打印的時(shí)候,因?yàn)?p1 的狀態(tài)為 resolved ,p2 為 rejected ,這個(gè)并不是已經(jīng)為 fulfilled 狀態(tài)改變?yōu)?rejected ,而是 p2 是一個(gè)新的 Promise 實(shí)例,then() 返回新的 Promise 實(shí)例。

關(guān)于透傳

Promise.resolve(11)
  .then(1)
  .then(2)
  .then(3)
  .then(res => {
    console.info("res", res);
  });
//   11

給 then 方法傳遞了一個(gè)非函數(shù)的值,等同于 then(null),會(huì)導(dǎo)致穿透的效果,就是直接過掉了這個(gè) then() ,直到符合規(guī)范的 then() 為止。

Promise 的串行調(diào)用

使用 Array.reduce 方法串行執(zhí)行 Promise

const sleep = (time = 0) => new Promise(resolve => setTimeout(resolve, time));
[1000, 2000, 3000, 4000].reduce((Promise, item, index) => {
  return Promise.then(res => {
    console.log(index + 1);
    return sleep(item);
  });
}, Promise.resolve());
// 在分別的等待時(shí)間后輸出 1,2,3,4

這篇文章到這里就基本上結(jié)束了,相信 如果能理解上面的內(nèi)容,并且在實(shí)際項(xiàng)目中使用的話。應(yīng)該會(huì)讓工作更高效吧,對(duì)于新的異步使用應(yīng)該也會(huì)更加的得心應(yīng)手。Promise 的使用相對(duì)簡單,可能后續(xù)再出一篇如何實(shí)現(xiàn)一個(gè) Promise 吧

那些收集的 Promise 的優(yōu)質(zhì)文章。

bluebird 是一個(gè)拓展 Promise 方法的庫,提供了非常多的實(shí)用的方法,推薦

[[思維導(dǎo)圖] Promise - 《你不知道的 JavaScript》- 中卷 - 第二部分](https://zhuanlan.zhihu.com/p/...

[[譯] 一個(gè)簡單的 ES6 Promise 指南](https://zhuanlan.zhihu.com/p/...

阮一峰-ES6 入門 Promise 對(duì)象

Promise 不夠中立

WHY “PROMISES ARE NOT NEUTRAL ENOUGH” IS NOT NEUTRAL ENOUGH

【譯】關(guān)于 Promise 的 9 個(gè)提示

Promise 必知必會(huì)(十道題)

Event Loop 必知必會(huì)(六道題)

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/98434.html

相關(guān)文章

  • JavaScript 異步

    摘要:從最開始的到封裝后的都在試圖解決異步編程過程中的問題。為了讓編程更美好,我們就需要引入來降低異步編程的復(fù)雜性。寫一個(gè)符合規(guī)范并可配合使用的寫一個(gè)符合規(guī)范并可配合使用的理解的工作原理采用回調(diào)函數(shù)來處理異步編程。 JavaScript怎么使用循環(huán)代替(異步)遞歸 問題描述 在開發(fā)過程中,遇到一個(gè)需求:在系統(tǒng)初始化時(shí)通過http獲取一個(gè)第三方服務(wù)器端的列表,第三方服務(wù)器提供了一個(gè)接口,可通過...

    tuniutech 評(píng)論0 收藏0
  • JS筆記

    摘要:從最開始的到封裝后的都在試圖解決異步編程過程中的問題。為了讓編程更美好,我們就需要引入來降低異步編程的復(fù)雜性。異步編程入門的全稱是前端經(jīng)典面試題從輸入到頁面加載發(fā)生了什么這是一篇開發(fā)的科普類文章,涉及到優(yōu)化等多個(gè)方面。 TypeScript 入門教程 從 JavaScript 程序員的角度總結(jié)思考,循序漸進(jìn)的理解 TypeScript。 網(wǎng)絡(luò)基礎(chǔ)知識(shí)之 HTTP 協(xié)議 詳細(xì)介紹 HTT...

    rottengeek 評(píng)論0 收藏0
  • 【全文】狼叔:如何正確的學(xué)習(xí)Node.js

    摘要:感謝大神的免費(fèi)的計(jì)算機(jī)編程類中文書籍收錄并推薦地址,以后在倉庫里更新地址,聲音版全文狼叔如何正確的學(xué)習(xí)簡介現(xiàn)在,越來越多的科技公司和開發(fā)者開始使用開發(fā)各種應(yīng)用。 說明 2017-12-14 我發(fā)了一篇文章《沒用過Node.js,就別瞎逼逼》是因?yàn)橛腥嗽谥跎虾贜ode.js。那篇文章的反響還是相當(dāng)不錯(cuò)的,甚至連著名的hax賀老都很認(rèn)同,下班時(shí)讀那篇文章,竟然坐車的還坐過站了。大家可以很...

    Edison 評(píng)論0 收藏0
  • 【全文】狼叔:如何正確的學(xué)習(xí)Node.js

    摘要:感謝大神的免費(fèi)的計(jì)算機(jī)編程類中文書籍收錄并推薦地址,以后在倉庫里更新地址,聲音版全文狼叔如何正確的學(xué)習(xí)簡介現(xiàn)在,越來越多的科技公司和開發(fā)者開始使用開發(fā)各種應(yīng)用。 說明 2017-12-14 我發(fā)了一篇文章《沒用過Node.js,就別瞎逼逼》是因?yàn)橛腥嗽谥跎虾贜ode.js。那篇文章的反響還是相當(dāng)不錯(cuò)的,甚至連著名的hax賀老都很認(rèn)同,下班時(shí)讀那篇文章,竟然坐車的還坐過站了。大家可以很...

    fengxiuping 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<