Hủy chuỗi Lời hứa ECMAScript 6 vani


110

Có phương pháp nào để xóa các phiên bản .thenJavaScript Promisekhông?

Tôi đã viết một khung kiểm tra JavaScript trên QUnit . Khung chạy các bài kiểm tra một cách đồng bộ bằng cách chạy từng cái trong một Promise. (Xin lỗi vì độ dài của khối mã này. Tôi đã nhận xét nó tốt nhất có thể, vì vậy nó cảm thấy bớt tẻ nhạt hơn.)

/* Promise extension -- used for easily making an async step with a
       timeout without the Promise knowing anything about the function 
       it's waiting on */
$$.extend(Promise, {
    asyncTimeout: function (timeToLive, errorMessage) {
        var error = new Error(errorMessage || "Operation timed out.");
        var res, // resolve()
            rej, // reject()
            t,   // timeout instance
            rst, // reset timeout function
            p,   // the promise instance
            at;  // the returned asyncTimeout instance

        function createTimeout(reject, tempTtl) {
            return setTimeout(function () {
                // triggers a timeout event on the asyncTimeout object so that,
                // if we want, we can do stuff outside of a .catch() block
                // (may not be needed?)
                $$(at).trigger("timeout");

                reject(error);
            }, tempTtl || timeToLive);
        }

        p = new Promise(function (resolve, reject) {
            if (timeToLive != -1) {
                t = createTimeout(reject);

                // reset function -- allows a one-time timeout different
                //    from the one original specified
                rst = function (tempTtl) {
                    clearTimeout(t);
                    t = createTimeout(reject, tempTtl);
                }
            } else {
                // timeToLive = -1 -- allow this promise to run indefinitely
                // used while debugging
                t = 0;
                rst = function () { return; };
            }

            res = function () {
                clearTimeout(t);
                resolve();
            };

            rej = reject;
        });

        return at = {
            promise: p,
            resolve: res,
            reject: rej,
            reset: rst,
            timeout: t
        };
    }
});

/* framework module members... */

test: function (name, fn, options) {
    var mod = this; // local reference to framework module since promises
                    // run code under the window object

    var defaultOptions = {
        // default max running time is 5 seconds
        timeout: 5000
    }

    options = $$.extend({}, defaultOptions, options);

    // remove timeout when debugging is enabled
    options.timeout = mod.debugging ? -1 : options.timeout;

    // call to QUnit.test()
    test(name, function (assert) {
        // tell QUnit this is an async test so it doesn't run other tests
        // until done() is called
        var done = assert.async();
        return new Promise(function (resolve, reject) {
            console.log("Beginning: " + name);

            var at = Promise.asyncTimeout(options.timeout, "Test timed out.");
            $$(at).one("timeout", function () {
                // assert.fail() is just an extension I made that literally calls
                // assert.ok(false, msg);
                assert.fail("Test timed out");
            });

            // run test function
            var result = fn.call(mod, assert, at.reset);

            // if the test returns a Promise, resolve it before resolving the test promise
            if (result && result.constructor === Promise) {
                // catch unhandled errors thrown by the test so future tests will run
                result.catch(function (error) {
                    var msg = "Unhandled error occurred."
                    if (error) {
                        msg = error.message + "\n" + error.stack;
                    }

                    assert.fail(msg);
                }).then(function () {
                    // resolve the timeout Promise
                    at.resolve();
                    resolve();
                });
            } else {
                // if test does not return a Promise, simply clear the timeout
                // and resolve our test Promise
                at.resolve();
                resolve();
            }
        }).then(function () {
            // tell QUnit that the test is over so that it can clean up and start the next test
            done();
            console.log("Ending: " + name);
        });
    });
}

Nếu bài kiểm tra hết thời gian chờ, Promise hết thời gian chờ của tôi sẽ xuất assert.fail()hiện trong bài kiểm tra để bài kiểm tra được đánh dấu là không thành công, điều này là tốt và tốt, nhưng bài kiểm tra vẫn tiếp tục chạy vì bài kiểm tra Promise ( result) vẫn đang chờ giải quyết.

