Giải quyết Javascript Promise bên ngoài phạm vi chức năng


279

Tôi đã và đang sử dụng ES6 Promise.

Thông thường, một Promise được xây dựng và sử dụng như thế này

new Promise(function(resolve, reject){
    if (someCondition){
        resolve();
    } else {
        reject();
    } 
});

Nhưng tôi đã làm một cái gì đó như dưới đây để giải quyết bên ngoài vì sự linh hoạt.

var outsideResolve;
var outsideReject;
new Promise(function(resolve, reject) { 
    outsideResolve = resolve; 
    outsideReject = reject; 
});

Và sau đó

onClick = function(){
    outsideResolve();
}

Điều này hoạt động tốt, nhưng có một cách dễ dàng hơn để làm điều này? Nếu không, đây có phải là một thực hành tốt?


2
Tôi không nghĩ có một cách khác. Tôi tin rằng nó được chỉ định rằng cuộc gọi lại được chuyển đến Promisephải được thực hiện đồng bộ để cho phép "xuất" hai chức năng.
Felix Kling

1
Điều này làm việc cho tôi chính xác như bạn đã viết nó. Theo như tôi nghĩ, đây là cách "kinh điển".
Gilad Barner

14
Tôi nghĩ nên có một cách chính thức để đạt được điều này trong tương lai. Theo tôi, tính năng này rất mạnh vì bạn có thể chờ đợi các giá trị từ các bối cảnh khác.
Jose

Bất cứ khi nào họ đưa ra một giải pháp thích hợp cho vấn đề này, tôi hy vọng họ cũng sẽ làm cho nó hoạt động cho những lời hứa lồng nhau, một số trong đó có thể tái diễn.
Arthur Tarasov

Tôi nghĩ rằng API Promise "đề xuất" luôn sử dụng chúng làm giá trị trả về và không bao giờ là đối tượng mà bạn có thể truy cập hoặc gọi. Nói cách khác, buộc chúng ta coi chúng là giá trị trả về thay vì các đối tượng chúng ta có thể truy cập hoặc các hàm chúng ta có thể gọi hoặc một cái gì đó chúng ta có thể tham chiếu với một biến hoặc truyền dưới dạng tham số, v.v. Nếu bạn bắt đầu sử dụng lời hứa như bất kỳ đối tượng nào khác có thể bạn sẽ cuối cùng cần phải giải quyết nó từ bên ngoài như trong câu hỏi của bạn ... Điều đó đã được nói, tôi cũng nghĩ nên có một cách chính thức để làm điều này ... và Trì hoãn dường như chỉ là một cách giải quyết đối với tôi.
Cancerbero

Câu trả lời:


92

Không, không có cách nào khác để làm điều này - điều duy nhất tôi có thể nói là trường hợp sử dụng này không phổ biến lắm. Giống như Felix đã nói trong bình luận - những gì bạn làm sẽ liên tục hoạt động.

Điều đáng nói là lý do nhà xây dựng lời hứa hành xử theo cách này là an toàn - nếu một ngoại lệ bạn không lường trước được xảy ra trong khi mã của bạn đang chạy bên trong nhà xây dựng lời hứa thì nó sẽ biến thành từ chối, hình thức ném an toàn này - chuyển đổi lỗi ném sang từ chối là quan trọng và giúp duy trì mã dự đoán.

Vì lý do an toàn ném này, nhà xây dựng lời hứa đã được chọn thay vì trì hoãn (là cách xây dựng lời hứa thay thế cho phép những gì bạn đang thực hiện) - như đối với các thực tiễn tốt nhất - thay vào đó tôi sẽ chuyển qua phần tử và sử dụng công cụ xây dựng lời hứa:

var p = new Promise(function(resolve, reject){
    this.onclick = resolve;
}.bind(this));

