阿里云主机折上折
  • 微信号
Current Site:Index > Interoperability with Promise

Interoperability with Promise

Author:Chuan Chen 阅读数:4285人阅读 分类: JavaScript

ECMAScript 6 and Promise Interoperability

ECMAScript 6 introduced Promises as a standard way to handle asynchronous operations, deeply integrating them with other ES6 features. Promises not only solve the "callback hell" problem but also form a complete asynchronous solution alongside generators, async/await, and other features.

Promise Basics and ES6 Syntax Integration

Promises are a native constructor provided by ES6, representing the eventual completion or failure of an asynchronous operation. Their basic usage is tightly integrated with ES6 features like arrow functions and destructuring:

const fetchData = () => new Promise((resolve, reject) => {  
  setTimeout(() => {  
    const success = Math.random() > 0.5;  
    success ? resolve({ status: 200, data: 'Sample' }) :   
              reject(new Error('Request failed'));  
  }, 1000);  
});  

// ES6 arrow function and destructuring  
fetchData()  
  .then(({ data }) => console.log(data))  
  .catch(error => console.error(error.message));  

The three states of a Promise (pending, fulfilled, rejected) also work well with ES6's module system:

// Exporting a Promise in a module  
export const apiPromise = fetchData();  

// Importing in another module  
import { apiPromise } from './api';  
apiPromise.then(handleResponse);  

Promise and Iterator/Generator Interoperability

ES6 generator functions can be combined with Promises for more elegant asynchronous flow control:

function* asyncGenerator() {  
  try {  
    const result1 = yield fetchData();  
    const result2 = yield fetchData();  
    return [result1, result2];  
  } catch (error) {  
    console.error('Generator error:', error);  
  }  
}  

// Helper function to execute the generator  
function runGenerator(gen) {  
  const iterator = gen();  

  function iterate(iteration) {  
    if (iteration.done) return iteration.value;  
    const promise = iteration.value;  
    return promise.then(  
      x => iterate(iterator.next(x)),  
      err => iterate(iterator.throw(err))  
    );  
  }  

  return iterate(iterator.next());  
}  

runGenerator(asyncGenerator).then(console.log);  

This pattern later evolved into the async/await syntactic sugar, which is still based on Promises and generators under the hood.

Promise Static Methods and ES6 Features

ES6 provides several static methods for Promises that work in harmony with new language features:

// Promise.all with destructuring assignment  
const [user, posts] = await Promise.all([  
  fetch('/user'),  
  fetch('/posts')  
]);  

// Promise.race with template literals  
Promise.race([  
  fetchData(),  
  new Promise((_, reject) =>   
    setTimeout(() => reject(new Error(`Timeout after 3000ms`)), 3000))  
]).catch(err => console.log(`${err.message} occurred`));  

// Promise.allSettled with object spreading  
const results = await Promise.allSettled(requests);  
const successful = results.filter(({status}) => status === 'fulfilled');  

Promise Prototype Methods and ES6 Classes

Using Promises in ES6 classes enables the creation of more powerful asynchronous objects:

class AsyncQueue {  
  constructor() {  
    this.queue = [];  
    this.resolveCurrent = null;  
    this.currentPromise = null;  
  }  

  enqueue(item) {  
    if (this.resolveCurrent) {  
      this.resolveCurrent(item);  
      this.resolveCurrent = null;  
    } else {  
      this.queue.push(item);  
    }  
  }  

  dequeue() {  
    if (this.queue.length > 0) {  
      return Promise.resolve(this.queue.shift());  
    }  
    return new Promise(resolve => {  
      this.resolveCurrent = resolve;  
    });  
  }  
}  

// Usage example  
const queue = new AsyncQueue();  
queue.dequeue().then(console.log); // Waits for data  
setTimeout(() => queue.enqueue('Hello'), 1000);  

Promise and Proxy Integration

ES6's Proxy can enhance Promise behavior:

const loggingProxy = (promise) => new Proxy(promise, {  
  get(target, prop) {  
    if (prop === 'then') {  
      return (...args) => {  
        console.log('Then handler attached');  
        return target.then(...args);  
      };  
    }  
    return target[prop];  
  }  
});  

const proxiedPromise = loggingProxy(fetchData());  
proxiedPromise.then(() => {}); // Logs "Then handler attached"  

Promise and Reflect Metaprogramming

The Reflect API can be combined with Promises for advanced metaprogramming patterns:

function timeoutPromise(promise, ms) {  
  const timeout = new Promise((_, reject) =>   
    setTimeout(() => reject(new Error('Timeout')), ms));  

  return Reflect.apply(Promise.race, null, [promise, timeout]);  
}  

// Usage example  
timeoutPromise(fetchData(), 500)  
  .then(console.log)  
  .catch(err => console.error(err.message));  

Promise and Symbol Collaboration

ES6's Symbol type can be used to customize Promise behavior:

const kCustomThen = Symbol('customThen');  

class CustomPromise extends Promise {  
  [kCustomThen](onFulfilled, onRejected) {  
    console.log('Custom then called');  
    return this.then(onFulfilled, onRejected);  
  }  
}  

const cp = new CustomPromise(resolve => resolve('value'));  
cp[kCustomThen](value => console.log(value));  

Special Applications of Promises in the Module System

Top-level await in ES6 modules is essentially syntactic sugar over Promises:

// module.mjs  
const data = await fetchData(); // Top-level await in modules  
export { data };  

// Equivalent to  
const dataPromise = fetchData();  
export const data = dataPromise;  

Performance Considerations and ES6 Optimizations

Modern JavaScript engines have special optimizations for Promises:

// V8 engine optimizations for microtasks  
Promise.resolve().then(() => console.log('microtask 1'));  
queueMicrotask(() => console.log('microtask 2'));  

// Avoiding Promise constructor antipatterns  
// Antipattern  
function delay(ms) {  
  return new Promise(resolve => setTimeout(resolve, ms));  
}  

// Better approach  
function delay(ms) {  
  return Promise.resolve().then(() =>   
    new Promise(resolve => setTimeout(resolve, ms)));  
}  

Promise and Web API Integration

Browser Web APIs increasingly return Promise objects:

// Modern Web API example  
async function useModernApis() {  
  const clipboardItems = await navigator.clipboard.read();  
  const battery = await navigator.getBattery();  
  const storage = await navigator.storage.estimate();  

  return { clipboardItems, battery, storage };  
}  

// Using ES6 object shorthand  
useModernApis().then(({ battery }) =>   
  console.log(`Battery level: ${battery.level * 100}%`));  

Promise Patterns and Antipatterns

Best practices for Promises with ES6 features:

// Correct chaining  
fetchData()  
  .then(data => processData(data))  
  .then(processed => saveData(processed))  
  .catch(handleError);  

// Antipattern: Nested Promises  
fetchData().then(data => {  
  processData(data).then(processed => {  
    saveData(processed).then(() => {  
      // More nesting  
    });  
  });  
});  

// Better parallel processing  
const [user, orders] = await Promise.all([  
  fetchUser(),  
  fetchOrders()  
]);  

Promise Extensions and Composition

Extending Promise functionality using ES6 classes:

class CancellablePromise extends Promise {  
  constructor(executor) {  
    super((resolve, reject) => {  
      executor(resolve, reject, () => {  
        reject(new Error('Cancelled'));  
      });  
    });  
    this._cancel = null;  
  }  

  cancel() {  
    this._cancel?.();  
  }  

  static withCancel(executor) {  
    let cancelFn;  
    const promise = new CancellablePromise((res, rej, cancel) => {  
      cancelFn = cancel;  
      return executor(res, rej);  
    });  
    promise._cancel = cancelFn;  
    return promise;  
  }  
}  

// Usage example  
const cp = CancellablePromise.withCancel((resolve, reject) => {  
  const timer = setTimeout(() => resolve('Done'), 2000);  
  return () => clearTimeout(timer);  
});  

setTimeout(() => cp.cancel(), 1000);  
cp.catch(err => console.log(err.message)); // Logs "Cancelled"  

Promise and Type Systems

Using ES6 Promise type definitions in TypeScript:

interface ApiResponse<T> {  
  data: T;  
  status: number;  
}  

function typedFetch<T>(url: string): Promise<ApiResponse<T>> {  
  return fetch(url).then(res => res.json());  
}  

// Usage example  
typedFetch<User[]>('/users')  
  .then(({ data }) => data.map(user => user.name))  
  .catch((err: Error) => console.error(err.stack));  

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

上一篇:top-level await

下一篇:常见异步模式实现

Front End Chuan

Front End Chuan, Chen Chuan's Code Teahouse 🍵, specializing in exorcising all kinds of stubborn bugs 💻. Daily serving baldness-warning-level development insights 🛠️, with a bonus of one-liners that'll make you laugh for ten years 🐟. Occasionally drops pixel-perfect romance brewed in a coffee cup ☕.