Tôi cần một cách tốt để hủy bỏ bài kiểm tra của mình. Tôi có thể làm điều đó bằng cách tạo một trường trên mô-đun khuôn khổ this.cancelTesthoặc thứ gì đó và kiểm tra mọi thứ thường xuyên (ví dụ: ở đầu mỗithen() lần lặp) trong thử nghiệm xem có hủy bỏ hay không. Tuy nhiên, lý tưởng nhất là tôi có thể sử dụng $$(at).on("timeout", /* something here */)để xóa các then()s còn lại trên resultbiến của mình , để không có phần còn lại của thử nghiệm nào được chạy.

Có một cái gì đó như thế này tồn tại?

Cập nhật nhanh

Tôi đã thử sử dụng Promise.race([result, at.promise]) . Nó không hoạt động.

Cập nhật 2 + nhầm lẫn

Để bỏ chặn tôi, tôi đã thêm một vài dòng với mod.cancelTest/ polling trong ý tưởng thử nghiệm. (Tôi cũng đã loại bỏ trình kích hoạt sự kiện.)

return new Promise(function (resolve, reject) {
    console.log("Beginning: " + name);

    var at = Promise.asyncTimeout(options.timeout, "Test timed out.");
    at.promise.catch(function () {
        // end the test if it times out
        mod.cancelTest = true;
        assert.fail("Test timed out");
        resolve();
    });

    // ...
    
}).then(function () {
    // tell QUnit that the test is over so that it can clean up and start the next test
    done();
    console.log("Ending: " + name);
});

Tôi đã đặt một điểm ngắt trong catchcâu lệnh, và nó đang bị tấn công. Điều khiến tôi bối rối bây giờ làthen() câu lệnh không được gọi. Ý tưởng?

Cập nhật 3

Đã tìm ra điều cuối cùng. fn.call()đã đưa ra một lỗi mà tôi không bắt được, vì vậy lời hứa kiểm tra bị từ chối trước khi at.promise.catch()có thể giải quyết nó.


Có thể thực hiện việc hủy bỏ với các lời hứa của ES6 nhưng nó không phải là thuộc tính của lời hứa (đúng hơn - đó là thuộc tính của hàm trả về nó) Tôi có thể làm một ví dụ ngắn nếu bạn quan tâm.
Benjamin Gruenbaum

@BenjaminGruenbaum Tôi biết đã gần một năm, nhưng tôi vẫn quan tâm nếu bạn có thời gian để viết một ví dụ. :)
dx_over_dt

1
Đã một năm trước nhưng nó đã được thảo luận chính thức hai ngày trước ngày hôm qua với các mã thông báo hủy và lời hứa có thể hủy chuyển sang giai đoạn 1.
Benjamin Gruenbaum

3
Câu trả lời ES6 cho việc hủy bỏ Lời hứa là có thể quan sát được. Bạn có thể đọc thêm về điều này tại đây: github.com/Reactive-Extensions/RxJS
Frank Goortani

Liên kết câu trả lời của tôi về việc sử dụng Prexthư viện để hủy bỏ lời hứa.
mũi,

Câu trả lời:


75

Có phương pháp nào để xóa các phiên bản .thenJavaScript Promise không?

Không. Ít nhất không có trong ECMAScript 6. Lời hứa (và thentrình xử lý của chúng ) không thể hủy theo mặc định (rất tiếc) . Có một chút thảo luận trên es-thảo luận (ví dụ: ở đây ) về cách thực hiện điều này đúng cách, nhưng bất kỳ cách tiếp cận nào sẽ giành chiến thắng, nó sẽ không hạ cánh trong ES6.

Quan điểm hiện tại là phân lớp sẽ cho phép tạo các lời hứa có thể hủy bằng cách sử dụng cách triển khai của riêng bạn (không chắc chắn rằng điều đó sẽ hoạt động tốt như thế nào) .

Cho đến khi người giao dịch ngôn ngữ tìm ra cách tốt nhất (hy vọng là ES7?), Bạn vẫn có thể sử dụng triển khai userland Promise, nhiều trong số đó đã hủy bỏ tính năng.

Cuộc thảo luận hiện tại nằm trong https://github.com/domenic/cancelable-promisehttps://github.com/bergus/promise-cancellation nháp.