Vì lý do này - bất cứ khi nào bạn có thể sử dụng hàm tạo hứa hẹn khi xuất các hàm - tôi khuyên bạn nên sử dụng nó. Bất cứ khi nào bạn có thể tránh cả hai - tránh cả hai và chuỗi.

Lưu ý rằng bạn không bao giờ nên sử dụng hàm tạo lời hứa cho những thứ như if(condition), ví dụ đầu tiên có thể được viết là:

var p = Promise[(someCondition)?"resolve":"reject"]();

2
Chào Benjamin! Hiện tại không có cách nào tốt hơn để có được lời hứa ngon lành nếu chúng ta không biết khi nào lời hứa sẽ được thực hiện? Giống như một số kiểu chờ / thông báo không đồng bộ ? Ví dụ như "cửa hàng", và sau đó gọi một Promisechuỗi? Ví dụ, trong trường hợp cụ thể của tôi, tôi đang ở trên một máy chủ, đang chờ phản hồi của một khách hàng cụ thể (một cái bắt tay kiểu SYN-ACK để đảm bảo máy khách được cập nhật trạng thái thành công).
Domi

1
@Domi kiểm tra kết nối q và RxJS.
Benjamin Gruenbaum

2
Làm cách nào tôi có thể sử dụng API tương tự?
Vinod Sobale

95
Không phổ biến? Tôi cuối cùng cần nó gần như mọi dự án.
Tomáš Zato - Phục hồi Monica

1
Đối với usecase, bạn cần phải làm gì đó sau khi một sự kiện được kích hoạt và một cái gì đó khác đã xảy ra. Bạn muốn biến sự kiện thành một lời hứa và hợp nhất nó với một lời hứa khác. Có vẻ như một vấn đề chung với tôi.
Gherman

130

đơn giản:

var promiseResolve, promiseReject;

var promise = new Promise(function(resolve, reject){
  promiseResolve = resolve;
  promiseReject = reject;
});

promiseResolve();

2
@ruX, Như câu trả lời được chấp nhận đề cập - nó được thiết kế theo cách này nhằm mục đích. Vấn đề là nếu một ngoại lệ được ném ra, nó sẽ bị bắt bởi nhà xây dựng lời hứa. Câu trả lời này (cũng như của tôi) có một cạm bẫy là có thể ném ngoại lệ cho bất kỳ cuộc gọi mã nào promiseResolve(). Các ngữ nghĩa của một lời hứa là nó luôn trả về một giá trị. Ngoài ra, đây là chức năng giống như bài viết của OP, tôi không hiểu vấn đề này đang giải quyết theo cách nào có thể sử dụng lại.
Jon Jaques

4
@JonJaques Tôi không chắc những gì bạn nói là đúng. Mã mà các cuộc gọi promiseResolve()sẽ không ném ngoại lệ. Bạn có thể định nghĩa một .catchtrên hàm tạo và bất kể mã nào gọi nó, hàm tạo .catchsẽ được gọi. Dưới đây là jsbin trình bày cách thức hoạt động của nó: jsbin.com/yicerewivo/edit?js,console
carter

Vâng, nó bị bắt bởi vì bạn đã bao bọc một nhà xây dựng lời hứa khác xung quanh nó - Chính xác là điểm tôi đang cố gắng thực hiện. Tuy nhiên, giả sử bạn có một số mã khác đang cố gắng gọi giải quyết () bên ngoài hàm tạo (còn gọi là đối tượng Trì hoãn) ... Nó có thể ném ngoại lệ và không bị bắt jsbin.com/cokiqiwapo/1/edit?js,console
Jon Jaques

8
Tôi thậm chí không chắc chắn đó là một thiết kế xấu. Một lỗi được đưa ra ngoài lời hứa sẽ không bị bắt trong lời hứa. Nó có lẽ là một ví dụ về quan niệm sai lầm hoặc hiểu sai, nếu nhà thiết kế thực sự mong đợi lỗi được bắt gặp bên trong.
KalEl

