鍍金池/ 問(wèn)答/HTML/ 回調(diào)函數(shù)運(yùn)行的順序

回調(diào)函數(shù)運(yùn)行的順序

代碼如下,data是長(zhǎng)度為3的一個(gè)數(shù)組,cmt是個(gè)object

function addComments(campground, cmt) {
    Comment.create(
        cmt,
        function(err, comment) {
            if (err) console.log(err);
            else {
                campground.comments.push(comment);
                campground.save();
                console.log("Created new comment");
        }
    });
}
    
function addCamps(seed) {
    Camp.create(seed, function(err, campground){
        if (err) console.log(err);
        else {
            console.log("Added a campground");
            addComments(campground, cmt);    
        }
    });
}


function seedDB(){
    Camp.remove({}, function(err) {
        if (err) console.log(err);
        else {
            console.log("removed campgrounds");
            Comment.remove({}, function(err) {
                if (err) console.log(err);
                else {
                    console.log("removed comments");                    
                    data.forEach(addCamps);
                }
            });
        }   
    });
}

seedDB();

請(qǐng)問(wèn)為什么輸出結(jié)果是

removed campgrounds
removed comments
Added a campground
Added a campground
Added a campground
Created new comment
Created new comment
Created new comment

而不是

removed campgrounds
removed comments
Added a campground
Created new comment
Added a campground
Created new comment
Added a campground
Created new comment

如果想讓結(jié)果變成第二種情況,應(yīng)該如何修改以上代碼?
應(yīng)該如何修改以上代碼?

回答
編輯回答
清夢(mèng)

因?yàn)榛卣{(diào)函數(shù)的特點(diǎn)就是無(wú)需等待,且回調(diào)執(zhí)行的時(shí)間也不確定。你這里出現(xiàn)這種輸出順序的原因是執(zhí)行addComments時(shí)花了些時(shí)間。

如果你想要按Added a campground、Created new comment這樣交替打印的話,就需要等待前一個(gè) comment完成再執(zhí)行下一個(gè)capmgroup的添加了。這就放棄了js異步的優(yōu)勢(shì)?,F(xiàn)在data數(shù)據(jù)只有三個(gè)不算多,但是數(shù)據(jù)一多就會(huì)影響體驗(yàn),用戶會(huì)看到最后面的comment添加的比第一個(gè)遲的多。

代碼的話可以用Promise:

function addComments(campground, cmt,resolve) {
  Comment.create(cmt, function(err, comment) {
    if (err) console.log(err);
    else {
      campground.comments.push(comment);
      campground.save();
      console.log("Created new comment");
      resolve();
    }
  });
}

function new_addCamps(seed) {
  return new Promise((resolve, reject) => {
    Camp.create(seed, function(err, campground) {
      if (err) reject(err);
      else {
        console.log("Added a campground");
        addComments(campground, cmt,resolve);
      }
    });
  });
}

同時(shí)不能再使用forEach而是使用for循環(huán):

(async function (){
for(let i=0;i<data.length;i++){
await addCamps(data[i]);
}
})();
2017年1月11日 01:30
編輯回答
維他命

樓上正解,舉個(gè)簡(jiǎn)單的例子
for (var i=0;i<3;i++){

setTimeout(function(){console.log(i)},100)

}
你覺(jué)得輸出結(jié)果是什么?

答案是三個(gè)3
異步回調(diào),普通的回調(diào)是沒(méi)問(wèn)題的,就是把setTimeout去掉,變成一個(gè)閉包函數(shù)。
輸出是0,1,2
但是異步回調(diào)會(huì)讓事件輪詢的順序產(chǎn)生變化。

特別詳細(xì)的去百度一下Js的事件輪詢機(jī)制吧

2017年11月23日 08:16