2
"Một chút của cuộc thảo luận" - Tôi có thể liên kết đến có lẽ 30 chủ đề trên esdiscuss hoặc GitHub :) (chưa kể đến sự giúp đỡ của riêng bạn với hủy trong bluebird 3.0)
Benjamin Gruenbaum

@BenjaminGruenbaum: Bạn có các liên kết đó sẵn sàng để chia sẻ ở đâu đó không? Từ lâu, tôi đã muốn tóm tắt các ý kiến ​​và nỗ lực cũng như đăng một đề xuất lên esdiscuss, vì vậy tôi rất vui nếu có thể kiểm tra lại rằng tôi không quên gì.
Bergi

Tôi có chúng ở nơi làm việc - vì vậy tôi sẽ có chúng sau 3-4 ngày. Bạn có thể kiểm tra thông số kỹ thuật hủy bỏ lời hứa trong Promlus-aplus để có một khởi đầu tốt.
Benjamin Gruenbaum

1
@ LUH3417: các chức năng "bình thường" chỉ là nhàm chán về mặt đó. Bạn bắt đầu một chương trình và đợi cho đến khi nó kết thúc - hoặc bạn killbỏ qua nó ở trạng thái kỳ lạ mà các tác dụng phụ đã để lại trong môi trường của bạn (vì vậy, bạn thường chỉ vứt bỏ nó, ví dụ như bất kỳ đầu ra đã hoàn thành nào). Tuy nhiên, các chức năng không chặn hoặc không đồng bộ được xây dựng để hoạt động trong các ứng dụng tương tác, nơi bạn muốn có loại kiểm soát tốt hơn đối với việc thực hiện các hoạt động đang diễn ra.
Bergi

6
Domenic đã xóa đề xuất TC39 ... ... cc @BenjaminGruenbaum
Sergio

50

Mặc dù không có cách tiêu chuẩn để thực hiện việc này trong ES6, nhưng có một thư viện tên là Bluebird để xử lý việc này.

Cũng có một cách được khuyến nghị được mô tả như một phần của tài liệu phản ứng. Nó trông tương tự như những gì bạn có trong bản cập nhật 2 và 3 của mình.

const makeCancelable = (promise) => {
  let hasCanceled_ = false;

  const wrappedPromise = new Promise((resolve, reject) => {
    promise.then((val) =>
      hasCanceled_ ? reject({isCanceled: true}) : resolve(val)
    );
    promise.catch((error) =>
      hasCanceled_ ? reject({isCanceled: true}) : reject(error)
    );
  });

  return {
    promise: wrappedPromise,
    cancel() {
      hasCanceled_ = true;
    },
  };
};

const cancelablePromise = makeCancelable(
  new Promise(r => component.setState({...}}))
);

cancelablePromise
  .promise
  .then(() => console.log('resolved'))
  .catch((reason) => console.log('isCanceled', reason.isCanceled));

cancelablePromise.cancel(); // Cancel the promise

Lấy từ: https://facebook.github.io/react/blog/2015/12/16/ismounted-antipattern.html


1
định nghĩa này của bị hủy bỏ chỉ là từ chối lời hứa. nó phụ thuộc vào định nghĩa của "bị hủy bỏ".
Alexander Mills

1
Và điều gì sẽ xảy ra nếu bạn muốn hủy một tập hợp các lời hứa?
Matthieu Brucher

1
Vấn đề với cách tiếp cận này là Nếu bạn có một Lời hứa sẽ không bao giờ được giải quyết hoặc từ chối nó sẽ không bao giờ bị hủy bỏ.
DaNeSh

2
Điều này đúng một phần, nhưng nếu bạn có chuỗi hứa hẹn dài, cách tiếp cận này sẽ không hiệu quả.
Veikko Karsikko

11

Tôi thực sự ngạc nhiên khi không có ai đề cập đến Promise.racenhư một ứng cử viên cho việc này:

const actualPromise = new Promise((resolve, reject) => { setTimeout(resolve, 10000) });
let cancel;
const cancelPromise = new Promise((resolve, reject) => {
    cancel = reject.bind(null, { canceled: true })
})

