在JavaScript中從外部解決Promise:實際應(yīng)用場景
這是JavaScript中那些在現(xiàn)實世界中極其強大的酷炫技巧之一。
強大的實際應(yīng)用場景
動作(A)等待另一個動作(B)
A正在進行,但用戶想做B,而A需要先發(fā)生。
例如:社交應(yīng)用,用戶可以創(chuàng)建、保存和發(fā)布帖子。就像Medium。
<p>
  Save status:
  <b><span id="save-status">Not saved</span></b>
</p>
<p>
  Publish status:
  <b><span id="publish-status">Not published</span></b>
</p>
<button id="save">Save</button>
<button id="publish">Publish</button>
圖片
如果用戶想在帖子保存時發(fā)布怎么辦?
解決方案:確保在發(fā)布之前帖子已保存。
saveButton.onclick = () => {
  save();
};
publishButton.onclick = async () => {
  await publish();
};
let saveResolve;
let hasSaved = false;
async function save() {
  hasSaved = false;
  saveStatus.textContent = 'Saving...';
  // ? Resolve promise from outside
  await makeSaveRequest();
  saveResolve();
  hasSaved = true;
  saveStatus.textContent = 'Saved';
}
async function waitForSave() {
  if (!hasSaved) {
    await new Promise((resolve) => {
      saveResolve = resolve;
    });
  }
}
async function publish() {
  publishStatus.textContent = 'Waiting for save...';
  await waitForSave();
  publishStatus.textContent = 'Published';
  return;
}
圖片
當(dāng)你將這個邏輯抽象成一種Deferred類時,它變得更好:
class Deferred {
  constructor() {
    this.promise = new Promise((resolve, reject) => {
      this.reject = reject;
      this.resolve = resolve;
    });
  }
}
const deferred = new Deferred();
// Resolve from outside
deferred.resolve();重構(gòu)?:
const deferredSave = new Deferred();
let hasSaved = false;
async function save() {
  hasSaved = false;
  saveStatus.textContent = 'Saving...';
  // ?? Resolve promise from outside
  await makeSaveRequest();
  saveResolve();
  hasSaved = true;
  saveStatus.textContent = 'Saved';
}
async function waitForSave() {
  if (!hasSaved) await deferredSave.promise;
}
async function publish() {
  // ...
}它的工作方式與之前完全相同:
圖片
Deferred更加清晰,這就是為什么我們有很多類似的NPM庫:ts-deferred、deferred、promise-deferred...
圖片
將事件流轉(zhuǎn)換為Promise
這是我多次使用過的一個很好的設(shè)置。
執(zhí)行一個異步任務(wù),實際上是在內(nèi)部等待事件流觸發(fā):
// data-fetcher.js
const deferred = new Deferred();
let dataDeferred;
function startListening() {
  dataDeferred = new Deferred();
  eventStream.on('data', (data) => {
    dataDeferred.resolve(data);
  });
}
async function getData() {
  return await dataDeferred.promise;
}
// client.js
const { startListening, getData } = require('./data-fetcher.js');
startListening();
// ?? Waits for event to happen once
const data = await getData();最后的思考
從外部解決Promise可以解鎖強大的模式。
它保持你的代碼清晰和靈活,從用戶操作到事件流。而像ts-deferred這樣的庫為我們提供了更好的處理方式。















 
 
 








 
 
 
 