3
Cấu trúc chính xác này đã được đề cập trong câu hỏi. Bạn thậm chí đọc nó?
Cedric Reichenbach

103

Đến bữa tiệc muộn ở đây, nhưng một cách khác để làm điều đó là sử dụng một đối tượng Trì hoãn . Về cơ bản, bạn có cùng số lượng nồi hơi, nhưng thật tiện dụng nếu bạn muốn vượt qua chúng và có thể giải quyết ngoài định nghĩa của chúng.

Thực hiện ngây thơ:

class Deferred {
  constructor() {
    this.promise = new Promise((resolve, reject)=> {
      this.reject = reject
      this.resolve = resolve
    })
  }
}

function asyncAction() {
  var dfd = new Deferred()

  setTimeout(()=> {
    dfd.resolve(42)
  }, 500)

  return dfd.promise
}

asyncAction().then(result => {
  console.log(result) // 42
})

Phiên bản ES5:

function Deferred() {
  var self = this;
  this.promise = new Promise(function(resolve, reject) {
    self.reject = reject
    self.resolve = resolve
  })
}

function asyncAction() {
  var dfd = new Deferred()

  setTimeout(function() {
    dfd.resolve(42)
  }, 500)

  return dfd.promise
}

asyncAction().then(function(result) {
  console.log(result) // 42
})

1
Đừng để ý phạm vi từ vựng ở đây.
Florrie

1
Không có sự khác biệt thực tế trong việc resolve|rejectđược chỉ định từ vựng hay thông qua bind. Đây chỉ là một triển khai đơn giản của đối tượng Trì hoãn jQuery đã có từ 1.0 (ish). Nó hoạt động chính xác như một lời hứa, ngoại trừ không có an toàn ném. Toàn bộ vấn đề của câu hỏi này là làm thế nào để lưu một vài dòng mã khi tạo lời hứa.
Jon Jaques

1
Sử dụng hoãn lại là cách thông thường để làm điều này, tôi không biết tại sao điều này không cao hơn
BlueRaja - Danny Pflughoeft

1
Câu trả lời tuyệt vời! Đã tìm kiếm chức năng hoãn lại mà jQuery cung cấp.
Anshul Koka

2
Deferredbị phản đối không?
Pacerier

19

Một giải pháp tôi đã đưa ra vào năm 2015 cho khuôn khổ của tôi. Tôi gọi loại lời hứa này là Nhiệm vụ

function createPromise(handler){
  var _resolve, _reject;

  var promise = new Promise(function(resolve, reject){
    _resolve = resolve; 
    _reject = reject;

    handler(resolve, reject);
  })

  promise.resolve = _resolve;
  promise.reject = _reject;

  return promise;
}

var promise = createPromise()
promise.then(function(data){ alert(data) })

promise.resolve(200) // resolve from outside

4
Cảm ơn, điều này đã làm việc. Nhưng xử lý là gì? Tôi đã phải loại bỏ nó để làm cho nó hoạt động.
Sahid

16

Tôi thích câu trả lời của @JonJaques nhưng tôi muốn tiến thêm một bước nữa.

Nếu bạn liên kết thencatchsau đó là Deferredđối tượng, thì nó thực hiện đầy đủ PromiseAPI và bạn có thể coi nó như lời hứa và awaitnó cũng như vậy.

class DeferredPromise {
  constructor() {
    this._promise = new Promise((resolve, reject) => {
      // assign the resolve and reject functions to `this`
      // making them usable on the class instance
      this.resolve = resolve;
      this.reject = reject;
    });
    // bind `then` and `catch` to implement the same interface as Promise
    this.then = this._promise.then.bind(this._promise);
    this.catch = this._promise.catch.bind(this._promise);
    this[Symbol.toStringTag] = 'Promise';
  }
}

const deferred = new DeferredPromise();
console.log('waiting 2 seconds...');
setTimeout(() => {
  deferred.resolve('whoa!');
}, 2000);