const cancelablePromise = Object.assign(Promise.race([actualPromise, cancelPromise]), { cancel });

3
Tôi không tin rằng điều này hiệu quả. Nếu bạn thay đổi lời hứa ghi nhật ký, việc chạy cancel()sẽ vẫn dẫn đến nhật ký được gọi. `` `const realityPromise = new Promise ((giải quyết, từ chối) => {setTimeout (() => {console.log ('thực tế được gọi'); giải quyết ()}, 10000)}); `` '
shmck

2
Câu hỏi đặt ra là làm thế nào để hủy một lời hứa (=> dừng các chuỗi thenđược thực thi), không phải làm thế nào để hủy setTimeout(=> clearTimeout) hoặc mã đồng bộ, trừ khi bạn đặt một if sau mỗi dòng ( if (canceled) return) thì điều này không thể đạt được. (Đừng làm điều này)
Pho3nixHun

10
const makeCancelable = promise => {
    let rejectFn;

    const wrappedPromise = new Promise((resolve, reject) => {
        rejectFn = reject;

        Promise.resolve(promise)
            .then(resolve)
            .catch(reject);
    });

    wrappedPromise.cancel = () => {
        rejectFn({ canceled: true });
    };

    return wrappedPromise;
};

Sử dụng:

const cancelablePromise = makeCancelable(myPromise);
// ...
cancelablePromise.cancel();

5

Thực sự là không thể ngăn việc thực hiện lời hứa, nhưng bạn có thể cướp lời từ chối và gọi nó từ chính lời hứa.

class CancelablePromise {
  constructor(executor) {
    let _reject = null;
    const cancelablePromise = new Promise((resolve, reject) => {
      _reject = reject;
      return executor(resolve, reject);
    });
    cancelablePromise.cancel = _reject;

    return cancelablePromise;
  }
}

Sử dụng:

const p = new CancelablePromise((resolve, reject) => {
  setTimeout(() => {
    console.log('resolved!');
    resolve();
  }, 2000);
})

p.catch(console.log);

setTimeout(() => {
  p.cancel(new Error('Messed up!'));
}, 1000);

1
@dx_over_dt Bản chỉnh sửa của bạn sẽ là một nhận xét tuyệt vời, nhưng không phải là một bản chỉnh sửa. Vui lòng để lại những chỉnh sửa quan trọng như vậy cho mục đích của OP (tất nhiên trừ khi bài đăng được đánh dấu là Wiki Cộng đồng).
TylerH

@TylerH vậy có phải là điểm chỉnh sửa để sửa lỗi chính tả và những thứ tương tự không? Hay để cập nhật thông tin khi nó trở nên lỗi thời? Tôi chưa quen với khả năng đặc quyền chỉnh sửa bài đăng của người khác.
dx_over_dt

@dx_over_dt Đúng vậy, chỉnh sửa là để cải thiện bài đăng bằng cách sửa lỗi chính tả, lỗi ngữ pháp và thêm đánh dấu cú pháp (nếu ai đó chỉ đăng một loạt mã nhưng không thụt lề hoặc gắn thẻ bằng `` 'chẳng hạn). Thêm nội dung quan trọng như giải thích bổ sung hoặc lập luận / biện minh cho mọi thứ thường là mục đích của người đã đăng câu trả lời. Bạn có thể tự do đề xuất nó trong nhận xét và OP sẽ được thông báo về nhận xét đó và sau đó có thể trả lời nhận xét đó hoặc họ có thể tự kết hợp đề xuất của bạn vào bài đăng.
TylerH

@dx_over_dt Các trường hợp ngoại lệ là nếu một bài đăng được đánh dấu là "Wiki cộng đồng" cho biết nó nhằm mục đích phục vụ như một bài đăng cộng tác (ví dụ như Wikipedia) hoặc nếu có vấn đề nghiêm trọng với bài đăng như ngôn ngữ thô lỗ / lạm dụng, nội dung nguy hiểm / có hại ( ví dụ như các đề xuất hoặc mã có khả năng cung cấp cho bạn vi-rút hoặc khiến bạn bị bắt, v.v.), hoặc thông tin cá nhân như hồ sơ sức khỏe, số điện thoại, thẻ tín dụng, v.v.; hãy tự xóa chúng.
TylerH

Cần lưu ý rằng lý do không thể tạm dừng việc thực thi trong một lời hứa là JavaScript là một luồng. Trong khi chức năng hứa đang được thực thi, không có gì khác đang chạy, vì vậy không có gì để kích hoạt việc tạm dừng thực thi.
dx_over_dt


2

Đây là cách triển khai của chúng tôi https://github.com/permettez-moi-de-construire/cancellable-promise

Được sử dụng như

const {
  cancellablePromise,
  CancelToken,
  CancelError
} = require('@permettezmoideconstruire/cancellable-promise')

const cancelToken = new CancelToken()

const initialPromise = SOMETHING_ASYNC()
const wrappedPromise = cancellablePromise(initialPromise, cancelToken)


// Somewhere, cancel the promise...
cancelToken.cancel()


//Then catch it
wrappedPromise
.then((res) => {
  //Actual, usual fulfill
})
.catch((err) => {
  if(err instanceOf CancelError) {
    //Handle cancel error
  }

  //Handle actual, usual error
})

cái nào:

  • Không chạm vào API Promise
  • Hãy để chúng tôi hủy thêm bên trong catch cuộc gọi
  • Dựa vào việc hủy bỏ bị từ chối thay vì được giải quyết không giống như bất kỳ đề xuất hoặc triển khai nào khác

Lời chào đón và bình luận


2

Lời hứa có thể bị hủy bỏ với sự giúp đỡ của AbortController.

Có một phương pháp để xóa sau đó không: có, bạn có thể từ chối lời hứa với AbortControllerđối tượng và sau đó ý promisechí bỏ qua tất cả các khối sau đó và đi trực tiếp đến khối bắt.

Thí dụ:

import "abortcontroller-polyfill";

let controller = new window.AbortController();
let signal = controller.signal;
let elem = document.querySelector("#status")

let example = (signal) => {
    return new Promise((resolve, reject) => {
        let timeout = setTimeout(() => {
            elem.textContent = "Promise resolved";
            resolve("resolved")
        }, 2000);

        signal.addEventListener('abort', () => {
            elem.textContent = "Promise rejected";
            clearInterval(timeout);
            reject("Promise aborted")
        });
    });
}

function cancelPromise() {
    controller.abort()
    console.log(controller);
}

example(signal)
    .then(data => {
        console.log(data);
    })
    .catch(error => {
        console.log("Catch: ", error)
    });

document.getElementById('abort-btn').addEventListener('click', cancelPromise);

Html


    <button type="button" id="abort-btn" onclick="abort()">Abort</button>
    <div id="status"> </div>

Lưu ý: cần thêm polyfill, không được hỗ trợ trong tất cả các trình duyệt.

Ví dụ trực tiếp

Chỉnh sửa nhã-hồ-5jnh3


1

phiên bản đơn giản :

chỉ đưa ra chức năng từ chối.

function Sleep(ms,cancel_holder) {

 return new Promise(function(resolve,reject){
  var done=false; 
  var t=setTimeout(function(){if(done)return;done=true;resolve();}, ms);
  cancel_holder.cancel=function(){if(done)return;done=true;if(t)clearTimeout(t);reject();} 
 })
}

một giải pháp bao bọc (nhà máy)

giải pháp mà tôi tìm thấy là chuyển một đối tượng hủy_ giữ. nó sẽ có chức năng hủy bỏ. nếu nó có chức năng hủy bỏ thì nó có thể hủy được.

Chức năng hủy bỏ này từ chối lời hứa với Lỗi ('bị hủy bỏ').

Trước khi giải quyết, từ chối hoặc on_cancel ngăn hàm hủy được gọi mà không có lý do.

Tôi thấy thuận tiện để vượt qua hành động hủy bằng cách tiêm

function cancelablePromise(cancel_holder,promise_fn,optional_external_cancel) {
  if(!cancel_holder)cancel_holder={};
  return new Promise( function(resolve,reject) {
    var canceled=false;
    var resolve2=function(){ if(canceled) return; canceled=true; delete cancel_holder.cancel; resolve.apply(this,arguments);}
    var reject2=function(){ if(canceled) return; canceled=true; delete cancel_holder.cancel; reject.apply(this,arguments);}
    var on_cancel={}
    cancel_holder.cancel=function(){
      if(canceled) return; canceled=true;

      delete cancel_holder.cancel;
      cancel_holder.canceled=true;

      if(on_cancel.cancel)on_cancel.cancel();
      if(optional_external_cancel)optional_external_cancel();

      reject(new Error('canceled'));
    };

    return promise_fn.call(this,resolve2,reject2,on_cancel);        
  });
}

function Sleep(ms,cancel_holder) {

 return cancelablePromise(cancel_holder,function(resolve,reject,oncacnel){

  var t=setTimeout(resolve, ms);
  oncacnel.cancel=function(){if(t)clearTimeout(t);}     

 })
}


let cancel_holder={};

// meanwhile in another place it can be canceled
setTimeout(function(){  if(cancel_holder.cancel)cancel_holder.cancel(); },500) 

Sleep(1000,cancel_holder).then(function() {
 console.log('sleept well');
}, function(e) {
 if(e.message!=='canceled') throw e;
 console.log('sleep interrupted')
})

1

Hãy thử dùng lời hứa có thể hủy bỏ : https://www.npmjs.com/package/promise-abortable

$ npm install promise-abortable
import AbortablePromise from "promise-abortable";

const timeout = new AbortablePromise((resolve, reject, signal) => {
  setTimeout(reject, timeToLive, error);
  signal.onabort = resolve;
});

Promise.resolve(fn()).then(() => {
  timeout.abort();
});

1

Nếu mã của bạn được đặt trong một lớp, bạn có thể sử dụng trình trang trí cho điều đó. Bạn có trình trang trí như vậy trong utils-decorator ( npm install --save utils-decorators). Nó sẽ hủy lệnh gọi trước đó của phương thức được trang trí nếu trước khi giải quyết cuộc gọi trước đó đã có một lệnh gọi khác cho phương thức cụ thể đó.

import {cancelPrevious} from 'utils-decorators';

class SomeService {

   @cancelPrevious()
   doSomeAsync(): Promise<any> {
    ....
   }
}

https://github.com/vlio20/utils-decorators#cancelprevious-method


0

Nếu bạn muốn ngăn tất cả các lệnh / lệnh bắt được thực thi, bạn có thể thực hiện điều này bằng cách đưa ra một lời hứa sẽ không bao giờ giải quyết được. Nó có thể có hậu quả do rò rỉ bộ nhớ nhưng nó sẽ khắc phục được sự cố và không gây lãng phí quá nhiều bộ nhớ trong hầu hết các ứng dụng.

new Promise((resolve, reject) => {
    console.log('first chain link executed')
    resolve('daniel');
}).then(name => {
    console.log('second chain link executed')
    if (name === 'daniel') {
        // I don't want to continue the chain, return a new promise
        // that never calls its resolve function
        return new Promise((resolve, reject) => {
            console.log('unresolved promise executed')
        });
    }
}).then(() => console.log('last chain link executed'))

// VM492:2 first chain link executed
// VM492:5 second chain link executed
// VM492:8 unresolved promise executed

0

Đặt thuộc tính "đã hủy" trên Lời hứa để báo hiệu then()catch()thoát sớm. Nó rất hiệu quả, đặc biệt là trong Nhân viên web có các vi nhiệm hiện có được xếp hàng đợi trong Lời hứa từ onmessagetrình xử lý.

// Queue task to resolve Promise after the end of this script
const promise = new Promise(resolve => setTimeout(resolve))

promise.then(_ => {
  if (promise.canceled) {
    log('Promise cancelled.  Exiting early...');
    return;
  }

  log('No cancelation signaled.  Continue...');
})

promise.canceled = true;

function log(msg) {
  document.body.innerHTML = msg;
}


0

Câu trả lời của @Michael Yagudaev phù hợp với tôi.

Nhưng câu trả lời ban đầu không kết nối lời hứa với .catch () để xử lý việc xử lý từ chối, đây là cải tiến của tôi về câu trả lời của @Michael Yagudaev:

const makeCancelablePromise = promise => {
  let hasCanceled = false;
  const wrappedPromise = new Promise((resolve, reject) => {
    promise
      .then(val => (hasCanceled ? reject({ isCanceled: true }) : resolve(val)))
      .catch(
        error => (hasCanceled ? reject({ isCanceled: true }) : reject(error))
      );
  });

  return {
    promise: wrappedPromise,
    cancel() {
      hasCanceled = true;
    }
  };
};

// Example Usage:
const cancelablePromise = makeCancelable(
  new Promise((rs, rj) => {
    /*do something*/
  })
);
cancelablePromise.promise.then(() => console.log('resolved')).catch(err => {
  if (err.isCanceled) {
    console.log('Wrapped promise canceled');
    return;
  }
  console.log('Promise was not canceled but rejected due to errors: ', err);
});
cancelablePromise.cancel();

0

Nếu p là một biến có chứa Promise, thì p.then(empty);nên loại bỏ lời hứa khi nó cuối cùng hoàn thành hoặc nếu nó đã hoàn thành (vâng, tôi biết đây không phải là câu hỏi ban đầu, nhưng đó là câu hỏi của tôi). "trống rỗng" là function empty() {}. Tôi chỉ là người mới bắt đầu và có thể sai, nhưng những câu trả lời khác này có vẻ quá phức tạp. Lời hứa được cho là đơn giản.


0

Tôi vẫn đang làm việc thông qua ý tưởng này, nhưng đây là cách tôi triển khai Lời hứa có thể hủy bằng cách sử dụng setTimeout làm ví dụ.

Ý tưởng là một lời hứa sẽ được giải quyết hoặc bị từ chối bất cứ khi nào bạn đã quyết định nó, do đó, bạn nên quyết định khi nào bạn muốn hủy bỏ, đáp ứng tiêu chí và sau đó tự gọi reject()hàm.

  • Đầu tiên, tôi nghĩ rằng có hai lý do để kết thúc lời hứa sớm: để hoàn thành và thực hiện (mà tôi gọi là giải quyết ) và hủy bỏ (mà tôi gọi là từ chối ). Tất nhiên, đó chỉ là cảm giác của tôi. Tất nhiên là có một Promise.resolve()phương thức, nhưng nó nằm trong chính phương thức khởi tạo và trả về một lời hứa đã được phân giải giả. resolve()Phương thức thể hiện này thực sự giải quyết một đối tượng hứa được khởi tạo.

  • Thứ hai, bạn có thể vui vẻ thêm bất cứ thứ gì bạn thích vào một đối tượng hứa mới được tạo trước khi bạn trả lại nó, và vì vậy tôi vừa thêm resolve()reject()các phương pháp để làm cho nó trở nên độc lập.

  • Thứ ba, mẹo là để có thể truy cập trình thực thi resolvevà các rejectchức năng sau này, vì vậy tôi chỉ cần lưu trữ chúng trong một đối tượng đơn giản từ bên trong bao đóng.

Tôi nghĩ rằng giải pháp là đơn giản và tôi không thể thấy bất kỳ vấn đề lớn nào với nó.

function wait(delay) {
  var promise;
  var timeOut;
  var executor={};
  promise=new Promise(function(resolve,reject) {
    console.log(`Started`);
    executor={resolve,reject};  //  Store the resolve and reject methods
    timeOut=setTimeout(function(){
      console.log(`Timed Out`);
      resolve();
    },delay);
  });
  //  Implement your own resolve methods,
  //  then access the stored methods
      promise.reject=function() {
        console.log(`Cancelled`);
        clearTimeout(timeOut);
        executor.reject();
      };
      promise.resolve=function() {
        console.log(`Finished`);
        clearTimeout(timeOut);
        executor.resolve();
      };
  return promise;
}

var promise;
document.querySelector('button#start').onclick=()=>{
  promise=wait(5000);
  promise
  .then(()=>console.log('I have finished'))
  .catch(()=>console.log('or not'));
};
document.querySelector('button#cancel').onclick=()=>{ promise.reject(); }
document.querySelector('button#finish').onclick=()=>{ promise.resolve(); }
<button id="start">Start</button>
<button id="cancel">Cancel</button>
<button id="finish">Finish</button>

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.