söz zincirinde setTimeout kullanarak


115

Burada sözlerin etrafına sarılmaya çalışıyorum. Burada ilk talepte bir dizi bağlantı getiriyorum ve bir sonraki talepte ilk bağlantının içeriğini alıyorum.Ama bir sonraki söz nesnesini geri vermeden önce bir gecikme yapmak istiyorum. setTimeout üzerinde.Ama bana şu JSON hatasını veriyor ( without setTimeout() it works just fine)

Sözdizimi Hatası: JSON.parse: JSON verilerinin 1. satırındaki 1. sütunda beklenmeyen karakter

neden başarısız olduğunu bilmek isterim?

let globalObj={};
function getLinks(url){
    return new Promise(function(resolve,reject){

       let http = new XMLHttpRequest();
       http.onreadystatechange = function(){
            if(http.readyState == 4){
              if(http.status == 200){
                resolve(http.response);
              }else{
                reject(new Error());
              }
            }           
       }
       http.open("GET",url,true);
       http.send();
    });
}

getLinks('links.txt').then(function(links){
    let all_links = (JSON.parse(links));
    globalObj=all_links;

    return getLinks(globalObj["one"]+".txt");

}).then(function(topic){


    writeToBody(topic);
    setTimeout(function(){
         return getLinks(globalObj["two"]+".txt"); // without setTimeout it works fine 
         },1000);
});

1
Bunun returnişleve özgü olduğunu ve yalnızca ana işleve döndüğünü ve zaman uyumsuz bir yöntemden dönemeyeceğinizi unutmayın.
adeneo

2
Bu kodu yapılandırmanın a kullanmaktan çok daha iyi yolları olduğuna dikkat edin globalObj.
Bergi

Nereye JSON.parseatıyor? setTimeoutBir thengeri aramanın olup olmadığının önceki thengeri aramadaki aramayı etkilediğine inanmakta zorlanıyorum .
Bergi

Yanıtlar:


191

Söz zincirini devam ettirmek için, uygulayıcıdan bir söz setTimeout()vermediğin için yaptığın yolu kullanamazsın .then()- onu setTimeout()geri aramadan geri veriyorsun ki bu sana bir yararı olmaz.

Bunun yerine, aşağıdaki gibi basit bir küçük gecikme işlevi yapabilirsiniz:

function delay(t, v) {
   return new Promise(function(resolve) { 
       setTimeout(resolve.bind(null, v), t)
   });
}

Ve sonra bunu şu şekilde kullanın:

getLinks('links.txt').then(function(links){
    let all_links = (JSON.parse(links));
    globalObj=all_links;

    return getLinks(globalObj["one"]+".txt");

}).then(function(topic){
    writeToBody(topic);
    // return a promise here that will be chained to prior promise
    return delay(1000).then(function() {
        return getLinks(globalObj["two"]+".txt");
    });
});

Burada .then()işleyiciden bir sözü geri veriyorsunuz ve bu nedenle uygun şekilde zincirleniyor.


Ayrıca Promise nesnesine bir gecikme yöntemi ekleyebilir ve ardından .delay(x)sözlerinizde doğrudan aşağıdaki gibi bir yöntem kullanabilirsiniz :

function delay(t, v) {
   return new Promise(function(resolve) { 
       setTimeout(resolve.bind(null, v), t)
   });
}

Promise.prototype.delay = function(t) {
    return this.then(function(v) {
        return delay(t, v);
    });
}


Promise.resolve("hello").delay(500).then(function(v) {
    console.log(v);
});

Veya yöntemi zaten yerleşik olan Bluebird vaat kitaplığını kullanın .delay().


1
çözümleme işlevi o zaman içindeki işlevdir () .. bu nedenle setTimeout (çözümleme, t), setTimeout anlamına gelir (işlev () {dönüş ....}, t) değil ... öyleyse neden çalışacak?
AL-zami

2
@ AL-zami - delay()sonra çözülecek bir söz verir setTimeout().
jfriend00

Bir sözü kolayca geciktirmek için setTimeout için bir söz sarmalayıcı oluşturdum. github.com/zengfenfei/delay
Kevin

4
@pdem - vgecikme vaadinin çözülmesini ve böylece söz zincirini geçmesini istediğiniz isteğe bağlı bir değerdir. resolve.bind(null, v)Yerinde function() {resolve(v);} ikisinden biri çalışacak.
jfriend00

çok teşekkür ederim ... prototip gecikmesi işe yaradı ama >>> .then işlevi değil. t tanımsızdı.
Christian Matthew

76
.then(() => new Promise((resolve) => setTimeout(resolve, 15000)))

GÜNCELLEME:

zaman uyumsuz işlevde uyumaya ihtiyacım olduğunda atıyorum

await new Promise(resolve => setTimeout(resolve, 1000))

Böyle bir eşzamansız işlev içinde uyuyamaz mısın? yeni Promise'i bekliyoruz (resol => setTimeout (çözümleme, 1000));
Anthony Moon Beam Toorie

@AnthonyMoonBeamToorie fixed, ty
Igor Korsakov

Hoşgeldin arkadaşım 🧐 şerefe
Anthony Moon Beam Toorie

52

Cevabın daha kısa ES6 versiyonu:

const delay = t => new Promise(resolve => setTimeout(resolve, t));

Ve sonra şunları yapabilirsiniz:

delay(3000).then(() => console.log('Hello'));

ve rejectseçeneğe ihtiyacınız varsa , örneğin eslint doğrulama için, o zamanconst delay = ms => new Promise((resolve, reject) => setTimeout(resolve, ms))
David Thomas

10

Bir .then () bloğunun içindeyseniz ve bir settimeout () yürütmek istiyorsanız

            .then(() => {
                console.log('wait for 10 seconds . . . . ');
                return new Promise(function(resolve, reject) { 
                    setTimeout(() => {
                        console.log('10 seconds Timer expired!!!');
                        resolve();
                    }, 10000)
                });
            })
            .then(() => {
                console.log('promise resolved!!!');

            })

çıktı aşağıda gösterildiği gibi olacaktır

wait for 10 seconds . . . .
10 seconds Timer expired!!!
promise resolved!!!

Mutlu Kodlama!


-1

Node.js'de aşağıdakileri de yapabilirsiniz:

const { promisify } = require('util')
const delay = promisify(setTimeout)

delay(1000).then(() => console.log('hello'))

Bunu denedim ve geçersiz sayıda argüman aldım, gecikme fonksiyonunda 0 bekleniyordu.
Alex Rindone

Node.js 8, 10, 12, 13'te çalıştığını doğrulayabilirim. Kodunuzu nasıl çalıştırdığınızdan emin değilim, ancak yalnızca utilhatalı bir şekilde çoklu doldurulduğunu varsayabilirim . Bir paketleyici veya başka bir şey mi kullanıyorsunuz?
Jan
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.