async function someAsyncFunction() {
  const value = await deferred;
  console.log(value);
}

someAsyncFunction();


10

Một phương thức trợ giúp sẽ giảm bớt chi phí phụ thêm này và mang lại cho bạn cảm giác giống như jQuery.

function Deferred() {
    let resolve;
    let reject;
    const promise = new Promise((res, rej) => {
        resolve = res;
        reject = rej;
    });
    return { promise, resolve, reject };
}

Cách sử dụng sẽ là

const { promise, resolve, reject } = Deferred();
displayConfirmationDialog({
    confirm: resolve,
    cancel: reject
});
return promise;

Tương tự với jQuery

const dfd = $.Deferred();
displayConfirmationDialog({
    confirm: dfd.resolve,
    cancel: dfd.reject
});
return dfd.promise();

Mặc dù, trong trường hợp sử dụng, cú pháp gốc đơn giản này vẫn ổn

return new Promise((resolve, reject) => {
    displayConfirmationDialog({
        confirm: resolve,
        cancel: reject
    });
});

8

Tôi đang sử dụng chức năng trợ giúp để tạo ra cái mà tôi gọi là "lời hứa bằng phẳng" -

function flatPromise() {

    let resolve, reject;

    const promise = new Promise((res, rej) => {
      resolve = res;
      reject = rej;
    });

    return { promise, resolve, reject };
}

Và tôi đang sử dụng nó như vậy -

function doSomethingAsync() {

    // Get your promise and callbacks
    const { resolve, reject, promise } = flatPromise();

    // Do something amazing...
    setTimeout(() => {
        resolve('done!');
    }, 500);

    // Pass your promise to the world
    return promise;

}

Xem ví dụ làm việc đầy đủ -

Chỉnh sửa: Tôi đã tạo một gói NPM được gọi là lời hứa phẳng và mã cũng có sẵn trên GitHub .


7

Bạn có thể gói Promise trong một lớp.

class Deferred {
    constructor(handler) {
        this.promise = new Promise((resolve, reject) => {
            this.reject = reject;
            this.resolve = resolve;
            handler(resolve, reject);
        });

        this.promise.resolve = this.resolve;
        this.promise.reject = this.reject;

        return this.promise;
    }
    promise;
    resolve;
    reject;
}

// How to use.
const promise = new Deferred((resolve, reject) => {
  // Use like normal Promise.
});

promise.resolve(); // Resolve from any context.

6

Nhiều câu trả lời ở đây tương tự như ví dụ cuối cùng trong bài viết này . Tôi đang lưu trữ nhiều lời hứa và các chức năng resolve()reject()có thể được gán cho bất kỳ biến hoặc thuộc tính nào. Kết quả là tôi có thể làm cho mã này gọn hơn một chút:

function defer(obj) {
    obj.promise = new Promise((resolve, reject) => {
        obj.resolve = resolve;
        obj.reject  = reject;
    });
}

Dưới đây là một ví dụ đơn giản về việc sử dụng phiên bản này defer()để kết hợp FontFacetải Promise với quy trình không đồng bộ khác:

function onDOMContentLoaded(evt) {
    let all = []; // array of Promises
    glob = {};    // global object used elsewhere
    defer(glob);
    all.push(glob.promise);
    // launch async process with callback = resolveGlob()

    const myFont = new FontFace("myFont", "url(myFont.woff2)");
    document.fonts.add(myFont);
    myFont.load();
    all.push[myFont];
    Promise.all(all).then(() => { runIt(); }, (v) => { alert(v); });
}
//...
function resolveGlob() {
    glob.resolve();
}
function runIt() {} // runs after all promises resolved 

Cập nhật: 2 lựa chọn thay thế trong trường hợp bạn muốn gói gọn đối tượng:

function defer(obj = {}) {
    obj.promise = new Promise((resolve, reject) => {
        obj.resolve = resolve;
        obj.reject  = reject;
    });
    return obj;
}
let deferred = defer();

class Deferred {
    constructor() {
        this.promise = new Promise((resolve, reject) => {
            this.resolve = resolve;
            this.reject  = reject;
        });
    }
}
let deferred = new Deferred();

Nếu bạn đang sử dụng các ví dụ này trong chức năng không đồng bộ, bạn sẽ cần tham khảo thuộc tính lời hứa, khi bạn muốn sử dụng giá trị của lời hứa đã giải quyết:const result = await deferred.promise;
b00t

6

Chấp nhận câu trả lời là sai. Việc sử dụng phạm vi và tài liệu tham khảo khá dễ dàng, mặc dù điều này có thể khiến những người theo chủ nghĩa thuần túy Promise tức giận:

const createPromise = () => {
    let resolver;
    return [
        new Promise((resolve, reject) => {
            resolver = resolve;
        }),
        resolver,
    ];
};

const [ promise, resolver ] = createPromise();
promise.then(value => console.log(value));
setTimeout(() => resolver('foo'), 1000);

Về cơ bản, chúng tôi đang lấy tham chiếu đến chức năng giải quyết khi lời hứa được tạo và chúng tôi trả lại để nó có thể được đặt bên ngoài.

Trong một giây, giao diện điều khiển sẽ xuất ra:

> foo

Tôi nghĩ rằng đây là cách tiếp cận tốt nhất. Điều duy nhất là mã có thể ít dài dòng hơn một chút.
pie6k

Đẹp! Ý tưởng thông minh. +50 nếu tôi có thể.
Utkanos

Đây chỉ là những gì OP đã làm. Trong thực tế, bạn đang phát minh lại mô hình Trì hoãn trên Promise, tất nhiên điều này là có thể và cách tiếp cận của bạn hoạt động (như mã OP ban đầu), nhưng đây không phải là cách thực hành tốt nhất do "lý do an toàn" được mô tả trong câu trả lời được chấp nhận.
dhilt

4

Vâng, bạn có thể. Bằng cách sử dụng CustomEventAPI cho môi trường trình duyệt. Và sử dụng một dự án trình phát sự kiện trong môi trường node.js. Vì đoạn trích trong câu hỏi dành cho môi trường trình duyệt, đây là một ví dụ hoạt động tương tự.

function myPromiseReturningFunction(){
  return new Promise(resolve => {
    window.addEventListener("myCustomEvent", (event) => {
       resolve(event.detail);
    }) 
  })
}


myPromiseReturningFunction().then(result => {
   alert(result)
})

document.getElementById("p").addEventListener("click", () => {
   window.dispatchEvent(new CustomEvent("myCustomEvent", {detail : "It works!"}))
})
<p id="p"> Click me </p>

Tôi hy vọng câu trả lời này là hữu ích!


3

Giải pháp của chúng tôi là sử dụng các bao đóng để lưu trữ các chức năng giải quyết / từ chối và thêm vào đó là đính kèm một chức năng để mở rộng lời hứa.

Đây là mẫu:

function getPromise() {

    var _resolve, _reject;

    var promise = new Promise((resolve, reject) => {
        _reject = reject;
        _resolve = resolve;
    });

    promise.resolve_ex = (value) => {
       _resolve(value);
    };

    promise.reject_ex = (value) => {
       _reject(value);
    };

    return promise;
}

Và sử dụng nó:

var promise = getPromise();

promise.then(value => {
    console.info('The promise has been fulfilled: ' + value);
});

promise.resolve_ex('hello');  
// or the reject version 
//promise.reject_ex('goodbye');

2
Tuyệt vời ... Tôi chỉ đang học Hứa nhưng đã luôn bối rối bởi thực tế là bạn dường như không thể giải quyết chúng "ở một nơi khác". Sử dụng một bao đóng để ẩn chi tiết triển khai là một ý tưởng tuyệt vời ... nhưng thực tế tôi không chắc đó là những gì bạn đã làm: thay vì có các biến riêng tư "giả" Tôi khá chắc chắn có một cách để che giấu hoàn toàn các biến không thể truy cập được ... đó thực sự là ý nghĩa của việc đóng cửa ...
loài gặm nhấm

> Một bao đóng là một khối mã có thể được tham chiếu (và được truyền xung quanh) với quyền truy cập vào các biến của phạm vi kèm theo. var _resolve, _reject; là phạm vi kèm theo.
Steven Spungin

vâng, đủ công bằng. Trên thực tế, dường như câu trả lời của tôi là quá phức tạp, và hơn nữa câu trả lời của bạn có thể được đơn giản hóa: bạn chỉ cần đi promise.resolve_ex = _resolve; promise.reject_ex = _reject;... vẫn hoạt động tốt.
mike gặm nhấm

" Đính kèm một chức năng để mở rộng lời hứa. " - đừng làm điều đó. Lời hứa là giá trị kết quả, họ không nên cung cấp khả năng giải quyết chúng. Bạn không muốn vượt qua những người mở rộng xung quanh.
Bergi

2
Câu hỏi là làm thế nào để giải quyết nó bên ngoài phạm vi. Đây là một giải pháp hiệu quả, và trong sản xuất của chúng tôi, chúng tôi thực sự đã có một lý do cần thiết để làm điều đó. Tôi không thấy lý do tại sao việc giải quyết vấn đề đã nêu lại xứng đáng với một downvote.
Steven Spungin

2

Tôi thấy mình thiếu mẫu Trì hoãn cũng như trong một số trường hợp nhất định. Bạn luôn có thể tạo một cái trên đầu Lời hứa ES6:

export default class Deferred<T> {
    private _resolve: (value: T) => void = () => {};
    private _reject: (value: T) => void = () => {};

    private _promise: Promise<T> = new Promise<T>((resolve, reject) => {
        this._reject = reject;
        this._resolve = resolve;
    })

    public get promise(): Promise<T> {
        return this._promise;
    }

    public resolve(value: T) {
        this._resolve(value);
    }

    public reject(value: T) {
        this._reject(value);
    }
}

2

Cảm ơn tất cả những người đã đăng trong chủ đề này. Tôi đã tạo một mô-đun bao gồm đối tượng Defer () được mô tả trước đó cũng như một vài đối tượng khác được xây dựng trên nó. Tất cả đều tận dụng Promise và cú pháp gọi lại Promise gọn gàng để thực hiện xử lý giao tiếp / sự kiện trong một chương trình.

  • Trì hoãn: Hứa rằng có thể giải quyết thất bại từ xa (bên ngoài cơ thể của nó)
  • Trì hoãn: Hứa hẹn sẽ được giải quyết tự động sau một thời gian nhất định
  • TimeOut: Hứa rằng sẽ tự động thất bại sau một thời gian nhất định.
  • Chu kỳ: Tái kích hoạt lời hứa để quản lý các sự kiện bằng cú pháp Promise
  • Hàng đợi: Hàng đợi thực thi dựa trên chuỗi Promise.

    rp = require("repeatable-promise")

    https://github.com/CABrouwers/repeatable-promise


1

Tôi đã viết một lib nhỏ cho việc này. https://www.npmjs.com/package/@inf3rno/promise.exposed

Tôi đã sử dụng cách tiếp cận phương pháp nhà máy khác đã viết, nhưng tôi gạt những then, catch, finallyphương pháp quá, vì vậy bạn có thể giải quyết lời hứa ban đầu của những người là tốt.

Giải quyết lời hứa mà không cần người thực hiện từ bên ngoài:

const promise = Promise.exposed().then(console.log);
promise.resolve("This should show up in the console.");

Đua xe với setTimeout của người thi hành từ bên ngoài:

const promise = Promise.exposed(function (resolve, reject){
    setTimeout(function (){
        resolve("I almost fell asleep.")
    }, 100000);
}).then(console.log);

setTimeout(function (){
    promise.resolve("I don't want to wait that much.");
}, 100);

Không có chế độ không xung đột nếu bạn không muốn làm ô nhiễm không gian tên toàn cầu:

const createExposedPromise = require("@inf3rno/promise.exposed/noConflict");
const promise = createExposedPromise().then(console.log);
promise.resolve("This should show up in the console.");

1

Tôi đã tạo một thư viện gọi manual-promisecác chức năng đó như là một sự thay thế cho Promise. Không có câu trả lời nào khác ở đây sẽ có tác dụng thay thế cho việc thay thế Promise, vì họ sử dụng proxy hoặc trình bao bọc.

yarn add manual-promise

npn install manual-promise


import { ManualPromise } from "manual-promise";

const prom = new ManualPromise();

prom.resolve(2);

// actions can still be run inside the promise
const prom2 = new ManualPromise((resolve, reject) => {
    // ... code
});


new ManualPromise() instanceof Promise === true

https://github.com/zpxp/manual-promise#readme


0

Làm thế nào về việc tạo ra một chức năng để chiếm quyền từ chối và trả lại nó?

function createRejectablePromise(handler) {
  let _reject;

  const promise = new Promise((resolve, reject) => {
    _reject = reject;

    handler(resolve, reject);
  })

  promise.reject = _reject;
  return promise;
}

// Usage
const { reject } = createRejectablePromise((resolve) => {
  setTimeout(() => {
    console.log('resolved')
    resolve();
  }, 2000)

});

reject();

0

Tôi đã tập hợp một ý chính thực hiện công việc đó: https://gist.github.com/thiagoh/c24 310b562d50a14f3e7602a82b4ef13

Dưới đây là cách bạn nên sử dụng nó:

import ExternalizedPromiseCreator from '../externalized-promise';

describe('ExternalizedPromise', () => {
  let fn: jest.Mock;
  let deferredFn: jest.Mock;
  let neverCalledFn: jest.Mock;
  beforeEach(() => {
    fn = jest.fn();
    deferredFn = jest.fn();
    neverCalledFn = jest.fn();
  });

  it('resolve should resolve the promise', done => {
    const externalizedPromise = ExternalizedPromiseCreator.create(() => fn());

    externalizedPromise
      .promise
      .then(() => deferredFn())
      .catch(() => neverCalledFn())
      .then(() => {
        expect(deferredFn).toHaveBeenCalled();
        expect(neverCalledFn).not.toHaveBeenCalled();
        done();
      });

    expect(fn).toHaveBeenCalled();
    expect(neverCalledFn).not.toHaveBeenCalled();
    expect(deferredFn).not.toHaveBeenCalled();

    externalizedPromise.resolve();
  });
  ...
});

0

lần đầu tiên kích hoạt --allow-nigen-cú pháp trên trình duyệt hoặc nút

const p = new Promise(function(resolve, reject){
    if (someCondition){
        resolve();
    } else {
        reject();
    } 
});

onClick = function () {
    %ResolvePromise(p, value)
}

0

Chỉ là một giải pháp khác để giải quyết Promise từ bên ngoài

 class Lock {
        #lock;  // Promise to be resolved (on  release)
        release;  // Release lock
        id;  // Id of lock
        constructor(id) {
            this.id = id
            this.#lock = new Promise((resolve) => {
                this.release = () => {
                    if (resolve) {
                        resolve()
                    } else {
                        Promise.resolve()
                    }
                }
            })
        }
        get() { return this.#lock }
    }

Sử dụng

let lock = new Lock(... some id ...);
...
lock.get().then(()=>{console.log('resolved/released')})
lock.release()  // Excpected 'resolved/released'
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.